初始示例代码
Hello,{{name.toUpperCase()}},{{address}}
Vue模板语法有2大类:
插值语法:
功能:用于解析标签体内容
写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性
指令语法:
功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)
举例:v-bind:href=“xxx” 或 简写为 :href=“xxx”,xxx同样要写js表达式,且可以直接读取到data中的所有属性
代码
Vue中有2种数据绑定的方式:
单向绑定(v-bind):数据只能从data流向页面
双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data
tips:
1.双向绑定一般都应用在表单类元素上(如:input、select等)
2.v-bind可以简写为:
2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值
代码
单向数据绑定:
双向数据绑定:
单向数据绑定:
双向数据绑定:
el有2种写法
new Vue时候配置el属性
先创建Vue实例,随后再通过vm.$mount(‘#root’)指定el的值
代码
data有2种写法
对象式
函数式
在组件中,data必须使用函数式,否则会报错
一个重要的原则:由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。
代码
1.data中所有的属性,最后都出现在了vm身上。
2.vm身上所有的属性及Vue原型上所有属性,在Vue模板中都可以直接使用。
const vm = new Vue({el: '#root',data: {name: 'yaya',address: '北京'}
})
了解数据代理需要js的一些知识:Object.defineProperty(),属性标志,属性描述符,getter,setter。。。
建议学习文章地址:
https://zh.javascript.info/property-descriptors
https://zh.javascript.info/property-accessors
这里简单介绍一下:
属性标志:
对象属性(properties),除 value
外,还有三个特殊的特性(attributes),也就是所谓的“标志”
writable
— 如果为 true
,则值可以被修改,否则它是只可读的enumerable
— 如果为 true
,则表示是可以遍历的,可以在for… .in Object.keys()中遍历出来configurable
— 如果为 true
,则此属性可以被删除,这些特性也可以被修改,否则不可以eg:
回顾Object.defineproperty方法
Object.getOwnPropertyDescriptor(obj, propertyName)
这个方法是查询有关属性的完整信息 obj是对象, propertyName是属性名
let user = {name: "John"
};let descriptor = Object.getOwnPropertyDescriptor(user, 'name');console.log(descriptor)/* 属性描述符:
{"value": "John","writable": true,"enumerable": true,"configurable": true
}
*/
打印结果
Object.defineProperty(obj, prop, descriptor)
obj:要定义属性的对象。
prop:要定义或修改的属性的名称
descriptor:要定义或修改的属性描述符
let user = {name: "John"
};Object.defineProperty(user, "name", {writable: false
});user.name = "Pete";// 打印后还是显示 'John',无法修改name值
其他的属性标志就不演示了,接下来看重点:访问器属性。
访问器属性:
本质上是用于获取和设置值的函数,但从外部代码来看就像常规属性。
访问器属性由 “getter” 和 “setter” 方法表示。在对象字面量中,它们用 get
和 set
表示:
let obj = {get name() {// 当读取 obj.propName 时,getter 起作用},set name() {// 当执行 obj.name = value 操作时,setter 起作用}
}
更复杂一点的使用
let user = {surname: 'gao',name: 'han'get fullName() {return this.name + this.surname;}
}console.log(user.fullName)
从外表看,访问器属性看起来就像一个普通属性。这就是访问器属性的设计思想。我们不以函数的方式 调用 user.fullName
,我们正常 读取 它:getter 在幕后运行。
vue的计算属性的底层构造感觉用到了这种思想,我目前还没看过源码,是这样猜想的。
截至目前,fullName
只有一个 getter。如果我们尝试赋值操作 user.fullName=
,将会出现错误:
user.fullName = "Test"; // Error(属性只有一个 getter)
为 user.fullName
添加一个 setter 来修复它:
let user = {surname: 'gao',name: 'han'get fullName() {return this.name + ' ' + this.surname;}set fullName(value) {// 这个用到了新语法 结构赋值[this.surname, this.name] = value.split(' ');}
}user.fullName = 'Li Hua'console.log(user.name);
console.log(user.surname);
终于可以介绍数据代理了:
数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)
先来看个案例:
let obj = {x: 100
}let obj2 = {y: 200
}
这时候提一个需求:我们想要访问 obj 中的 x 的值,但我们最好不要直接去访问 obj ,而是想要通过 obj2 这个代理对象去访问。
这时候就可以用上 Object.defineProperty(),给 obj2 添加上访问器属性(也就是getter和setter)
代码
let obj = {x: 100
}let obj2 = {y: 200
}Object.defineProperty(obj2, 'x', {get() {return obj.x;},set(value) {obj.x = value;}
})
接下来介绍Vue中的数据代理
我来用一个案例来详细解释这一个过程。
学校名称:{{name}}
学校地址:{{address}}
我们在控制台打印 new 出来的 vm
可以看到,写在配置项中的 data 数据被 绑定到了 vm 对象上,我先来讲结果,是 Vue 将 _data 中的 name,address 数据 代理到 vm 本身上。
一脸懵逼?
先来解释下_data 是啥, _data 就是 vm 身上的 _data 属性,就是下图那个
这个 _data 是从哪来的?
new Vue 时, Vue 通过一系列处理, 将匹配项上的 data 数据绑定到了 _data 这个属性上,并对这个属性进行了处理(数据劫持),但这个属性就是来源于配置项中的 data,我们可以来验证一下。
打印结果为true,说明两者就是同一个
好了,再回到数据代理上来,将 vm._data 中的值,再代理到 vm 本身上来,用vm.name 代替 vm._data.name。这就是 Vue 的数据代理
这一切都是通过 Object.defineProperty() 来完成的,我来模拟一下这个过程
Object.defineProperty(vm, 'name', {get() {return vm._data.name;},set(value) {vm._data.name = value}
})
这样有啥意义?明明通过 vm._data.name 也可以访问 name 的值,为啥费力去这样操作?
在插值语法中,{{ name }} 取到的值就相当于 {{ vm.name }},不用数据代理的话,在插值语法就要这样去写了。
{{ _data. name }} 这不符合直觉,怪怪的。vue 这样设计更利于开发者开发,我们在研究原理会觉得有些复杂
来个尚硅谷张天禹老师做的图(非常推荐去看他的课,讲的非常好)
事件的基本使用:
欢迎来到{{name}}学习
Vue中的事件修饰符
键盘事件语法糖:@keydown,@keyup
欢迎来到{{name}}学习
计算属性完整版写法
姓:名: 全名:{{fullName}}
计算属性简写
姓:名: 全名:{{fullName}}