1. 插值语法 {{}} 可以写什么???
- 在data中声明的变量,函数等都可以
- 常量
- 合法的JavaScript表达式
- 模板表达式都被放置盒中,只能访问全局变量的一个白名单,如Math 和 Date等
'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,'
'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,'
'require'
- 补充:js表达式只能放三目运算符
- 三目运算符语法
{{gender ? `男` : `女`}} //如果为true返回第一个,false返回第二个
gender:true, //布尔值
2.指令语法
1. 什么是指令?有什么作用?
- 指令的职责是:当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM
- Vue框架中的所有指令的名字都是以
v-开始
3. 插值是写在标签体中,那么指定写在哪里?
- vue框架中所有的指令都是以HTML标签的属性形式存在的.
- 比如:
<span 指令语法处>{{插值语法处}}</span>- 注意:虽然指令是写在标签的属性位置上,但是指令浏览是无法直接看懂的
- 是需要通过vue进行编译的,编译之后的内容浏览器是可以看懂的
4. 指令的语法规则
- 指令是一个完整的语法格式:
<HTML标签 v-指令名:参数="javascript表达式"></HTML标签>- 表达式:
- 之前的插值语法中{{}},可以写什么,那么指令中的表达式就可以写什么
- 但是:在指令中的表达式不能在外层添加{{}}
- 不是所有的指令都有参数和表达式:
- 有的指令,不需要参数,也不需要表达式. eg: v-once
- 有的指令,不需要参数,但需要表达式. eg: v-if="表达式"
- 有的指令,需要参数,也需要表达式. eg:v-bind:参数="表达式"
5. v-once 指令
- 作用: 只渲染一次元素,后面的重新渲染,元素及所有的子节点都会被视为静态内容并被跳过.这可以用于优化更新性能。
6. v-if 指令
- 作用: 表达式的执行结果需要是一个布尔值的数据: ture或false
- true 这个指令所在的标签,会被渲染到浏览器中
- false: 这个指令所在的标签,不会被渲染到浏览器中
7. v-bind 指令(重点)
-
该指令的作用?
- 该指令可以让html的标签的某个属性的值产生动态的效果
-
语法格式 -
<html 标签 v-bind:参数="表达式"></html> -
v-bind指令的编译原理?
- 编译前:
- <HTML标签 v-bind:参数="表达式"></HTML标签>
- 编译后:
- <HTML标签 参数="表达式的执行结果"></HTML标签>
- 注意两点:
- 在编译的时候v-bind后面的"参数名"会被编译为HTML的属性名
- 表达式会关联data,当data发生改变后,表达式的执行结果会发生变化
- 所有:连带的就会产生动态的效果
- 编译后:
- v-bind的简写方式:
<img :src = "IMSI">
- 什么时候用插值语法,什么时候用指令?
- 当标签体中的内容需要动态设置时,使用插值语法
- 当HTML标签的属性动态设置时,使用指令语法
- 编译前:
- <HTML标签 v-bind:参数="表达式"></HTML标签>
//简写
<img :src="imgArr[4] ,width,height" alt="鞠婧祎" >
//完整写法
<img v-bind:src="imgArr[4] ,width,heig" alt="鞠婧祎">
//推荐简写
<input type="text" name="useName" :value="userName">
<a :href="url">点我</a>
data: {
imgArr:[`./images/1.webp`,`./images/2.webp`,`./images/3.webp`,
`./images/4.webp`,`./images/5.webp`,`./images/6.webp`
],
width:`500px`,
height:`500px` ,
userName:"张三",
url:`https://juejin.cn/`
}
})
8. v-bind 和 v-mode的区别和联系
- v-bind 和v-model 都可以完成数据绑定
- v-bind是单向数据绑定
- 数据(data) ==> 视图(view)
- v-model是双向数据绑定
- 数据(data) <===> 视图(view)
- v-bind可以使用在任何html元素中,v-model只能使用在表单类元素上,列如:
- input标签,select标签,textare标签
- 为什么v-model会有这个限制???
- 因为表单类的元素才能给用户提供交互输入的界面 - v-modl指令通常也是写在value属性上
- v-biand和v-model都有简写方式:
- v-bind 简写为 :
- v-model 简写为 v-molde=""
3.MVVM模型
1. MVVM是什么?
- M Model(模型/数据)
- V View(视图)
- VM ViewModel(视图模型): VM是MVVM中的核心
- MVVM是目前前端开发主流框架中非常流行的开发思想(一种架构模式)
- 目前主流的前端框架都遵循MVVM思想(如:React Vue)
-
MVVM中倡导来Model和View进行分离,为什么要分离?
- 如果View和Model不分离,使用最原始的js代码写项目
- 如果数据发生任意的改动,那么就需要大量操作DOM元素的js代码
- 也就是说,当Model发生改变之后,VM自动去更新View,当View改变之后
- Vm会自动更新Model.
- 如果View和Model不分离,使用最原始的js代码写项目
<!--view V(视图)-->
<div id="app">
姓名 <input type="text" v-model="name">
</div>
<script>
<!-- View model VM(视图模型)-->
const vm = new Vue({
el:`#app`,
data:{
// model M(模型)
name:`江桥`
}
})
</script>
4.Vue实例可以访问哪些属性?
- Vue实例中的属性很多,有的以$开始,有的以_开始
- 所有以$开始的属性,都可以是作为公开的属性,这些属性是提供给程序员使用的
- 所有以_开始的属性,可以看做是私有的属性,这些属性是Vue框架底层使用的
- 通过vm也可以访问Vue实例对象的原型对象上的属性 比如:vm.$delete...
5.Vue2响应式实现原理
1. Vue2 通过Object.defineProperty()实现数据响应式代理
- 这个方法是ES5新增的。
- 通过该方法给对象新增属性,或设置对象原有的属性obj
- 怎么用?
- Object.defineProperty(给哪个对象新增属性,
新增对象属性名,{设置key:value对})
- Object.defineProperty(给哪个对象新增属性,
- 怎么用?
- 第三个参数的配置项有哪些?以及他们的作用?
-
value 配置项:给属性指定值
-
writable 配置项:设置该属性的值是否可以被修改.true表示可以修改,false表不能修改
-
getter方法 配置项:不需要我们手动调用的。当读取属性值的时候,getter方法被自动调用。
-
该方法返回值非常重要,这个返回值就是代表这个属性的值
-
setter方法 配置项:不需要我们手动调用的。当修改属性值的时候,setter方法被自动调用。
-
setter方法上是有一个参数的,这个参数可以接收传过来的值。
-
注意:当配置项当中有setter和getter的时候,value和writable配置项都不能存在。
-
2.什么是数据代理机制?
- 通过访问 代理对象的属性 来间接访问 目标对象的属性
- 数据代理机制的实现需要依靠: Object.defineProperty()方法。
- ES6新特性:
- 在对象中的函数/方法 :function 是可以省略的。
<script>
// 目标对象
let target ={
name:`张三`
}
// 代理对象
let proxy = {}
// 如果要实现数据代理机制的话,就需要给proxy新增一个name属性。
// 注意:代理对象新增的这个属性的名字 和 目标对象的属性名要一致。
Object.defineProperty(proxy,`name`,{
get(){
// 间接访问目标对象的属性
return target.name
},
set(val){
target.name = val;
}
})
</script>
3. Vue2数据代理中关键性代码解读
<!-- 容器 -->
<div id="app">
<h1>姓名:{{name}}</h1>
<h1>年龄:{{age}}岁</h1>
</div>
<!-- vue代码 -->
<script>
function isReserved(str) {
var c = (str + '').charCodeAt(0);
return c === 0x24 || c === 0x5f;
}
const vm = new Vue({
el : '#app',
data : {
name : 'jackson',
age : 35
}
})
// 如果我们程序员不想走代理的方式读取data,想直接读取data当中的数据,可以通过_data和$data属性来访问。
// 建议使用$data这个属性。
console.log('name = ' + vm.$data.name)
console.log('age = ' + vm.$data.age)
</script>
var data = vm.$options.data;- 注意:这是获取data。程序执行到这里是vm还没有创建_data属性
data = vm._data = isFunction(data) ? getData(data, vm) : data || {};- 程序执行完这段代码之后,vm对象上多冷一个_data这样的属性
- 通过以上源码解读,可以得知data不一定是一个{},也可以是一个函数
- 代码含义:
- 如果data是一个函数,则调用getData(data,vm)来获取data
- 如果data不是一个函数,则将data返回,给data变量,并将data赋值给vm._data属性了;
- 小疑问?
- 程序执行到这里,为什么要给vm扩展一个_data属性呢?
- data属性,以"_"开始,足以说明,这个属性是人家Vue框架底层需要访问的。
- Vue框架底层它使用vm._data这个属性干啥呢?
- vm._data是啥?
- vm._data 是:{ name : 'jackson', age : 35 }
- vm._data 这个属性直接指向了底层真实的data对象。通过_data访问的name和age是不会走数据代理机制的。
- 通过vm._data方式获取name和age的时候,是不会走getter和setter方法的。
- 注意: 对于vue实例vm来说,不仅有data这个属性,还有一个$data属性
- _data是vue内部使用的,可以看做私有的
- $data是vue对外公开的一个属性,是给我程序员使用的
- 程序执行到这里,为什么要给vm扩展一个_data属性呢?
- 重点函数:
function isReserved(str) { var c = (str + '').charCodeAt(0); return c === 0x24 || c === 0x5f; }
- 该函数是用来判断字符串是否以_和$开头
- true表示以_或$开头
- false表示不是以_或$开头
proxy(vm, "_data", key);
- 通过该代码直接进入代理机制(数据代理)
- 重点函数:proxy
function proxy(target, sourceKey, key) { // target是vm,sourceKey是"_data",key是"age"
sharedPropertyDefinition.get = function proxyGetter() {
return this["_data"]["age"];
};
sharedPropertyDefinition.set = function proxySetter(val) {
this["_data"]["age"] = val;
};
Object.defineProperty(vm, 'age', sharedPropertyDefinition);
}
4.data可以是一个函数
data functions should return an object:data函数应该返回一个对象。- data 也可以是一个函数。
- 如果是函数的话,必须使用return语句返回{}对象。
data(){
// 在对象当中,函数的 :function 可以省略
return {
msg : 'Hello Zhangsan!'
}
}
6.Vue的事件处理
1.指令的语法格式:
- <标签 v-指令名:参数名="表达式">{{插值语法}}</标签>
- "表达式都可以写什么?
- 常量、js表达式、Vue实列管理的对象
2.在Vue当中完成事件绑定需要哪个指令?
- v-on指令
- 语法格式:
- v-on:事件名="表达式
- 列如:
- v-on:click="表达式" 表示当发生鼠标单击事件之后,执行表达式。
- v-on:keydown="表达式" 表示当发生键盘按下事件之后,执行表达式。
3. 在vue中,所有时间关联的回调函数,都要在vue实例的配置项methods中进行
- methods是一个对象:{}
- 在这个methods对象中可以定义多个回调函数
4. v-on指令的简写形式
- v-on:click 简写 @click
- v-on:kedown 简写 @kdydown
- v-on:mouseover 简写 @mouseover
- 绑定的回调函数,如果函数调用时不需要传递任何参数,小括号()可以省略。
- Vue在调用回调函数的时候,会自动给回调函数传递一个对象,这个对象是:当前发生的事件对象。
- 在绑定回调函数的时候,可以在回调函数的参数上使用 event 占位符之后,会自动将当前事件以对象的形式传过去。
<!-- 容器 -->
<div id="app">
<h1>{{msg}}</h1>
<!-- 使用javascript原生代码如何完成事件绑定。 -->
<button onclick="alert('hello')">hello</button>
<!-- 使用Vue来完成事件绑定 -->
<!-- 以下是错误的,因为alert()并没有被Vue实例管理。 -->
<!-- <button v-on:click="alert('hello')">hello</button> -->
<!-- 以下是错误的,因为sayHello()并没有被Vue实例管理。 -->
<!-- <button v-on:click="sayHello()">hello</button> -->
<!-- 正确的写法 -->
<button v-on:click="sayHello()">hello</button>
<!-- v-on指令的简写形式 -->
<button @click="sayHi()">hi button</button>
<button @click="sayHi($event, 'jack')">hi button2</button>
<!-- 绑定的回调函数,如果不需要传任何参数,小括号() 可以省略 -->
<button @click="sayWhat">what button</button>
</div>
7.事件修饰符
1.vue中提供的事件修饰符
- stop: 停止事件冒泡 等同于 event.stopPropagation()
- prevent: 阻止默认行为 等同于 event.preventDefault()
- capture: 添加事件监听器时使用事件捕获模式:
- 添加事件监听器两种方式:
- 从内岛外添加 (事件冒泡)
- 从外到内添加 (事件捕获)
- 添加事件监听器两种方式:
- self: 该事件只执行自己发生的事件,别传递给我的事件则不执行
- once: 事件只执行一次
- passive: 立即执行事件的默认行为
- .passive 和 .prevent 修饰符是对立的。不可以共存。(如果一起用,就会报错。)
- .prevent:阻止事件的默认行为。
- .passive:解除阻止。
<!-- 在Vue当中,事件修饰符是可以多个联合使用的。
但是需要注意:
@click.self.stop:先.self,再.stop
@click.stop.self:先.stop,再.self
-->
<div @click="san">
<div @click="er">
<button @click.self.stop="yi">self修饰符</button>
</div>
</div>
8.按键修饰符
1. 9个常用的按键修饰符
- .enter
- .table (必须配合keydown事件使用。)
- .dalete (捕获“删除”和“退格”键)
- .esc
- .space
- .up
- .down
- .left
- .right
2. 怎么获取某个键的按键修饰符?
- 通过
event.key获取该键的真实名字 - 将这个真实名字以
kebab-case风格进行命名
3. 按键修饰符怎么自定义?
- 通过vue的全局配置对象config来进行按键修饰符的自定义
- 语法规则:
Vue.config.keyCodes.按键修饰符的名字 = 键值
4. 系统修饰符: 4个比较特殊的键
- ctrl 、alt、shift、meta(win键)
- 对于keydown:只要按下ctrl键,keydown事件就会触发
- 对于keyup:需要按下ctrl键,并且加上按下组合键,然后松开组合键之后,keyup事件才能触发。
9.计算属性(computed)
1.什么是计算属性
- 使用vue原有的属性,经过一系列的运算/计算,最终得到了一个全新的属性,叫做计算属性
- vue的原有属性:data对象中的属性可以叫做vue的原有属性
- 全新的属性:表示生成了一个新的属性,和data的属性无关了,新的属性也有自己的属性名和属性值
2.计算属性怎么用?
- 语法格式:需要一个新的配置项
computed
computed : {
// 这是一个计算属性
计算属性1 : {
// setter 和 getter方法。
// 当读取计算属性1的值的时候,getter方法被自动调用。
get(){
},
// 当修改计算属性1的值的时候,setter方法被自动调用。
set(val){
}
},
// 这是另一个计算属性
计算属性2 : {},
}
3.计算属性作用?
- 代码得到了复用
- 代码便于维护
- 代码执行效率提高
4.注意:
- 计算属性里面的值是属于对象的key,所以调用的时候不能加(),否则会报错
{{key}}
10.侦听属性(watch)
1.watch 关键字
- 侦听属性的变化其实就是监视某个属性的变化。当被监视的属性一旦发生改变时,执行某段代码。
- 监视属性变化时需要使用 watch 配置项
// 可以监视多个属性
// 监视哪个属性,请把这个属性的名字拿过来即可。
// 可以监视Vue的原有属性
/* number : {
// 初始化的时候,调用一次handler方法。
immediate : true,
// 这里有一个固定写死的方法,方法名必须叫做:handler
// handler方法什么时候被调用呢?当被监视的属性发生变化的时候,handler就会自动调用一次。
// handler方法上有两个参数:第一个参数newValue,第二个参数是oldValue
// newValue是属性值改变之后的新值。
// oldValue是属性值改变之前的旧值。
handler(newValue, oldValue){
console.log(newValue, oldValue)
// this是当前的Vue实例。
// 如果该函数是箭头函数,这个this是window对象。不建议使用箭头函数。
console.log(this)
}
}, */
// 无法监视b属性,因为b属性压根不存在。
/* b : {
handler(newValue, oldValue){
console.log('@')
}
} */
// 如果监视的属性具有多级结构,一定要添加单引号:'a.b'
/* 'a.b' : {
handler(newValue, oldValue){
console.log('@')
}
},
'a.c' : {
handler(newValue, oldValue){
console.log('@')
}
}, */
a : {
// 启用深度监视,默认是不开启深度监视的。
// 什么时候开启深度监视:当你需要监视一个具有多级结构的属性,并且监视所有的属性,需要启用深度监视。
deep : true,
handler(newValue, oldValue){
console.log('@')
}
},
// 注意:监视某个属性的时候,也有简写形式,什么时候启用简写形式?
// 当只有handler回调函数的时候,可以使用简写形式。
number(newValue, oldValue){
console.log(newValue, oldValue)
}
// 也可以监视计算属性
/* hehe : {
handler(a , b){
console.log(a, b)
}
} */
}
})
2.后期监视
- 调用API: vm.$watch('属性名',{})
// 如何后期添加监视?调用Vue相关的API即可。
// 语法:vm.$watch('被监视的属性名', {})
/* vm.$watch('number2', {
immediate : true,
deep : true,
handler(newValue, oldValue){
console.log(newValue, oldValue)
}
}) */
// 这是后期添加监视的简写形式。
vm.$watch('number2', function(newValue, oldValue){
console.log(newValue, oldValue)
})
3. computed和watch怎么选择?
- computed和watch如果都能够完成某个功能时,优先选择computed
- 有一种情况下,必须使用watch,computed无法完成
- 如果在该程序中使用了异步的方式时,则使用watch
4.什么时候使用箭头函数?什么时候使用普通函数?
- 如果这个函数属于vue管理的,则统一使用普通函数
- 如果这个函数不是属于vue管理的,则统一写箭头函数
<script>
const vm = new Vue({
el : '#app',
data : {
msg : '比较大小的案例',
num1 : 0,
num2 : 0
},
computed : {
// 计算属性的简写形式
compareResult(){
let result = this.num1 - this.num2
// 这里采用了异步方式,这里的箭头函数是javascript引擎去调用。所以最终return的时候,也会将值返回给javascript引擎。
setTimeout(() => {
if(result == 0){
return this.num1 + ' = ' + this.num2
}else if(result > 0){
return this.num1 + ' > ' + this.num2
}else {
return this.num1 + ' < ' + this.num2
}
}, 1000 * 3)
}
}
})
</script>
11.class动态绑定和style动态绑定
1. 动态绑定---字符串绑定
- 适用场景: 如果确定动态绑定的样式个数只有一个但名字不确定
2. 动态绑定---数组绑定
- 适用场景:当样式的个数不确定,并且样式的名字也不确定,使用动态绑定
3. 态绑定---对象
- 适用场景:样式的个数是固定的,样式的名字也是固定的,但是需要动态的决定样式用还是不用。
<style>
.static {
border: 1px solid black;
width: 100px;
height: 100px;
}
.active {
background-color: green;
}
.text-danger {
color: red;
}
</style>
<!-- 字符串绑定 -->
<div class="static" :class="c1">{{msg}}</div>
<!-- 数组绑定 -->
<div class="static" :class="classArray">{{msg}}</div>
<!-- 对象绑定 -->
<div class="static" :class="{active:true,'text-danger':false}">{{msg}}</div>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
msg : 'Class绑定之字符串形式',
c1 : 'small',
classArray : ['active', 'text-danger'],
classObj : {
// 该对象中属性的名字必须和样式名一致。
active : false,
'text-danger' : true
}
},
methods: {
changeBig(){
this.c1 = 'big'
}
})
</script>
4.style动态
.static {
border: 1px solid black;
width: 100px;
height: 100px;
}
<!-- 静态写法 -->
<div class="static" style="background-color: green;">{{msg}}</div>
<!-- 动态写法:字符串形式 -->
<div class="static" :style="myStyle">{{msg}}</div>
<!-- 动态写法:对象形式 -->
<div class="static" :style="{backgroundColor: 'gray'}">{{msg}}</div>
<div class="static" :style="styleObj1">{{msg}}</div>
<!-- 动态写法:数组形式 -->
<div class="static" :style="styleArray">{{msg}}</div>
const vm = new Vue({
el : '#app',
data : {
msg : 'Style绑定',
myStyle : 'background-color: gray;',
styleObj1 : {
backgroundColor: 'green'
},
styleArray : [
{backgroundColor: 'green'},
{color : 'red'}
]
}
})
12. 条件渲染 v-if和v-show
1. v-if指令的值: true/false
- true 表示该元素会被渲染到页面中
- false 表示该元素不会被渲染到页面上 (注意:不是修改了CSS样式,是这个元素压根没有加载)
- 其他的值: v-else-if 和 v-else
- 注意:v-if v-else-if v-else三者在使用的时候,中间不能断开。
温度:<input type="number" v-model="temprature">
<!-- 天气:<span v-if="temprature <= 10">寒冷</span>
<span v-if="temprature > 10 && temprature <= 25">凉爽</span>
<span v-if="temprature > 25">炎热</span> -->
天气:<span v-if="temprature <= 10">寒冷</span>
<span v-else-if="temprature <= 25">凉爽</span>
<span v-else>炎热</span>
2. v-show指令
- v-show指令是通过修改元素的CSS样式的display属性来达到显示和隐藏的。
3. v-if和v-show应该如何选择?
- 1.如果一个元素在页面上被频繁的隐藏和显示,建议使用v-show,因为此时使用v-if开销比较大。
-
- v-if的优点:页面加载速度快,提高了页面的渲染效率。
4. template标签
- template标签在页面中起到站位的作用,不会真正的渲染到页面中,也不会影响页面的结果
<template v-if="counter === 10">
<input type="text">
<input type="checkbox">
<input type="radio">
</template>
13.列表渲染 v-for
1.语法格式 :
- v-for指令。该指令用在被遍历的标签上。
- v-for的语法规则:
- v-for="(变量名,index) in/of 数组"
- 变量名 代表了 数组中的每一个元素
<ul>
<li v-for="(vip,index) of vips">
会员名:{{vip.name}},年龄:{{vip.age}}岁
</li>
</ul>
const vm = new Vue({
el : '#app',
data : {
vips : [
{id:'111',name:'jack',age:20},
{id:'222',name:'lucy',age:30},
{id:'333',name:'james',age:40}
]
})
14. 虚拟DOM和diff算法
1. :key
- v-for指令中所在的标签中,
:key是一个非常重要的属性 - 如果没有指定
:key属性,会自动拿index作为key - 这个key是DOM元素的身份证号/唯一标识.
2.分析问题:采用index作为:key存在什么问题?
1.效率低 2.产生数组混乱
3.怎么解决该问题
- 建议使用对象的id作为key
<tr v-for="(hero,index) in heros" :key="hero.id">
<td>{{index+1}}</td>
<td>{{hero.name}}</td>
<td>{{hero.power}}</td>
<td><input type="checkbox"></td>
</tr>
heros : [
{id:'101',name:'艾格文',power:10000},
{id:'102',name:'麦迪文',power:9000},
{id:'103',name:'古尔丹',power:8000},
{id:'104',name:'萨尔',power:6000}
]
4.(重点)虚拟DOM
- 虚拟 dom 就是内存当中的 dom 对象。vue 为了提高渲染的效率,只有真正改变的 dom 元素才会重新渲染。
15. Vue的其他指令
1. v-text
- 等同于原生js的innerText
- 将内容填充到标签体当中,并且是以覆盖的形式填充,而且填充的内容中即使存在 HTML 标签也只是会当 做一个普通的字符串处理,不会解析。
2. v-html
- 等同于原生js的innerHTML
- v-html不能用到用户提交的内容上.否则可能会导致XSS攻击
3. v-clock
- v-clock配置css样式来解决胡子的闪现问题
- v-clock指令使用在标签中,当Vue实例接管后会删除这个指令
- 这是一段 CSS 样式:当前页面中所有带有 v-cloak 属性的标签都隐藏起来
[v-cloak] { display : none;}
4.v-pre
-使用该指令可以提高编译速度。带有该指令的标签将不会被编译。可以在没有 Vue 语法规则的标签中使用 可以提高效率。不要将它用在带有指令语法以及插值语法的标签中。
16. 自定义指令
1. 自定义指令的两种方式
- 函数式
- 函数调用时机:
- 第一时机: 模板初次解析时(元素与指令初次绑定)
- 第二时机:模板重新解析时
- 关于指令的名字:
- 1.v- 不需要写
-
- Vue官方建议指令的名字全部小写
- 函数式的回调函数有两个参数:
- 第一个参数是真实DOM元素
- 第二个参数是标签与指令之间绑定关系的对象
- 函数调用时机:
directives : { ‘text-reverse’ : function(element, binding){
// ‘text-reverse’ 是自定义指令名(指令名可以自定义)
// 对于自定义指令来说.函数体当中的this是window,而不是vue实例
// element 是真实 dom 对象(可以通过 element instanceof HTMLElement 判断)
// binding 是绑定的对象
element.innerText = binding.value.split(‘’).reverse().join(‘’) } }
- 对象式:可以使用对象式完成更加细致的功能
bindinsetreedupdate这三个方法的名字不能随便写- 这三个函数会被自动调用
- 元素与指令初次绑定的时候,自动调用bind
- 元素被插入到页面之后,自动调用inserted
- 当模板重新解析的时候,自动调用update
directives : { ‘bind-parent’ : {
// 元素与指令初次绑定时自动调用。
bind(element, binding){},
// 元素已经被插入页面后自动调用。
inserted(element, binding){},
// 模板重新解析时被自动调用。
update(element, binding){} }
}
2.自定义指令的函数中的this是window
3.全局指定自定义
- 对象式
Vue.directive(‘bind-parent’, {
bind(element, binding){}
inserted(element, binding){},
update(element, binding){} })
- 函数式
Vue.directive(‘text-reverse’, function(element, binding){})
17. 响应式与数据劫持
1. 什么响应式?
- 修改 data 后,页面自动改变/刷新。这就是响应式。就像我们在使用 excel 的时候,修改一个单元格中的数据, 其它单元格的数据会联动更新,这也是响应式。
2.Vue 的响应式是如何实现的?
- 数据劫持:Vue 底层使用了
Object.defineProperty,配置了setter方法 - 当去修改属性值时
setter方法则被自动调用 setter方法中不仅修改了属性值,而且还做了其他的事情.- 例如:重新渲染页面。
setter方法就像半路劫持一样,所以称为数据劫持
3.Vue 会给 data 中所有的属性,以及属性中的属性,都会添加响应式
4.后期添加的属性,不会有响应式,怎么处理?
- Vue.set(目标对象,'属性名',值)
- vm.$set(目标对象,'属性名',值)
Vue.set(vm.a, 'email', 'jack@123.com')
vm.$set(vm.a, 'email', 'jack@456.com')
5. Vue2中通过数组下标去修改数组中的元素,默认是没有添加响应式处理的,怎么解决?
- 第一种方案:
- vm.$set(数组对象, 下标, 值)
- Vue.set(数组对象, 下标, 值)
- 第二种方案:
- 通过以下七个方法来给数组添加响应式处理
push()
pop()
reverse()
splice()
shift()
unshift()
sort()
17.Vue的生命周期(重点)
1.什么是生命周期
- vm对象从创建到最终销毁的整个过程
- 虚拟 DOM 在内存中就绪时:去调用一个 a 函数
- 虚拟 DOM 转换成真实 DOM 渲染到页面时:去调用一个b函数
- Vue 的 data 发生改变时:去调用一个 c 函数
- ...
- Vue 实例被销毁时:去调用一个 x 函数
- 该函数在某个时间点自动执行,称为
钩子函数
2.Vue生命周期的4个阶段8个钩子
- Vue 的生命周期可以被划分为 4 个阶段:初始阶段、挂载阶段、更新阶段、销毁阶段。
- 初始阶段
beforeCereate()创建前created()创建后
- 挂载阶段
beforeMount()挂载前Mount()挂在后
- 更新阶段
beforUpdate()更新前updated()更新后
- 销毁阶段
beforeDestroy()销毁后destroyed()销毁后
3.初始阶段做了什么?
- 创建Vue实例vm(此时Vue实例已经完成了创建,这是生命的起点)
- 初始化事件对象和生命周期(接产大夫正给他洗澡)
- 调用
beforeCreate()钩子函数(此时还无法通过vm去访问打他对象的属性) - 初始化数据代理和数据监测
- 调用
created()钩子函数(此时数据代理和数据监测创建完毕,已经可以通过 vm 访问 data对象的属性) - 编译模板语句生成虚拟 DOM(此时虚拟 DOM 已经生成,但页面上还没有渲染)
- 该阶段适合做什么?
- beforeCreate:可以在此时加一些 loading
- created:结束 loading 效果。也可以在此时发送一些网络请求,获取数据。也可以在这里添加定时器
4.挂载阶段做了什么?
- 调用
beforeMount()钩子函数(此时页面还未渲染,真实 DOM 还未生成) - 给 vm 追加el 代表了真实的 DOM 元素(此时真实 DOM 生成,页面渲染完 成)
- 调用
mounted()钩子函数
- 该阶段适合做什么?
- mounted:可以操作页面的 DOM 元素了
5.更新阶段做了什么?
- data 发生变化(这是该阶段开始的标志)
- 调用
beforeUpdate()钩子函数(此时只是内存中的数据发生变化,页面还未更新) - 虚拟 DOM 重新渲染和修补
- 调用
updated()钩子函数(此时页面已更新)
6. 销毁阶段做了什么?
vm.$destroy()方法被调用(这是该阶段开始的标志)- 调用
beforeDestroy()钩子函数(此时Vue实例还在。虽然vm上的监视器、vm 上的子组件、vm上的自定义事件监听器还在,但是它们都已经不能用了。此时修改 data 也不会重新渲染页面了) - 卸载子组件和监视器、解绑自定义事件监听器
- 调用
destroyed()钩子函数(虽然destroyed翻译为已销毁,但此时 Vue 实例还在,空间并没有释放,只不过马上要释放了,这里的已销毁指的是 vm 对象上所有的东西都已经解绑完成了)
- 该阶段适合做什么?
- beforeDestroy:适合做销毁前的准备工作,和人临终前写遗嘱类似。
- 例如:可以在这里清除定时器