vue 知识点

155 阅读7分钟

Object.defineProperty

Object.defineProperty()的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性

Object.defineProperty(obj, prop, desc)
  • obj 需要定义属性的当前对象
  • prop 当前需要定义的属性名
  • desc 属性描述符

一般通过为对象的属性赋值的情况下,对象的属性可以修改也可以删除,但是通过Object.defineProperty()定义属性,通过描述符的设置可以进行更精准的控制对象属性。

Object.defineProperty缺点:

  1. 无法监听es6 的Set、Map变化
  2. 无法监听Class类型的数据
  3. 属性的新加或者删除也无法监听
  4. 数组元素的增加和删除也无法监听

属性的新加或者删除无法监听

  1. vue2的解决方案
Vue.set(对象, 属性, true)
  1. vue3支持动态增加属性的拦截

数组元素的增加和删除无法监听

  1. vue2的解决方案,vue2重新写了push
  2. vue3支持动态增加的拦截

v-show和v-if的区别

(1)、v-if和v-show用于视图层进行条件判断视图展示

(2)、v-if的原理是根据判断条件来动态的进行增删DOM元素,v-show是根据判断条件来动态的进行显示和隐藏元素,频繁的进行增删DOM操作会影响页面加载速度和性能,由此我们可以得出结论:

当您的项目程序不是很大的时候,v-if和v-show都可以用来进行判断展示和隐藏(这种场景使用v-if只是影响不大,并不是没有影响);

当您的项目程序比较大的时候,不推荐使用v-if来进行判断展示和隐藏,推荐使用v-show;

(3)、只有v-if能和v-else连用进行分支判断,v-show是不能和v-else连用的,如果出现多种条件场景的情况下,可以使用v-if来进行判断

Vue中的v-if和v-for不建议一起用

vue源码: 源码位置:\vue-dev\src\compiler\codegen\index.js

