[TOC]html
这是一份我给公司后端同事培训Vue的培训第一节课技术文档,旨在带领他们入门Vue的开发世界,释放更多的前端资源。现开放出来以求业界各位的技术指点或补充,感谢~
如下文档配合代码一块儿演示和讲解效果更佳。代码地址:Vue-coe-test代码地址前端
使用如下命令行建立一个vue项目vue
$ npm install -g vue-cli
$ vue init webpack vue-coe-test
$ cd vue-coe-test
$ npm install
$ npm run dev
复制代码
官方文档说明jquery
### // App.vue
<div id="app"></div>
//main.js
new Vue({
el: '#app',
router,
components: { App },
template: '<h1>{{ msg }}</h1>',
data () {
return {
msg: 'Hello,my first Vue.js App'
}
}
})
复制代码
官方文档-插值 官方文档-v-text & v-htmlwebpack
<h1>{{ msg }}</h1>
<div v-text="text"></div>
<div v-html="text"></div>
复制代码
data () {
return {
msg: 'Welcome to Your Vue.js App',
text: '<div style="color: red">I am red</div>'
}
},
复制代码
<div v-bind:title="title" v-bind:class="[{ active: isActive }, 'title']">阿弥陀佛,么么哒</div>
data () {
return {
title: '大冰的畅销书'
}
}
复制代码
如今演示的都是单向绑定,那双向绑定是什么呢?git
数据双向绑定是指数据能够决定页面的展现,页面的操做也能够改变数据。github
<input type="text" v-model="title">
data () {
return {
title: '大冰的畅销书'
}
},
复制代码
指令 (Directives) 是带有 v- 前缀的特殊特性。指令特性的值预期是单个 JavaScript 表达式 (v-for 是例外状况,稍后咱们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地做用于 DOM。web
官方文档vue-cli
动态地绑定一个或多个特性,或一个组件 prop 到表达式。npm
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
复制代码
在这里 href 是参数,告知 v-bind 指令将该元素的 href 特性与表达式 url 的值绑定。
<!-- class 绑定 -->
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
复制代码
data: {
isActive: true,
errorClass: 'text-danger'
}
复制代码
这里的class是响应的,是根据data里的值来显示对应class的,固然你也能够加上指定的class。
v-if 是“真正”的条件渲染,由于它会确保在切换过程当中条件块内的事件监听器和子组件适当地被销毁和重建。 v-if 也是惰性的:若是在初始渲染时条件为假,则什么也不作——直到条件第一次变为真时,才会开始渲染条件块。 相比之下,v-show 就简单得多——无论初始条件是什么,元素老是会被渲染,而且只是简单地基于 CSS 进行切换。 通常来讲,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。所以,若是须要很是频繁地切换,则使用 v-show 较好;若是在运行时条件不多改变,则使用 v-if 较好。
HTML
<!-- vue -->
<div>
<h2>问:猩猩最讨厌什么线?</h2>
<div>
<button :class="[{active: item.active}, 'js-button btn-answer']" v-for="item, index in btns" @click="clickHandle(index)">{{item.text}}</button>
</div>
<div class="js-answer"></div>
<div v-show="show">
<div v-if="answer == 0">
bingo!平行线没有相交(香蕉)
</div>
<div v-else-if="answer == 1">
你怕是个假猩猩吧
</div>
<div v-else>
你怕是个假猩猩吧
</div>
</div>
</div>
<!-- twig -->
{% set items = ['A、平行线', 'B、线段', 'C、交叉线'] %}
{% for item in items %}
<button class="js-button btn-answer"
{{ item }}
</button>
{% endfor %}
<div class="js-answer"></div>
复制代码
data
data () {
return {
show: false,
answer: 0,
btns: [
{
key: 0,
text: 'A、平行线',
active: false
},
{
key: 1,
text: 'B、线段',
active: false
},
{
key: 2,
text: 'C、交叉线',
active: false
}]
}
},
复制代码
js
<!-- jquery -->
mounted() {
$('.js-button').click(function(e) {
let index = $(e.target).index();
let answerText = '';
index ? (answerText = '你怕是个假猩猩吧') : (answerText = 'bingo!平行线没有相交(香蕉)')
$('.js-answer').text(answerText);
$(this).addClass('active').siblings().removeClass('active');
})
}
<!-- vue -->
methods: {
clickHandle(index) {
this.show = true;
this.answer = index;
this.btns.forEach( item=> {
if (item.key == index) {
item.active = true;
} else {
item.active = false;
}
})
}
}
复制代码
绑定事件监听器。事件类型由参数指定。 表达式能够是一个方法的名字或一个内联语句,若是没有修饰符也能够省略。
<!-- 方法处理器 -->
<button v-on:click="doThis"></button>
<!-- 缩写 -->
<button @click="doThis"></button>
<!-- 内联语句 -->
<button v-on:click="doThat('hello', $event)"></button>
<!-- 在子组件上监听自定义事件 (当子组件触发“my-event”时将调用事件处理器) -->
<my-component @my-event="handleThis"></my-component>
复制代码
$emit
与$on
来进行组件之间的数据传输
1.父组件到子组件通讯
2.子组件到父组件的通讯
3.兄弟组件之间的通讯
vm.$on( event, callback )
监听当前实例上的自定义事件。事件能够由vm.$emit触发。回调函数会接收全部传入事件触发函数的额外参数。
vm.$emit( eventName, […args] )
触发当前实例上的事件。附加参数都会传给监听器回调。
vm.$emit('test', 'hi')
vm.$on('test', function (msg) {
console.log(msg) // hi
})
复制代码
代码演示
第一种:父组件给子组件传子,使用props
<!-- 父组件 -->
<child :sonMsg="msg"></child>
// js
import child from './children.vue';
export default {
components: {
child
}
}
复制代码
<!-- 子组件 -->
// html
<div class="children-text">{{sonMsg}}</div>
// js
export default {
props: {
sonMsg: {
type: String,
default: '父组件数据的默认值'
}
}
}
复制代码
第二种:使用$refs
传输数据
<!-- 父组件 -->
// html
<input type="button" @click="parentEnvet" value="父组件触发" />
<child ref="childcomp"></child>
// js
import child from './children.vue';
export default {
components: {
child
},
methods: {
parentEnvet() {
// 注意:这里的childFn是子组件里已存在的方法
this.$refs.childcomp.childFn();
// 或者这样写:this.$refs['childcomp'].childFn();
}
}
}
复制代码
<!-- 子组件 -->
// js
methods: {
childFn() {
// do somethings
}
}
复制代码
第三种:使用$emit 和 $on
传输数据(包括子父通讯)
<!-- 父组件 -->
// html
<div class="parent-box">
<div class="mb20" v-text="vals"></div>
</div>
<div class="children-box">
<child @showMsg="msgFromChild" :sonMsg="msg">
</child>
</div>
// js
<script>
import child from './children.vue';
export default {
components: {
item
},
data () {
return {
vals: '我会展现子组件传给个人数据',
msg: '我是父组件的数据,将传给子组件~'
}
},
methods: {
// 接受子组件的数据
msgFromChild(data) {
this.vals = data;
}
}
}
</script>
复制代码
<!-- 子组件 -->
// html
<div>
<div class="children-text">{{parentMsg}}</div>
<button @click="send">子组件触发</button>
</div>
// js
<script>
export default {
props: {
parentMsg: {
type: String,
default: '父组件数据的默认值'
}
},
data () {
return {
msg: '我真的是太帅了'
}
},
methods: {
send() {
// 给父组件传递数据
this.$emit('showMsg', this.msg)
}
}
}
</script>
复制代码
思考:了解了父子通讯后,你认为非父子组件之间的通讯应该是怎样的呢?
非父子组件之间传值,须要定义个公共的实例文件bus.js,做为中间仓库来传值,否则路由组件之间达不到传值的效果。
1.创建公共的实例文件,内容以下:
// src/util/bus.js
import Vue from 'vue'
export default new Vue();
复制代码
2.分别在非父子组件内引入该公共实例文件(假如命名为Bus)
A组件在方法里使用Bus.$emit('fnName', data)
传送数据
// 组件A
<template>
<div>
<h3>我如今要跟B组件打个招呼</h3>
<input type="text" @change="saiHi" v-model="text"/>
</div>
</template>
<script>
import Bus from '../util/bus.js';
export default {
data () {
return {
text: '你好,我是小猪佩奇A'
}
},
methods: {
saiHi() {
Bus.$emit('saiHi', this.text);
}
}
}
</script>
复制代码
B组件(常在created,mounted生命周期里)使用Bus.$on('fnName', (data) => {xxx})
接收数据
// 组件B
<template>
<div>
<div class="message-text" v-for="msg in msgs" v-text="msg.text"></div>
</div>
</template>
<script>
import Bus from '../util/bus.js';
export default {
data () {
return {
msgs: [{
text: 'hello'
}],
}
},
mounted() {
Bus.$on('saiHi', (data) => {
this.msgs.push({text: data});
})
},
}
</script>
复制代码
**计算属性:**基于它们的依赖进行缓存的。只在相关依赖发生改变时它们才会从新求值。 **侦听属性:**当须要在数据变化时执行异步或开销较大的操做时,这个方式是最有用的。一般更好的作法是使用计算属性而不是命令式的 watch 回调
<div id="demo">{{ fullName }}</div>
复制代码
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
复制代码
fullName属性依赖于firstName和lastName,这里有个缺点就是,不管firstName或lastName其中的任何一个发生改变时,都要调用不一样的监听函数来更新fullName属性。可是当咱们使用计算属性时,代码就会变得更加简洁。
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
复制代码
这时,咱们只要监听fullName属性就行,至于firstName或lastName属性的任何改变,咱们均可以经过fullName的getter()方法获得最终的fullName值。 另外须要注意的是,计算属性默认只有 getter ,不能经过this.xxx = 'xxx'
这种方式去赋值,不过在须要时你也能够提供一个 setter,容许同时设置getter()、setter()方法。以下:
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
复制代码
相同点: 首先它们都是以Vue的依赖追踪机制为基础的,它们的共同点是:都是但愿在依赖数据发生改变的时候,被依赖的数据根据预先定义好的函数,发生“自动”的变化。
不一样点: watch和computed各自处理的数据关系场景不一样 (1) watch擅长处理的场景:一个数据影响多个数据。适合监控场景,某【一个】变量改变时须要作什么操做;相似于onchange,适合耗时操做,如网络请求等。 (2) computed擅长处理的场景:一个数据受多个数据影响。某【一些】变量发生变化时,影响的【单个】结果对应地发生改变。
建立前/后**(beforeCreated/created)**: 在beforeCreated阶段,vue实例的挂载元素$el
和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,$el
尚未。
载入前/后**(beforeMount/mounted)**:在beforeMount阶段,vue实例的$el和data都初始化了,但仍是挂载以前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后**(beforeUpdate/updated)**:当data变化时,会触发beforeUpdate和updated方法。
销毁前/后**(beforeDestory/destroyed)**:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,可是dom结构依然存在