【十七】vue常用API

在这里插入图片描述

前言

本篇博客主要讲述了vue的相关API、Mixin混入、数据整合以及开发中的注意事项。

面题回答

1.$set的实现:首先判断set的目标是否是值类型,如果是值类型就报错。如果不是,就会判断了目标是否是数组,如果是数组,那么就会判断key是不是合法,如果条件都成立就对目标数组进行操作,而这些操作诸如push、splice、pop等都是经过重写的,以达到响应式的操作。如果是对象,那么就需要通过vue.observable或者用object.defineProperty设置get/set去实现。

2.$nextTick的作用:$.nextTick可以当作一个Promise使用,它在下一次DOM更新循环结束之后执行延迟回调。这里涉及到事件循环以及微任务的概念。因为UI渲染是在微任务队列执行完毕之后进行的,我们要做的是在UI渲染之前完成数据的变更,那么就需要添加一个微任务,这样这个微任务会被push到任务队列的末尾。常见的场景一般有在create生命周期中,DOM节点未更新,此时拿不到DOM节点,那么可以$.nextTick方法包裹,在下一个DOM节点出现的时候,拿到对应的节点。

3.v-if和v-show的区别:v-show的本质是把所在元素的display样式设置为none,dom元素其实还在,切换时不会触发组件的生命周期。而v-if则是真正的销毁所在的元素,因此会产生局部编译, 开销更大,且切换过程中会触发生命周期钩子函数。而决定使用哪个取决于切换频率,切换频率低使用v-if。

4.v-for索引:v-for默认使用就地复用策略。一般我们常用v-for来渲染列表数据,比如动态表头,有可能出现表头内容改变但是index不变的情况,这时候会出现渲染问题。或者是在表格数据量可能较大,且伴随一些增删改的操作,如果没有key整个列表都得重新渲染一遍,如果直接使用index,在增删数据后,index会产生变化,比如从4条数据的第二条数据中插入一条新的数据,就会导致后续的数据都会重新渲染,从而导致大量不必要的渲染,消耗性能。而使用唯一id,则只会对新增的数据进行渲染处理。

知识点

常用方法、Mixin混入、数据整合、注意事项理解

1.常用方法

$set

Vue有一些数组的变动无法被检测到,比如通过索引改变数组的值(this.arr[5] = ‘zxp’)、修改数组的长度(this.arr.length = 5 ) 等,此时需要用到$set用来添加对象属性(确保该属性为响应式,并且能触发视图更新)。

<div v-for="(item,index) in list" :key="index">
  {{item.name}}
</div>
<el-button @click="changeValue">change</el-button>

//js部分
data(){
  return {
    list:[
      {name:'111',id:'1'},
      {name:'222',id:'2'}
    ]
  }
},
methods:{
  changeValue(){
    this.$set(this.list,0,{name:'333',id:'3'})
    //如果直接将list第一个值改为{name:'333',id:‘3’},会出现数据改变了,视图不更新的异常
  }
}
$delete

用来删除对象数学(确保该属性为响应式,并且能触发视图更新)。一般我们常用delete关键字进行对象内部值得删除,但在Vue2里面不能直接使用对象删除的方法,会出现数据已经被删除,而视图没有更新的情况,即不能实现双向数据绑定。

let obj ={
    a:'1',
    b:'2',
    c:'3'
}
delete obj.b
console.log(obj) //{a:'1',c:'3'}
data(){
  return{
    testData:{
      name:'zxp'
    },
    test:'abc'
  }
},
methods:{
  del(){
    //如果是数组,则将name改为index(数组下标)
    this.$delete(this.testData,'name')
    //下面这行是直接删除data中的test属性
    delete test
  }
}

PS:Vue2底层使用的Object.defineProperty可以实现修改和查看,但是监听不到数据的添加和删除,Vue3使用了proxy方式实现双向数据绑定,可以直接添加、删除。

$nextTick

$.nextTick可以当作一个Promise使用,它在下一次DOM更新循环结束之后执行延迟回调。这里涉及到事件循环以及微任务的概念。因为UI渲染是在微任务队列执行完毕之后进行的,我们要做的是在UI渲染之前完成数据的变更,那么就需要添加一个微任务,这样这个微任务会被push到任务队列的末尾。

showPwd(){
  this.pwdType = !this.pwdType 
  this.$nextTick(()=>{
    this.$refs.password.focus()
  })
}
<template>
  <div @click="handleClick" ref="test">{{message}}</div>
</template>

<script>
export default{
  data(){
    return {
      message:'zxp'
    }
  },
  methods:{
    handleClick(){
      this.message="Hello"
      console.log(this.$refs.test.innerText)//zxp 
      console.log(this.message)//Hello 
      this.$nextTick(()=>{
        console.log(this.$refs.test.innerText)//Hello
      	console.log(this.message)//Hello 
      })
    }
  }
}

2.事件监听

