1.Vue中的基础技术

228 阅读16分钟

1. 插值语法 {{}} 可以写什么???

  1. 在data中声明的变量,函数等都可以
  2. 常量
  3. 合法的JavaScript表达式
  4. 模板表达式都被放置盒中,只能访问全局变量的一个白名单,如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
  1. 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 指令(重点)

  1. 该指令的作用?

    • 该指令可以让html的标签的某个属性的值产生动态的效果
  2. 语法格式 - <html 标签 v-bind:参数="表达式"></html>

  3. v-bind指令的编译原理?

    • 编译前: - <HTML标签 v-bind:参数="表达式"></HTML标签>
      • 编译后:
        • <HTML标签 参数="表达式的执行结果"></HTML标签>
      • 注意两点:
        • 在编译的时候v-bind后面的"参数名"会被编译为HTML的属性名
        • 表达式会关联data,当data发生改变后,表达式的执行结果会发生变化
      • 所有:连带的就会产生动态的效果
    1. v-bind的简写方式:
      • <img :src = "IMSI">
    2. 什么时候用插值语法,什么时候用指令?
      • 当标签体中的内容需要动态设置时,使用插值语法
      • 当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的区别和联系

  1. v-bind 和v-model 都可以完成数据绑定
  2. v-bind是单向数据绑定
    • 数据(data) ==> 视图(view)
  3. v-model是双向数据绑定
    • 数据(data) <===> 视图(view)
  4. v-bind可以使用在任何html元素中,v-model只能使用在表单类元素上,列如:
    • input标签,select标签,textare标签
    • 为什么v-model会有这个限制???
      • 因为表单类的元素才能给用户提供交互输入的界面 - v-modl指令通常也是写在value属性上
    1. 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)
  1. MVVM中倡导来Model和View进行分离,为什么要分离?

    • 如果View和Model不分离,使用最原始的js代码写项目
      • 如果数据发生任意的改动,那么就需要大量操作DOM元素的js代码
    • 也就是说,当Model发生改变之后,VM自动去更新View,当View改变之后
    • Vm会自动更新Model.
<!--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对})
  • 第三个参数的配置项有哪些?以及他们的作用?
    • 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>
  1. var data = vm.$options.data;
    • 注意:这是获取data。程序执行到这里是vm还没有创建_data属性
  2. 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对外公开的一个属性,是给我程序员使用的
  3. 重点函数:
    • function isReserved(str) { var c = (str + '').charCodeAt(0); return c === 0x24 || c === 0x5f; }
  • 该函数是用来判断字符串是否以_和$开头
    • true表示以_或$开头
    • false表示不是以_或$开头
  1. proxy(vm, "_data", key);
  • 通过该代码直接进入代理机制(数据代理)
  1. 重点函数: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
  1. 绑定的回调函数,如果函数调用时不需要传递任何参数,小括号()可以省略。
  2. Vue在调用回调函数的时候,会自动给回调函数传递一个对象,这个对象是:当前发生的事件对象。
  3. 在绑定回调函数的时候,可以在回调函数的参数上使用 event占位符,Vue框架看到这个event 占位符,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. 怎么获取某个键的按键修饰符?

  1. 通过event.key获取该键的真实名字
  2. 将这个真实名字以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怎么选择?

  1. computed和watch如果都能够完成某个功能时,优先选择computed
  2. 有一种情况下,必须使用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开销比较大。
    1. 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 元素才会重新渲染。

image.png

image.png

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- 不需要写
        1. 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(‘’) } }

  • 对象式:可以使用对象式完成更加细致的功能
    • bind insetreed update这三个方法的名字不能随便写
    • 这三个函数会被自动调用
    • 元素与指令初次绑定的时候,自动调用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对象从创建到最终销毁的整个过程
    1. 虚拟 DOM 在内存中就绪时:去调用一个 a 函数
    2. 虚拟 DOM 转换成真实 DOM 渲染到页面时:去调用一个b函数
    3. Vue 的 data 发生改变时:去调用一个 c 函数
    4. ...
    5. Vue 实例被销毁时:去调用一个 x 函数
  • 该函数在某个时间点自动执行,称为钩子函数

2.Vue生命周期的4个阶段8个钩子

  • Vue 的生命周期可以被划分为 4 个阶段:初始阶段、挂载阶段、更新阶段、销毁阶段。
  1. 初始阶段
    • beforeCereate()创建前
    • created() 创建后
  2. 挂载阶段
    • beforeMount() 挂载前
    • Mount() 挂在后
  3. 更新阶段
    • beforUpdate() 更新前
    • updated() 更新后
  4. 销毁阶段
    • beforeDestroy() 销毁后
    • destroyed() 销毁后

3.初始阶段做了什么?

  1. 创建Vue实例vm(此时Vue实例已经完成了创建,这是生命的起点)
  2. 初始化事件对象和生命周期(接产大夫正给他洗澡)
  3. 调用beforeCreate()钩子函数(此时还无法通过vm去访问打他对象的属性)
  4. 初始化数据代理和数据监测
  5. 调用 created()钩子函数(此时数据代理和数据监测创建完毕,已经可以通过 vm 访问 data对象的属性)
  6. 编译模板语句生成虚拟 DOM(此时虚拟 DOM 已经生成,但页面上还没有渲染)
  • 该阶段适合做什么?
    • beforeCreate:可以在此时加一些 loading
    • created:结束 loading 效果。也可以在此时发送一些网络请求,获取数据。也可以在这里添加定时器

4.挂载阶段做了什么?

  1. 调用 beforeMount()钩子函数(此时页面还未渲染,真实 DOM 还未生成)
  2. 给 vm 追加el属性,用它来代替”el”,el 属性,用它来代替”el”,el 代表了真实的 DOM 元素(此时真实 DOM 生成,页面渲染完 成)
  3. 调用 mounted()钩子函数
  • 该阶段适合做什么?
    • mounted:可以操作页面的 DOM 元素了

5.更新阶段做了什么?

  1. data 发生变化(这是该阶段开始的标志)
  2. 调用 beforeUpdate()钩子函数(此时只是内存中的数据发生变化,页面还未更新)
  3. 虚拟 DOM 重新渲染和修补
  4. 调用 updated()钩子函数(此时页面已更新)

6. 销毁阶段做了什么?

  1. vm.$destroy()方法被调用(这是该阶段开始的标志)
  2. 调用 beforeDestroy()钩子函数(此时Vue实例还在。虽然vm上的监视器、vm 上的子组件、vm上的自定义事件监听器还在,但是它们都已经不能用了。此时修改 data 也不会重新渲染页面了)
  3. 卸载子组件和监视器、解绑自定义事件监听器
  4. 调用 destroyed()钩子函数(虽然 destroyed 翻译为已销毁,但此时 Vue 实例还在,空间并没有释放,只不过马上要释放了,这里的已销毁指的是 vm 对象上所有的东西都已经解绑完成了)
  • 该阶段适合做什么?
    • beforeDestroy:适合做销毁前的准备工作,和人临终前写遗嘱类似。
    • 例如:可以在这里清除定时器