Twlig / issuesBlog

MIT License
3 stars 0 forks source link

Vue基础指令 #30

Open Twlig opened 2 years ago

Twlig commented 2 years ago

Vue会自动通过状态来生成DOM,并渲染在网页上,而网页的DOM变化又会反过来更新Vue的数据状态。

Vue实例

每个Vue应用都是通过Vue函数创建Vue实例

var vm = new Vue({
    el: '#app',
    data() {
        return {
            name: 'zzy',
            age: 22
        }
    },
    computed: {
        year: function(oldV, newV) {
            return oldV + newV
        }
    },
    methods: {
        sayName() {
            console.log(this.name)
        },
        func2() {}
    },
    mounted() {

    },
    components: {
        A,
        B
    }
})

下面是DOM的写法

<div id="app">
  {{ name }}
</div>

基础指令

指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。

Twlig commented 2 years ago

生命周期钩子函数不能使用箭头函数

生命周期钩子的 this 上下文指向调用它的 Vue 实例。

比如:

new Vue({
  data: {
    a: 1
  },
  created: function () {
    // `this` 指向 vm 实例
    console.log('a is: ' + this.a)
  }
})
// => "a is: 1"

不能在选项 property 或回调上使用箭头函数,比如 created: () => console.log(this.a)vm.$watch('a', newValue => this.myMethod())。因为箭头函数的this是指向定义时的上下文对象,而不是调用函数的对象。而我们想要的this往往是当前实例vm,并通过this去访问vm实例上的属性和方法。

举个例子:

window.color = 'red'; 
let o = { 
    color: 'blue' ,
    sayColor: () => console.log(this.color)
}; 
o.sayColor(); // 'red'

可以看到虽然sayColor是定义在对象o上面的,且通过o调用,但是最终this指向的还是window这个上下文。这和此处的Vue实例类似,虽然created箭头函数是创建在Vue实例上的,但是this指向的不是Vue实例。因此,最好不要使用箭头函数以免this指向不明确。

Twlig commented 2 years ago

v-if vs v-show

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

Twlig commented 2 years ago

v-forv-if 一同使用

推荐在同一元素上使用 v-ifv-for

当它们处于同一节点,v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。当只想为部分项渲染节点时,这种优先级的机制会十分有用,如下:

<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo }}
</li>

但是v-for和v-if叠加其实不高效,需要全部渲染然后再判断。完全可以用计算属性替代,先过滤再渲染更加高效。

计算属性过滤

当Vue.js处理指令时,v-forv-if的优先级更高,所以即使只渲染出列表中的一小部分元素,也得在每次重新渲染的时候遍历整个列表,而不考虑过滤元素是否发生变化。

通过将列表更换为在一个计算属性上遍历并过滤掉不需要渲染的元素,会获得以下好处:

<ol>
    <li
        v-for="user in users"
        v-if="user.isActive"
        :key="user.id"
    >
        {{user.name}}
    </li>
</ol>

可以更换为:

computed:{
    activeUsers: function(){
        return this.users.filter(function(user){
            return user.isActive
        })
    }
}

模板更换为:

<ol>
    <li
        v-for="user in activeUsers"
        :key="user.id"
    >
        {{user.name}}
    </li>
</ol>
Twlig commented 2 years ago

key 管理可复用的元素

Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染 。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address">
</template>

那么在上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素,<input> 不会被替换掉——仅仅是替换了它的 placeholder

这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key attribute 即可:

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>

现在,每次切换时,输入框都将被重新渲染。

注意,<label> 元素仍然会被高效地复用,因为它们没有添加 key attribute。

Twlig commented 2 years ago

为列表渲染设置key属性⭐⭐⭐

<div v-for="item in items" :key="item.id">
    {{item.id}}
</div>

虚拟DOM中,当更新子节点时,会查找新旧虚拟节点列表中相同的节点,从而进行更新。

key是给每个虚拟节点的唯一id,依靠key,diff操作会更准确、快速。

比如当前item.id有

var vm = new Vue({
    data() {
        return {
            items: [
                {id: 1},
                {id: 2},
                {id: 3}
            ]
        }
    }
})

那么当前页面就会渲染三个div元素key分别为1,2,3.

当使用unshift在items开头添加一个id为0的对象

vm.items.unshift({id: 0})

可以看到,key属性相当于是DOM节点的唯一标识。就类似于身份证。key不同Vue就会把DOM节点当成不同的节点。如果没有key且元素Tag(类型)相同,如div,text等,Vue就会把他们看成相同的节点去处理。