事件监听
  • @load:img上的src有值时,图片便开始加载,但是加载完毕需要一定的时间,而@load事件是在完成加载后触发的。也可以应用于iframe、webView、滚动事件等完成后触发。

    <img :src="url" @load="imgLoad"></img>
    
    export default{
        data(){
            return {
                url:'xxxxx'
            }
        },
        methods:{
            imgLoad(){
                console.log('加载完成')
            }
        }
    }
    
  • @click

    <div id="app">
        <button @click="click">click me</button>
    </div>
    ...
    var app = new Vue({
        el: '#app',
        methods: {
            click(event) {
                console.log(typeof event);    // object
                //使用不带圆括号的形式,event对象将被自动当做实参传入;
            }
        }
    });@change
    
  • @change

    <div id="app">
        <button v-on:click="click($event, 'zxp')">click me</button>
    </div>
    ...
    var app = new Vue({
        el: '#app',
        methods: {
            click(event, val) {
                console.log(typeof event);    // object
                console.log(val);    // zxp
                //使用带圆括号的形式,我们需要使用 $event 变量显式传入 event 对象。
            }
        }
    });
    
  • @focus:获取input焦点事件

  • @input:input输入值时的事件

  • @keyup:当指定的按键松开会触发的事件

  • @keydown:当指定的按键按下会触发的事件

  • @mousedown:按下鼠标键时触发

  • @mouseup:释放按下的鼠标键时触发

  • @mousemove:鼠标移动事件,

  • @mouseover:移入事件,鼠标指针穿过被选元素或其子元素、孙元素,会冒泡

  • @mouseout:移出事件,鼠标指针穿过被选元素或其子元素、孙元素,会冒泡

  • @mouseenter:移入事件,只触发一次,不冒泡

  • @mouseleave:移出事件,只触发一次,不冒泡

事件修饰符
  • .stop - 阻止冒泡
  • .prevent - 阻止默认事件,比如提交
  • .capture - 阻止捕获
  • .self - 只监听触发该元素的事件
  • .once - 只触发一次
  • .left - 左键事件
  • .right - 右键事件
  • .middle - 中间滚轮事件
<!-- 阻止单击事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联  -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件侦听器时使用事件捕获模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>

<!-- click 事件只能点击一次,2.1.4版本新增 -->
<a v-on:click.once="doThis"></a>
按键修饰符
  • .enter
  • .tab
  • .delete (捕获 “删除” 和 “退格” 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
  • .ctrl
  • .alt
  • .shift
  • .meta
<p><!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

3.面试题

v-if和v-show有什么区别

共同点:v-show与v-if的作用效果是相同的,都是控制元素在页面显示。

区别:v-show的本质是把v-show所在元素的样式设置为display:none,dom元素其实还在,切换时不会触发组件的生命周期,初始渲染成本较高;而v-if则是真正的销毁所在的元素,因此v-if会产生局部编译, 开销更大,且切换过程中会触发生命周期钩子函数。而决定使用哪个取决于切换频率,切换频率低使用v-if。

v-if和v-for不能共用的原因

在对template解析时,当v-for和v-if 处于同一个节点时,v-for的执行级别比v-if要高,同时使用会遍历数组的每一项,那么每一项都会进行v-if的判断,这样会产生不必要的性能开销)。

以上内容针对vue2版本,vue3是可以一起用的,vue3更新了优先级,v-if高于v-for,但仍旧不建议两者一起使用。

v-for中key的作用

key的作用:key给每一个vnode节点一个唯一id,虚拟dom可以依靠key,更准确、更快的拿到对应的vnode节点。(PS:对比的是拿到vnode的速度而不是实际所消耗的速度。)

不带key的diff速度确实会更快,因为虚拟dom在默认情况下会采取就地复用的方式(dom节点位置不变),即没有key时,状态默认绑定的是位置,有key时,状态根据key的属性值绑定到了响应的数组元素。但是这种方式会产生如过渡效果异常等依赖于组件状态的问题(就地复用),即不够准确。

常见场景:表格动态表头,表头由动态数据v-for遍历渲染,有可能出现表头内容改变但是index不变的情况,这时候会出现渲染问题。或者是在表格数据量可能较大,且伴随一些增删改的操作,如果没有key整个列表都得重新渲染一遍,如果直接使用index,在增删数据后,index会产生变化,比如从4条数据的第二条数据中插入一条新的数据,就会导致后续的数据都会重新渲染,从而导致大量不必要的渲染,消耗性能。而使用唯一id,则只会对新增的数据进行渲染处理。

组件中的data为函数的原因
<script>
export default{
    data(){
        return {
            a:'1',
            b:'2'
        }
    }
    
}
</script>

一个组件被复用多次的话,也就会创建多个实例,从本质上来说,这些实例用的都是同一个构造函数,当我们将组件中的data写成一个函数,数据是以函数返回值形式定义的,这样每复用一次data,都会返回一份新的data,拥有自己的作用域,也是vue中闭包的一种应用。 如果组件中data是对象的话,对象是引用数据类型,它就会共用一个内存地址,造成数据污染。

最后

data(){
return {
a:‘1’,
b:‘2’
}
}

}


一个组件被复用多次的话,也就会创建多个实例,从本质上来说,这些实例用的都是同一个构造函数,当我们将组件中的data写成一个函数,数据是以函数返回值形式定义的,这样每复用一次data,都会返回一份新的data,拥有自己的作用域,也是vue中闭包的一种应用。 如果组件中data是对象的话,对象是引用数据类型,它就会共用一个内存地址,造成数据污染。 



## 最后

走过路过,不要错过,点赞、收藏、评论三连~
  • 25
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值