export function genElement (el: ASTElement, state: CodegenState): string {
  if (el.parent) {
    el.pre = el.pre || el.parent.pre
  }
  if (el.staticRoot && !el.staticProcessed) {
    return genStatic(el, state)
  } else if (el.once && !el.onceProcessed) {
    return genOnce(el, state)
  } else if (el.for && !el.forProcessed) {
    return genFor(el, state)
  } else if (el.if && !el.ifProcessed) {
    return genIf(el, state)
  } else if (el.tag === 'template' && !el.slotTarget && !state.pre) {
    return genChildren(el, state) || 'void 0'
  } else if (el.tag === 'slot') {
    return genSlot(el, state)
  } else {
    // component or element
    ...
}

在进行if判断的时候,v-for是比v-if先进行判断

结论:v-for优先级比v-if高:

  1. 永远不要把 v-if 和 v-for 同时用在同一个元素上,带来性能方面的浪费(每次渲染都会先循环再进行条件判断)
  2. 如果避免出现这种情况,则在外层嵌套template(页面渲染不生成dom节点),在这一层进行v-if判断,然后在内部进行v-for循环

动态 class

<div :class="classObj">动态切换class 对象方法</div>
<div :class="classArr">动态切换class 数组方法</div>
...
data: {
    classObj: {
        aa: true,
        bb: true,
        cc: false,
    }
    classArr: ["aa", "bb"]
}

动态 style

<div :style="styleObj">动态切换class 对象方法</div>
<div :style="styleArr">动态切换class 数组方法</div>
...
data: {
    styleObj: {
        backgrounColor: "red",
        fontSize: "12px"
    }
    classArr: [
        { backgrounColor: "red" },
        { fontSize: "12px" }
    ]
}

Vue3

  1. 初始化写法变了
  2. data写法改了,函数式写法
<div id="box">
    {{10+20}}
</div>

//vue2
new Vue({
    el: "#box",
    data: {
    
    },
    methods: {
    
    }
})

//vue3 初始化
Vue.createApp({
    data() {
        return {
            myname: "abc"
        }
    },
    methods: {
        
    }
}).mount("#box")

v-for中的key

vue渲染过程是,是先生成虚拟DOM,然后再根据虚拟DOM生成真实DOM, 数据更新的时候,不是完全地将整颗Virtual DOM进行渲染,而是去渲染改变的部分, 这时候就需要一个计算Virtual DOM树改变部分的算法了,这个算法就是Diff算法。

Vue为了高效地渲染元素,默认会复用已有元素而不是重新渲染。

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

在上面的代码中,如果没有为input元素设置key,在切换loginType之后,Vue会使用原来的input元素,而其中的内容也不会清空。

为了使切换loginType之后input元素的内容清空,需要为input标签添加key,使切换过后用新的input元素进行渲染且清空内容。

  • diff算法默认执行起来是这样的:

image2020-12-7_17-3-9.png

  • 引入key之后,diff算法:

image2020-12-7_16-42-39.png

跟踪每个节点的身份,从而重用和重新排序现有元素 理想的key值是每项都有的唯一标记

key 是 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速:

  • 1、更准确:因为带 key 就不是原地复用了,在比较是否是同一个节点的 sameNode 函数 a.key === b.key 对比中可以避免就地复用的情况,所以会更加准确。同时避免频繁更新不同元素,从而使得整个 patch 过程更加高效,减少 DOM 操作量,提高性能。
  • 2、更快速:利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快。

数据更新检测(Vue2)

Vue3没有这个问题

  • 使用以下方法操作数组,可以检测变动

push() pop() shift() unshift() splice() sort() reverse()

  • 新数组替换旧的数组,不会被拦截到

filter() concat() slice() map()

  • 不能检测以下变动的数组 vm.item[indexOfItem] = newValue

解决:

  1. Vue.set(vm.dataList, 0. "hello")
  2. splice

修饰符

事件修饰符

<ul @click.self="handleUlClick">
    //stop: 阻止冒泡
    <li @click.stop="handleLiClick">1111</li>
    <li>2222</li>
</ul>
修饰符作用JS原生
stop阻止冒泡event.stopPropagation()
self将事件绑定到自身,只有自身才能触发,通常用于避免冒泡事件的影响
prevent阻止默认事件的发生event.preventDefault()
capture捕获冒泡,即有冒泡发生时,有该修饰符的dom元素会先执行,如果有多个,从外到内依次执行,然后再按自然顺序执行触发的事件。
once设置事件只能触发一次,比如按钮的点击等。
passive该修饰符大概意思用于对DOM的默认事件进行性能优化,根据官网的例子比如超出最大范围的滚动条滚动的。
native在父组件中给子组件绑定一个原生的事件,就将子组件变成了普通的HTML标签,不加'. native'事件是无法触 发的。

按键修饰符

//enter键 + ctrl键 时,触发
<input type="text" @keyup.enter.ctrl="handleKeyup"/>
<input type="text" @keyup.65="handleKeyup"/>

<!-- Alt + C --> 
<input @keyup.alt.67="clear">

<!-- Ctrl + Click --> 
<div @click.ctrl="doSomething">做一些操作</div>


methods: {
    handleKeyup(evt) {
        //if(evt.keyCode===13) {
            
        //}
    }
}
修饰符作用
enterenter键
delete(捕获“删除”和“退格”按键) => // 删除键
tabtab键
esc取消键
space空格键
up
down
left
right
ctrl
shift

每一个键盘按键都对应一个数字,一般也会将这个数字称之为键盘码值,使用[keyCode大全]

表单修饰符

lazy修饰符

  • 默认情况下,v-model默认是在input事件中同步输入框的数据。也就是说,一旦有数据发生改变对应的data中的数据就会自动发生改变
  • lazy修饰符可以让数据在失去焦点或者回车时才会更新

number修饰符

  • 默认情况下,在输入框无论我们输入的是字母还是数字,都会被当做字符串类型进行处理
  • number修饰符可以让在输入框中输入的内容自动转成数字类型

trim修饰符

  • 如果输入的内容首尾有很多空格,通常我们希望将其去掉
  • trim修饰符可以过滤内容左右两边的空格
<!-- 没有加lazy之前,实时绑定,加上之后,回车绑定--> 
<input type="text" v-model.lazy="message"><br>

<input type="number" v-model.number="age"><br>

<input type="text" v-model.trim="name">


const app = new Vue({ 
    el:"#app", 
    data:{ 
        message:'', 
        age:'', 
        name:'' 
    } 
})

计算属性和侦听器

computed

  • 计算属性(防止模板过重,难易维护),负责逻辑放在计算属性中来写。
  • 计算属性有缓存,基于依赖的缓存。

watch

  • 当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

区别:

  • methods: 事件绑定,逻辑计算。可以不用return,没有缓存
  • computed: (重视结果)解决模板过重问题,必须有return,只求结果,有缓存,同步。
  • watch: (重视过程),监听一个值的改变。不用返回值,异步同步。