Vue.js 的核心是允许采用简洁的模版语法来声明式地将数据渲染进DOM的系统。
介绍
结合DOM树我们来说一下 Vue 框架的数据渲染(数据绑定)。
文本节点渲染数据
通过插值表达式:{{}}
属性节点渲染数据
通过: v-bind:attribute
DOM结构渲染数据
通过:v-if、v-show、v-for
交互
Vue通过 v-on 添加事件监听器,调用实例里定义的方法,让用户和应用进行交互。
实例
Vue组件都是Vue实例,并且接受相同的选项对象(根实例特有的选项除外。)
数据和方法
当一个 Vue实例被创建时,它将 data 对象中的所有参数加入到 Vue的响应系统中。当这些参数的值发生改变时,视图会产生响应。
只有当Vue实例被创建时,就已经存在的data对象中的参数才是响应式的。
例外:Object.freeze() 会阻止修改 data对象中参数的值
let obj = {
message: 'hello world'
}
Object.freeze(obj)
var vm = new Vue({
el: '#app',
data: obj
})
报错翻译:无法给只读属性的 message 分配对象
生命周期
生命周期钩子的this 指向调用它的 Vue实例。
不要在选项方法或者回调函数上使用箭头函数,因为箭头函数并没有this,this会作为变量一直向上级词法作用域查找,直至找到为止,经常会导致报错。
var vm = new Vue({
el: '#app',
data: {
message: 'hello world'
},
created: () => {
console.log(this.message)
}
})
模版语法
插值
<span v-once>{{message}}</span>
v-once 一次性地插值,当数据改变时,插值处的内容不会更新。
v-html
你的站点上动态渲染的任意 html,可能会非常危险,因为它很容易导致 xss攻击。请只对可信任内容使用 html 插值,绝不要对用户提供的内容使用插值。
属性
<input v-bind:disabled="show" type="text">
对于布尔属性,例如 disabled,存在就意味着禁用,但v-bind 略有不同,如果 show 值为 null、false、undefined时,disabled不起作用甚至不会渲染。
对于所有数据绑定, Vue都提供了完全的 js表达式。 {{message + 1}} {{a+1>0 ? yes : no}} <span :id="'item' + id">,这些表达式在所属 Vue实例的数据作用域下作为 js被解析,有个限制就是每个绑定都只能包含单个表达式,{{var a = 1}} 不被支持。
模板表达式都被放在沙盒中,只能访问全局变量的一个白名单,如 Math和Date,{{Date()}},不应该在模版表达式中试图访问用户定义的全局变量。
指令-动态参数
<div @[handlename]="value"></div>
动态参数预期会求出一个字符串,异常情况下值为 null, null值可以被显性的用于移除绑定,任何其他字符串类型的值都将会触发一个警告。
var vm = new Vue({
el: '#app',
data: {
message: 'hello world',
name: "123"
}
})
报错翻译:在“元素”上执行“setAttribute”失败:“123”不是一个有效的属性名称。
var vm = new Vue({
el: '#app',
data: {
message: 'hello world',
name: 1
}
})
报错翻译:动态指令参数无效值(预期字符串或null)
动态参数表达式的规范:不需有空格和引号(使用没有空格和引号的表达式或者用计算属性替代这种复杂表达式)、避免使用大写字母
修饰符
用于指出一个指令应该以特殊的方式绑定。
计算属性和侦听器
在模版内的表达式,一旦有复杂的逻辑时,都应该应用计算属性。
计算属性具有缓存性,是基于响应式依赖进行缓存的,只在相关响应式依赖发生改变时,才会重新计算。
计算属性对象内的方法名可以直接当做数据参数进行使用。(Vue实例会先在 data 中查找,如果没有发现,就会在计算属性里查找)
computed:{
now: function(){
return Date.now()
}
}
计算属性缓存 vs 方法
methods:{
now: function(){
return Date.now()
}
}
now 和 now() 的值是一样的,相比之下,调用方法,每当触发重新渲染时,将总会再次执行,性能上计算属性更好一些。
getter 和 setter
computed:{
now: {
get: function(){
return Date.now()
}
set: function(newValue){ //当now值改变时执行
console.log(value)
}
}
}
侦听器
相比侦听器,计算属性在大部分情况下更适合。但是,在需要数据变化时执行异步或者开销较大的操作时,侦听器更适合。
侦听器同样具有缓存,只有当侦听数据变化时,才会重新执行。
<div id="app">
<input type="text" v-model="message">
</div>
<script>
let vm = new Vue({
el: '#app',
data: {
message: 'Hello',
},
watch: {
message: function (newQuestion,oldQuestion){
console.log(newQuestion,oldQuestion)
this.message = "new Hello"
console.log("即将显示最新值 ↓")
console.log(newQuestion,oldQuestion)
}
}
})
</script>
Class 与 Style 绑定
html语法参照如下:
<style>
.home{color: red;}
</style>
<div style="color:red;">hello world</div>
对象语法
<div :class="{active: isActive, item: isItem}" class="home"></div>
active、item(class名)的样式是否生效,取决于 isActive、isItem 的值。 :class 和 class 属性可以同时存在。
另一种简洁写法,可以通过 classObj 参数的值,来觉决定想要显示的样式。
<div :class="classObj"></div>
<script>
data: {
classObj: {
active: true,
item: null
}
}
</script>
我们也可以在 classObj 绑定一个返回对象的计算属性,这是一个常用且强大的模式。
数组语法
<div :class="[home, item]">{{message}}</div>
<script>
data: {
home: '',
item: 'classItem'
}
</script>
数组内的元素,类似于变量,home为空,所以class样式为 classItem。
在数组里使用对象语法
<div :class="[home, {active: isActive}]"></div>
style 对象语法
<div :style="{color: colorValue, fontSize: sizeValue}"></div>
<script>
data: {
colorValue: 'red',
sizeValue: '80px'
},
</script>
或者绑定样式对象
<div :style="styleObj"></div>
<script>
data: {
styleObj:{
colorValue: 'red',
sizeValue: '80px'
}
},
</script>
style 数组语法
div :style="[colorValue, sizeValue]">hello</div>
<script>
data: {
colorValue:{
color: 'green',
fontSize: '30px'
},
sizeValue: {
lineHeight: '50px'
}
},
</script>
:style 数组语法,可以将多个对象数据应用到一个元素上。
条件渲染
<template v-if="show">
<div>……</div>
<div>条件渲染</div>
</template>
<div v-if="show"></div>
<div v-else-if="show1"></div>
<div v-else></div>
//需要紧挨在一起使用
整块的显示隐藏可以用 tempalte 当成不可见的包裹元素(v-if可以,v-show不可以)。频繁切换建议使用 v-show,反之 v-if。
列表渲染
<div v-for="(item, index) in items" :key="item.id">{{item}}</div>
<div v-for="(value, key, index) in items">{{value}}</div>
key 值,不建议直接使用 index,因为在频繁操作 index 对应的数据时,还是比较费性能的,让 Vue 没有办法充分复用节点。
数组更新的三种方式
1、变更方法(push、pop、shift、unshift、reverse、splice、sort)
这些数组方法竟会触发视图更新。
2、替换数组
vm.items = [] //重新赋值
3、set 方式
//数组 第一个参数是 具体数组对象 第二个参数是 索引 第三个参数是 变更后的值
Vue.set(vm.items, 0, 8)
vm.$set(vm.items, 0, 1)
//对象
Vue.set(vm.items, "name", "Lee")
vm.$set(vm.items, "name", "Lee")
对象变更的两种方式:一是重新赋值、一是set方法。
v-for 和 计算属性
<script>
data: {
list:[1,2,3,4,5,6]
},
computed: {
items: function(){
return this.list.filter(function(item){
return item % 2 === 0
})
}
}
</script>
类似于 v-if 可以使用携带v-for的 <template> 循环渲染一段含有多个元素的内容。
事件处理
this 在方法里指向当前的 Vue实例。event是原生的DOM事件。
methods: {
addNewTodo: function (event) {
console.log(this.name)
console.log(event)
}
}
//还可以用Js直接调用方法 vm.addNewTodo()
事件修饰符
.stop 阻止单击事件继续传播
.once 点击事件只会触发一次
.prevent
.self
.passive 不想阻止事件的默认行为
.capture
按键修饰符:在监听键盘事件时,需要检查详细的按键
<input v-on:keyup.enter="submit">
//点击 enter键时,才会调用 submit 方法
.exact 精确系统修饰符
<button v-on:click.ctrl.exact="onCtrlClick">A</button>
//只按住 ctrl 再点击才会执行
表单输入绑定
<input type="checkbox" v-model="check">
//单个复选框的绑定值是布尔值
//多个复选框绑定值是数组,数组元素为单个复选框的 value 值
可以把表单的值绑定到 :value 上,可以传自定义的值
<input type="radio" v-model="radio" :value='a'>
<script>
data: {
radio:'',
a:'yes'
}
//当单选框被选中时,radio的值为 yes
</script>
修饰符
.lazy change事件,会触发数据更新(默认是 input 事件)
<input type="text" v-model.lazy="message">
//默认情况下输入时,message会时时更新
//.lazy 只有当输入结束,message的值才会更新
.number 可以将绑定的值转为 数值类型
<input v-model.number="age" type="number">
//typeof(age) 为 number
.trim 可以自动过滤用户输入的首尾空白字符
<input type="text" v-model.trim="message">
//如果输入 ' name ', message 的值为 'name'
组件基础
每个组件都会各自独立维护它的数据,因为每用一次组件,就会有有一个它的新实例被创建。
组件的 data 必须是一个函数,来返回数据,便于组件都有独立的数据存储。
//这是一个全局组件
Vue.component('item',{
template:'<div>{{message}}</div>',
data: function(){
return {
message: 'wenmeichao'
}
}
})
父子组件间的传值: 父子间通过属性向子组件传值,子组件通过 props 来接收。子组件通过 $emit ('change',参数)向父组件传值,父组件 @change="handle" 来接收。
每个组件必须只有一个根元素。
1、在 table ul/li select 标签内使用组件,可能出现解析错误,用 is 解决
<table>
<custom-input></custom-input>
</table>
<script>
Vue.component('custom-input', {
template: '<tr><td></td></tr>'
})
</script>
组件中的内容,并没有如我们预期的那样,出现在 table 中,这是因为 html 的编码规范中,table 标签内,只能用 tr 标签,而不是 <custom-input> 标签
解决方案:
<table>
<tr is="custom-input"></tr>
</table>
用 is 属性,这样既符合编码规范,又能把组件渲染出来。