vue2主要语法点记录。下面的代码是为了速查用法,没有使用脚手架,js为es5写法,没有注意eslink验证。
vue实例
js
var vm = new Vue ({
el: '#app',
data: {
msg: 'hello vue'
}
});
console.info(vm.msg); //hello vue
console.info(vm.$data.msg); //hello vue
console.info(vm.msg === vm.$data.msg) //true
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>vue</title>
<script type="text/javascript" src="https://cdn.bootcss.com/vue/2.5.13/vue.min.js"></script>
</head>
<body>
<div id="app">
{{msg}}
</div>
<script type="text/javascript" src="script/index.js"></script>
</body>
</html>
vue实例中的选项:
el:vue实例的挂载点,和angular中的ng-app类似,可以用css选择符
data:vue实例上挂载的数据,可以用实例.$data.名称
提取,也可以用实例.名称
提取,是一份数据,和angular中的scope类型。
template:使用template模板替换挂载点内容。
components:引入其他组件。
使用脚手架生成的SPA框架,vue实例已经初始化好,挂载在入口index.html的#app上。
动态改变数据
var vm = new Vue ({
el: '#app',
data: {
msg: 'hello vue',
person: {
name: 'thatway'
}
},
methods: {
addAge: function(){
console.info("addAge");
this.$data.person.age = 18;
console.info(this.person.age); //18
}
}
});
给this.$data动态添加数据,注意是添加新数据不是修改,视图上不会出现新数据,上面的实例中虽然打印出18,但视图并没有改变,动态改变实例数据的方法:
用途 | 用法 |
---|---|
单个属性 | Vue.set(Object,key,value) |
多个属性 | Object.assign() |
实例中this.$data.person.age = 18;
更改为Vue.set(this.person,'age',18);
视图随之改变。
多个数据:
this.person = Object.assign({},this.$data.person,{age: 18, name:'wp'});
Object.assign 将参数中的所有对象属性和值 合并到第一个参数 并返回合并后的对象。
获取dom更新后数据
更新后dom中的数据 通过 Vue.nextTick(callback)
tick: function(){
this.msg = 'change'
this.$nextTick(function () {
console.log('$nextTick中打印:', this.$el.children[0].innerText);
})
console.log('直接打印:', this.$el.children[0].innerText);
}
输出:
直接打印: hello vue
$nextTick中打印: change
计算属性
计算属性,是vue中可以声明一系列属性,这些属性是通过计算而来的,它依赖于参与计算的属性是否发生变化,计算结果会被缓存,参与计算的属性值不变则会使用缓存,可以提升性能。
var vm = new Vue ({
el: '#app',
data: {
v1: 10,
v2: 9
},
computed: {
computeValue: function(){
return this.v1 + this.v2;
}
}
});
页面中
<div>{{computeValue}}</div>
组件
全局组件
全局组件在所有的vue实例中都可以使用
Vue.component('component-test',{
template: '<div>this is component-test,{{componentMsg}}</div>',
data: function(){
return {
componentMsg: 'hello component'
}
}
});
页面中使用标签
<component-test></component-test>
需要注意的是
全局组件要在vue实例化之前注册,坑
template比较长时可以用x-template方式引入
<script type="text/x-template" id="testtpl">
<div>{{componentMsg}}</div>
</script>
组件中改为
Vue.component('component-test',{
template: '#testtpl',
data: function(){
return {
componentMsg: 'hello component'
}
}
});
效果一样。有点angular中模板缓存的意思。
大多数情况下是不需要注册全局组件的,而是创建好组件需要的地方引入组件。
局部组件
在需要引入组件的实例中使用components选项实现。
var componentTest = {
template: '#testtpl',
data: function(){
return {
componentMsg: 'component'
}
}
}
var vm = new Vue ({
el: '#app',
data: {
msg: 'hello vue',
person: {
name: 'thatway'
}
},
components: {
'component-test':componentTest
}
});
当组件名声明为驼峰写法时,视图中应在驼峰处改为-连接,如声明一个组件componentTest,视图中的标签名应为component-test。
component模板中只能有一个根节点,这点与angular、react都是一样的。
使用webpack模板,每一个组件可以封装成一个.vue文件,导出后在需要的组件上引入,多页面应用时就要自己来组织了。
组件data
上面封装组件时,如果数据是使用data{componentMsg: 'component'}
那么,所有组件都将引用这个data,有点类似angular的全局scope,实际希望每个组件拥有自己的数据,对外不影响,应该使用data:function(){return 数据对象}
的方式,有点类似angular的独立scope。
组件通信
组件内的数据仅当前组件可见,这就需要一套与其他组件进行数据通信的机制,比如首页上有可能出现两个广告位,这两个广告位的数据是相互独立的,互不影响,但又有可能都是从父组件(首页)中获取的。在之前的angular项目中绝大部分的组件数据都封装成开放的了,共有一份scope数据,仅将页面中一开始就有多个的组件数据封装为独立scope,实践证明是有问题的,在某个组件在未来需要在页面上出现多个时麻烦就来了,及时不出现多个,数据也是混乱的。
- 父组件到子组件
父组件中的数据传递到子组件中,关键在子组件的component实例中使用props选项。
var componentTest = {
props: [
'personInfo',
'stringMsg'
],
template: '#testtpl',
data: function(){
return {
componentMsg: 'component'
}
}
};
var vm = new Vue ({
el: '#app',
data: {
msg: 'hello vue',
person: {
name: 'thatway'
}
},
components: {
'component-test':componentTest
}
});
组件模板
<script type="text/x-template" id="testtpl">
<div>
<div>personName:{{personInfo.name}}</div>
<div>stringMsg:{{stringMsg}}</div>
</div>
</script>
页面中
<component-test :person-info="person" string-msg="this is string"></component-test>
这里同样注意参数的驼峰转连接符问题。
- 子组件到父组件
子组件的数据传递给父组件,需要使用vue的自定义事件机制,与react是一样的。
var childComponent = {
template: '<div><button @click="toParent">向父组件传递数据</button></div>',
data: function(){
return {
info: {
msg: 'this is child msg'
}
}
},
methods: {
toParent: function(){
console.info("toParent");
this.$emit('parentfn',this.info);
}
}
};
var vm = new Vue ({
el: '#app',
data: {
msg: 'hello vue',
person: {
name: 'thatway'
}
},
components: {
'component-test': componentTest,
'childComponent': childComponent
},
methods: {
handleChild: function(data){
console.info("来自子组件的数据" + data.msg);
}
}
});
页面中
<child-component @parentfn="handleChild"></child-component>
子组件上定义一个自定义事件parentfn,指向父组件的一个方法handleChild。
子组件内部toParent方法,使用$emit触发parentfn事件,并给事件传值。
- 非父子组件通信
两个没关系的组件通信可以借助在空vue实例绑定与触发自定义事件来实现。
var vueTemp = new Vue();
var childComponentA = {
template: '<div><button @click="toA">告诉B点事</button></div>',
data: function(){
return {
msg: '你背后有个人...'
}
},
methods: {
toA: function(){
var that = this;
vueTemp.$emit('handleA',that.msg);
}
}
};
var childComponentB = {
template: '<div>B告诉我{{talk}}</div>',
data: function(){
return{
talk: ''
}
},
created: function(){
var that = this;
vueTemp.$on('handleA',function(data){
console.info("handleA:"+data);
that.talk = data;
});
}
};
var vm = new Vue ({
el: '#app',
data: {
msg: 'hello vue',
person: {
name: 'thatway'
}
},
components: {
'childComponentA': childComponentA,
'childComponentB': childComponentB
}
});
页面中
<child-component-a></child-component-a>
<child-component-b></child-component-b>
代码中创建了一个空的vue实例vueTemp,在A中$on绑定一个自定义事件,在B中触发自定义事件。
上面代码中因为是es5的语法,会出现this指向问题,es6箭头函数就不用转换了。
- 组件插槽
vue中使用slot标签可以实现内容的占位或者叫分发。
var slotComponent = {
template: '<div>' +
'这是slotComponent的内容' +
'<slot></slot>' +
'<slot name="slotA"></slot>' +
'</div>'
};
var vm = new Vue ({
el: '#app',
data: {
msg: 'hello vue',
person: {
name: 'thatway'
}
},
components: {
'slotComponent': slotComponent
}
});
页面中
<slot-component>
<div slot="slotA">这是带名称的slot</div>
<div slot>页面上原来的内容</div>
</slot-component>
可以有一个不带名称的slot,实际场景里一般一个就够用了,就不用写name了,内容出现的位置是组件template中slot标签的位置。
- 引用组件
vue实例上有一个$refs
,页面中的元素(标签)如果声明了ref,则可以通过$refs
获取到,如果是普通html标签,则获取到的是html元素,如果是一个组件,则获取到这个组件的实例数据。
var vm = new Vue ({
el: '#app',
data: {
msg: 'hello vue',
person: {
name: 'thatway'
}
},
components: {
'slotComponent': slotComponent
},
mounted: function(){
console.info(this.$refs.refdiv);
console.info(this.$refs.refcomponent);
}
});
页面中
<div v-text="person.age" ref="refdiv"></div>
<slot-component ref="refcomponent">
<div slot="slotA">这是带名称的slot</div>
<div slot>页面上原来的内容</div>
</slot-component>
指令
指令(directive)是用于数据与视图进行交互,实际运用是vue中以v-开头的标签属性,在vue中指令叫directive,组件叫component,需要理解、区分概念。
指令看官方文档即可,下面简单罗列常用指令。
指令 | 简写 | 修改器 | 描述 |
---|---|---|---|
v-html | - | - | 向元素绑定html内容 |
v-text | - | - | 与插值{{}}相同效果,但可防止闪屏 |
v-bind | : | - | 绑定属性值 |
v-model | - | - | 绑定数据对象,双向绑定 |
v-for | - | - | 循环,item in list、(item,index)in list、(item,key,index) in list、item in 1000,提供唯一标识避免渲染耗时用:key=”标识” |
v-if | - | - | 判断,会创建和销毁dom |
v-show | - | - | 切换显示状态,dom始终存在 |
v-on | @ | .stop 阻止冒泡、.prevent 阻止默认行为、capture 添加事件侦听器时使用事件捕获模式、.self 只当事件在该元素本身(比如不是子元素)触发时,才会触发事件、.once事件只触发一次 | 绑定时间,如v-on:click或@click |
v-once | - | - | 数据只绑定一次 |
v-pre | - | - | 内容显示原始状态 |
样式
与angular中的ng-class类似。
<!-- 1 -->
<div v-bind:class="{ active: true }"></div> ===> 解析后
<div class="active"></div>
<!-- 2 -->
<div :class="['active', 'text-danger']"></div> ===>解析后
<div class="active text-danger"></div>
<!-- 3 -->
<div v-bind:class="[{ active: true }, errorClass]"></div> ===>解析后
<div class="active text-danger"></div>
--- style ---
<!-- 1 -->
<div v-bind:style="{ color: activeColor, 'font-size': fontSize + 'px' }"></div>
<!-- 2 将多个 样式对象 应用到一个元素上-->
<!-- baseStyles 和 overridingStyles 都是data中定义的对象 -->
<div v-bind:style="[baseStyles, overridingStyles]"></div>
自定义指令
自定义指令用来操作dom,就是自己定义一些v-指令,和组件、过滤器一样,有全局和局部的区别。
直接贴个大拿的解释代码吧:
全局指令
// 第一个参数:指令名称
// 第二个参数:配置对象,指定指令的钩子函数
Vue.directive('directiveName', {
// bind中只能对元素自身进行DOM操作,而无法对父级元素操作
// 只调用一次 指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
bind( el,binding, vnode ) {
// 参数详解
// el:指令所绑定的元素,可以用来直接操作 DOM 。
// binding:一个对象,包含以下属性:
// name:指令名,不包括 v- 前缀。
// value:指令的绑定值,等号后面的值 。
// oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
// expression:字符串形式的指令表达式 等号后面的字符串 形式
// arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
// modifiers:指令修饰符。例如:v-directive.foo.bar中,修饰符对象为 { foo: true, bar: true }。
// vnode:Vue 编译生成的虚拟节点。。
// oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
},
// inserted这个钩子函数调用的时候,当前元素已经插入页面中了,也就是说可以获取到父级节点了
inserted ( el,binding, vnode ) {},
// DOM重新渲染前
update(el,binding, vnode,oldVnode) {},
// DOM重新渲染后
componentUpdated ( el,binding, vnode,oldVnode ) {},
// 只调用一次,指令与元素解绑时调用
unbind ( el ) {
// 指令所在的元素在页面中消失,触发
}
})
// 简写 如果你想在 bind 和 update 时触发相同行为,而不关心其它的钩子:
Vue.directive('自定义指令名', function( el, binding ) {})
// 例:
Vue.directive('color', function(el, binding) {
el.style.color = binging.value
})
// 使用 注意直接些会被i成data中的数据“red” 需要字符串则嵌套引号"'red'"
<p v-color="'red'"></p>
局部变量
var vm = new Vue({
el : "#app",
directives: {
directiveName: { }
}
})
过滤器
过滤器是在页面上输出之前做一遍过滤,分全局过滤器和局部过滤器,用法和组件基本一样
全局过滤器:
Vue.filter('testfilter',function(value){
return value+"filter";
});
<div>{{person.name|testfilter}}</div>
局部过滤器只对当前实例有效,使用实例的filters属性
var testFilter = function(value){
return 'filter,'+value;
};
var vm = new Vue ({
el: '#app',
data: {
msg: 'hello vue',
person: {
name: 'thatway'
}
},
filters:{
testFilter:testFilter
}
});
watch
监听实例数据,和angular的$watch作用一样。
var vm = new Vue ({
el: '#app',
data: {
msg: 'hello vue',
person: {
name: 'thatway'
},
info: {
key: 'thatway'
}
},
filters:{
testFilter:testFilter
},
methods:{
changeData: function () {
this.msg = "123";
this.person.name = 'wp';
this.info.key = '111';
}
},
watch: {
msg: function(newVal,oldVal){
console.info("watch msg");
console.info(newVal,oldVal);
},
person: {
handler: function(newVal,oldVal){
console.info("watch person");
console.info(newVal,oldVal);
},
deep:true
},
'info.key': function(newVal,oldVal){
console.info("watch info.key");
console.info(newVal,oldVal);
}
}
});
生命周期
vue在生命周期中提供了一系列的钩子函数。官方图很清晰,这里做个简单记录。
- beforeCreate()
在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用,此时,无法获取 data中的数据、methods中的方法 - created()
实例已创建完毕,最常用的生命周期,可以调用methods中的方法、改变data中的数据 - beforeMounted()
实例挂载之前被调用 - mounted()
vue实例已经挂载到页面中,dom已经渲染好 - beforeUpdated()
数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。此处获取的数据是更新后的数据,但是获取页面中的DOM元素是更新之前的。 - updated()
组件 DOM 已经更新,可以执行依赖于 DOM 的操作。 - beforeDestroy()
实例销毁之前调用。在这一步,实例仍然完全可用。使用场景:实例销毁之前,执行清理任务,比如:清除定时器等。 - destroyed()
Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
vue中文文档:https://cn.vuejs.org/v2/api/