[笔记]尚硅谷Vue2.0+Vue3.0笔记前面部分

143 阅读5分钟

笔记的后面部分转用notion来记录了,时间关系写得都比较简易,就不发在这里了。

vid4-6 hello world案例


<body>
    <!-- 容器里的代码被称为vue模版 -->
    <!-- 流程 -->
    <!--  Vue实例开始工作时, 去找el中对应的容器,然后开始进行解析,扫描模版内是否有vue的特殊语法-->
    <!-- 例如发现要用name,会用name中的内容替换{{name}}, 然后生成一个全新div,再把解析完的div重新放到容器里-->
    <!-- 所有容器的作用有两个: (1)为vue提供模版,(2)把vue的工作成果提供可放置的容器 -->
    <div id="root">
        <!-- 插值语法 , 与解构对象什么的无关 -->
        <h1>hello, {{name}}</h1>
    </div>
</body>
<script>
    Vue.config.productionTip = false

    // const vm定义不需要。直接去掉即可
    const vm = new Vue({ // 构造函数参数只有一个,也就是配置对象
        el: '#root', // 用于指定当前Vue实例为哪个容器服务。这里用document.getElement.byId()也ok
        data: { // 存储供指定容器使用的data
            name: 'Alex'
        }
    })
</script>

vid7/8 模板语法 数据绑定

两大类:

  • 插值语法(用于标签体内)
  • 指令语法(用于标签属性) 例如: v-bind(可以简写为:)、v-model(双向数据绑定)

vid9 el与data的两种写法

   const v = new Vue({
        // el: "#root",
        // data: {
        //     name: 'Alex'
        // }
        data() { // 组件data必须用函数式
            console.log(this) // Vue实例对象
            return {
                name: 'Alex'
            }
        }
    })

    v.$mount("#root")

image.png data最终会出现于Vue实例对象上。Vue实例对象及其原型上的属性都可以在模版中获取。

image.png

10 MVVM模型

M: 对应data中的数据 V: view VM: view modal, Vue实例对象

VM可以理解为是V和M之间的桥梁 image.png

11 数据代理

Object.defineProperty()

用该方法定义属性时与字面量定义的主要区别是: (1)前者定义的属性默认情况下是无法被枚举的,在console中输出可以看到,hobby属性和其他属性颜色是不同的。 image.png

    // 以下结果中均没有hobby属性
    console.log(Object.keys(myFriend))
    for (key in myFriend) {
        console.log(myFriend[key])
    }

如果要想被枚举,可以在配置对象中加上enumerable: true

    Object.defineProperty(myFriend, 'hobby', {
        value: 'archery',
        enumerable: true
    })

(2)前者默认情况下无法通过xx.xx的方法去修改属性,可以配置writable:true来允许修改

(3) 前者默认情况下无法通过delete xx.xx方法删除,可配置configurale:true (4)

  let age = 11
  let p = {
      name: 'alex',
      age: age
  }
  age = 13
  console.log(p.age) //11 ,因为p的定义语句只会执行一次,所以只会取到一开始11的值。

而如果使用Object.defineProperty()的话,我们可以用get来设定每次读取属性值时都会值进行更新 image.png 还可以去set来进行p.age = xx的修改绑定

    let num = 15
    let p = {
        name: 'alex'
    }

    Object.defineProperty(p, 'age', {
        get: function() {
            return num
        },
        set(value) {
            num = 13
            console.log(p)
        }
    })

    console.log(p)

用defineProperty实现简单的数据代理

数据代理定义: 通过一个对象代理对另一个对象中属性的操作(读写)

    let p1 = {
        name: 'alex',
        age: 5
    }
    let p2 = {
        name: 'louie'
    }

    Object.defineProperty(p2, 'age', {
        get() {
            return p1.age
        },
        set(value) {
            p1.age = value
        }
    })

vue中的数据代理

在下面的例子中,打印出vm,它的两个data是...状态,鼠标放上去会出现invoke property getter,所以它本质上调用的就是 Object.defineProperty中的get。

image.png

如果再往下看,会发现有这两个数据的getter和setter

image.png

所以vm和我们写的data构成了一个数据代理。当我们获取vm中的hobby时,其实调用了getter来获取data中的hobby。它的基本原理就是:通过Object.defineProperty把data中的属性都添加到vm上,并且都指定getter、setter。

如果我们让vm.hobby ='xx', 会发现页面上的hobby已变化。

data实际上是存储在vm.__data中的,两个是全等的。那为什么不直接到__data中获取数据,而是用进行数据代理呢?

这是因为我们插值表达式中要写vm的属性名,如果从___data中获取数值,我们需要写{{__data.name}}。所以数据代理的好处就是操作data数据更方便。

事件修饰符

  • prevent
  • stop
  • once: 事件只触发一次
  • capture: 在捕获模式处理事件
  • self:只有event.target是当前操作的元素时才触发事件。 例如:
<div class="container" @click.self="containerSayHello">
   <button @click="buttonSayHello">click me</button>
</div>

在上面情况下,只有点击的是container(不含button),才会触发containerSayHello事件。self实际上也能起到阻止冒泡的作用。

  • passive:事件的默认行为立即执行,无需等待cb执行完毕(用很少,这里暂时先跳过)。

12. v-for

  • vue内部会用key来标识每个v-for生成的内容,在浏览器中标签上是看不到key这个属性置的。
  • 当不写key时,如果每个item内部还有输入框的话,在最上方新增一个item会出现错位的情况。但这时即使用index,也还是会错位,用唯一标识(例如id)则不会出现这个问题。

image.png

key 的工作原理

  1. vue根据初始数据生成虚拟dom,这些虚拟dom是在内存中的,页面上什么也没有。

image.png

  1. 把虚拟dom转化为真实dom,然后渲染到页面上。当用户在input中输入数据时,数据是残留在真实dom中。

  2. 此时数组第一项新增数据后,vue根据新数据生成一个新的虚拟dom。此时第一项的key是0。 image.png

  3. 此时vue要用到虚拟dom的对比算法

在对比时,它会根据key去对比,新增的第一项key是0,所以它会与左边第一项key是0 的项进行对比。 它会先去分析:第一项有两个节点,一个是文本节点,一个是input标签节点。一一对比之后,发现只有第一个文本节点有不同

image.png

  1. 此时vue开始将第一项转化真实dom,但因为第一项中只有第一个文本节点有不同,input没有不同,所以input会被重复利用。但之前用户输入的文字还残留在里面。

对比第二项时,会在左右两边去找id为1的项目,两边input没变,但是文本节点已经不同了,所以文本节点部分也会被重新生成为真实dom,而input则重复利用...一直到最后一项,因为左边已经没有id为3的项目,所以只能直接生成真实dom。

可以看出,在这个过程中,除了错位外,之前已经生成过的一些文本节点也不会被再次利用,所以效率比较低。

总结:

  • key是虚拟dom对象的标识,当数据发生变化的时,会根据新数据生成新虚拟dom,而会根据key来将新旧讯息dom进行比较。

比较过程中如果找到了key相同的项目,则会更新其中不同的部分,如果没有找到,则直接生成新的真实dom。

  • 用index作为key可能会引发的问题: 对数据进行破坏顺序的操作时,有可能出现错位等问题,而且效率比较低。

  • 开发中最好用唯一标识作为key,但如果不存在破坏顺序的操作,仅仅用于展示,则用index作为key也可以。