vue面试五之vue修饰符中 .lazy 等用法、Vue v2.4中新增的$attrs及$listeners属性的使用、v-once 的使用场景、vue组件里的定时器该如何销毁、vue海量数据优化等

一 vue修饰符 中 .lazy .number .trim 的用法

1 .lazy 的用法(使双向数据绑定不起作用,且失去焦点的时候,触发@change方法)

<template>
  <div>
    <div>
      <input v-model="msg" @change="show">
      <span>{{msg}}</span>
    </div>
  </div>
</template>


<script>
export default {
  data () {
    return {
      msg: 123
    }
  },
  methods: {
    show () {
      console.log(this.msg)
    }
  }
}
</script>

v − m o d e l 是 双 向 绑 定 的 如 果 这 个 时 候 , 修 改 < i n p u t > 框 中 的 内 容 , < s p a n > 中 内 容 也 会 修 改 v-model是双向绑定的如果这个时候,修改<input>框中的内容,<span>中内容也会修改 vmodel<input><span>
在这里插入图片描述

当使用 .lazy 时

<template>
  <div>
    <div>
      <input v-model.lazy="msg" @change="show">
      <span>{{msg}}</span>
    </div>
  </div>
</template>


<script>
export default {
  data () {
    return {
      msg: 123
    }
  },
  methods: {
    show () {
      console.log(this.msg)
    }
  }
}
</script>

改 变 < i n p u t > 框 中 的 内 容 并 不 会 使 得 < s p a n > 中 的 内 容 发 生 变 化 , 此 时 当 输 入 框 失 去 焦 点 后 触 发 c h a n g e 事 件 。 也 就 是 说 加 上 . l a z y 后 相 当 于 双 向 数 据 绑 定 不 起 作 用 了 改变<input>框中的内容并不会使得<span>中的内容发生变化,此时当输入框失去焦点后触发change事件。也就是说加上.lazy后相当于 双向数据绑定不起作用了 <input>使<span>change.lazy

2 .number 修饰符可以将输入的值转化为Number类型 ( 否则虽然你输入的是数字
但它的类型其实是String ) 在数字输入框中比较有用

<template>
    <div>
        <p>.number修饰符</p>
        <input type="number" v-model.number="val">
        <p>我的数据类型是:{{ typeof(val) }}</p>
    </div>
</template>

<script>
    export default {
        data(){
            return{
              val:''
            }
        }
    }
</script>

3 .trim 修饰符会自动过滤掉输入的首尾空格

<template>
    <div>
        <p>.trim修饰符</p>
        <input type="etxt" v-model.trim="val">
        <p>val的长度是:{{ val.length }}</p>
    </div>
</template>

<script>
    export default {
        data(){
            return{
              val:''
            }
        }
    }
</script>

二 Vue v2.4中新增的$attrs$listeners属性的使用

背景:组件之间传值
在这里插入图片描述
$attrs:
接收除了props声明外的子组件的所有绑定属性(class、style除外)(父组件向子组件传值)
在这里插入图片描述
由于child.vue 在 props 中声明了 name 属性,$attrs 中只有age、gender两个属性,输出结果为:
{ age: “20”, gender: “man” }

在这里插入图片描述
通过 v-bind="$attrs", 可以将属性继续向下传递,让 grandson.vue 也能访问到父组件的属性,这在传递多个属性时会显得很便捷,而不用一条条的进行绑定。
console的结果为:{ height: “180”, gender: “man” } (child.vue 在 props 中声明了 name 属性,grandson.vue在props 中有age属性)

$listeners
接收除了带有.native事件修饰符的所有事件监听器(子组件向父组件传值)
在这里插入图片描述


总结:在child组件上绑定$attrs 和 $listeners 使grandson组件获取parent传递的值并且可以调用在parent那里定义的方法


简单demo举例:

// 父组件
<template>
   <div>
     //给子组件传递两个值
     <child-dom
      :foo="foo"     
      :coo="foo"
     >
     </child-dom>
   </div>
</template>
<script>
   import childDom from "./ChildDom.vue";
   export default {
     data() {
        return {
          foo:"Hello, world",
          coo:"Hello,rui"
        }
     },
     components:{childDom},
   }
</script>



// 子组件
<template>
   <div>
      <p>foo:{{foo}}</p>
      <p>attrs:{{$attrs}}</p>  //通过$attrs获取非props的值
      <childDomChild v-bind="$attrs"></childDomChild>  // 通过v-bind传递值给孙子组件
   </div>
</template>
<script>
import childDomChild from './childDomChild';
export default {
 name:'child-dom'
 props:["foo"],
 inheritAttrs:false,
}
</script>




// 孙子组件
<template>
  <div>
   <p>coo:{{coo}}</p>
  </div>
</template>
<script>
  export default {
    name:'childDomChild'
    props:["coo"],     // 获取子组件传来的值
    inheritAttrs:false
  }
</script>
// 父组件
<template>
 <div>
   <child-dom
     v-on:upRocket="reciveRocket"
   >
   </child-dom>
 </div>
</template>
<script>
 import childDom from "@/components/ChildDom.vue";
 export default {
   name:'demoNo',
   data() {
     return {
    }
  },
 components:{childDom},
 methods:{
   reciveRocket(){
      console.log("reciveRocket success")
   }
 }
}
</script>


// 子组件
<template>
 <div>
 <childDomChild v-on="$listeners"></childDomChild>    // 孙子组件向父组件传值,调用方法
 </div>
</template>
<script>
import childDomChild from './childDomChild';
export default {
 name:'child-dom'
}
</script>


// 孙子组件
<template> 
 <div>
 <button @click="startUpRocket">我要发射火箭</button>
 </div>
</template>
<script>
 export default {
 	name:'childDomChild',
 	methods:{
 		startUpRocket(){
 		this.$emit("upRocket");
 		console.log("startUpRocket")
 	}
 }
</script>

将这个两个demo合在一起则是:

// 父组件
<template>
 <div>
   //1 父组件要给子孙组件传递的值,以及子孙组件让父组件调用的方法
   <child-dom
    :foo="foo"
    :coo="coo"
     v-on:upRocket="reciveRocket"
   >
   </child-dom>
 </div>
</template>
<script>
 import childDom from "@/components/ChildDom.vue";
 export default {
   name:'demoNo',
   data() {
     return {
       foo:"Hello, world",
        coo:"Hello,rui"
    }
  },
 components:{childDom},
 methods:{
   reciveRocket(){
      console.log("reciveRocket success")
   }
 }
}
</script>

// 子组件
<template>
 <div>
 <p>foo:{{foo}}</p>
 <p>attrs:{{$attrs}}</p>
 <childDomChild v-bind="$attrs" v-on="$listeners"></childDomChild>   // 2  v-bind绑定父组件的值,并传给孙子组件,v-on使孙子组件的值,传给父组件
 </div>
</template>
<script>
import childDomChild from './childDomChild';
export default {
 name:'child-dom'
 props:["foo"],
 inheritAttrs:false,
}
</script>

// 孙子组件
<template> 
 <div>
 // 3 可获取父组件的传来的值,可调用方法,使父组件方法执行
 <p>coo:{{coo}}</p>
 <button @click="startUpRocket">我要发射火箭</button>
 </div>
</template>
<script>
 export default {
 	name:'childDomChild',
 	props:['coo'],
 	methods:{
 		startUpRocket(){
 		this.$emit("upRocket");
 		console.log("startUpRocket")
 		}
 }
</script>

三 v-once 的使用场景

背景:v-once的使用
没有使用v-once下的情景:

在这里插入图片描述
打开浏览器,并修改值的时候,mes也会跟着修改,正常,正是vue的双向绑定

在这里插入图片描述

当把上述代码,修改成v-once以后
打开浏览器,并修改值的时候,mes不会发生改变

在这里插入图片描述

v-once只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。

使用场景:

上面是种理想状态,实际开发的时候要想做到上面的理想状态,很难。
当然如果是纯粹的展示大量静态内容,可以用v-once避免重复渲染,提高效率

四 vue组件里的定时器该如何销毁?

this.$once(‘hook:beforeDestroy’,()=>{});
直接在需要定时器的方法或者生命周期函数中声明并销毁,代码如下:

export default{
  methods:{
    fun1(){
      const timer = setInterval(()=>{
      	//需要做的事情
         console.log(11111);
      },1000);
      this.$once('hook:beforeDestroy',()=>{
        clearInterval(timer);
        timer = null;
      })
    }
  }
}

关于this.$once
this.$once是个事件函数,是一个用于监听自定义的函数,或者vue生命周期函数的一个函数
用法this.$once(参数1,参数2)
第一个参数即是被监听的函数(自定义函数,或者vue生命周期函数)
第二个参数就是第一个函数执行后的回调函数

五 如果有大量数据需要渲染,如何提升vue优化?

优化方案:
1 按需加载局部数据, 虚拟列表,无限下拉刷新。(vue-virtual-scroll-list)

2 js运行异步处理: 分割任务,实现时间切片处理, 类似react fiber, 每次执行记录时间, 超过一定执行时间则settimeout或requestAnimation推迟到下一个时间片,一般一个时间片为16ms。

3 大量纯展示的数据,不需要追踪变化的 用object.freeze冻结(可以使用虚拟列表,Object.freeze冻结对象,Object.preventExtentsion阻止对象扩展来阻止vue给每个对象加上get,set,但是缺点是不能响应了)

4 数据量大的时候,可以做分页处理。翻页一次请求10-20条数据。

补充背景:
Object.freeze() 方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。该方法返回被冻结的对象。
vue1.0.18+对其提供了支持,对于data或vuex里使用freeze冻结了的对象,vue不会做getter和setter的转换。

补充背景:
vue-virtual-scroll-list官网地址 https://tangbc.github.io/vue-virtual-scroll-list/#/
https://www.npmjs.com/package/vue-virtual-scroll-list

六 vue递归组件是啥,手写一个递归组件?

递归组件,顾名思义,就是自己的内部实现又调用自己的组件。比如Vue官方给的treeView的例子,父目录下有子目录,子目录下还有子目录,子子孙孙,无穷尽也。就像俄罗斯套娃

手写一个递归组件:

// 父组件
<template>
  <div id="app">   
    <category :datalist="datalist"></category>
  </div>
</template>
 
<script>
import category from './category.vue'
export default {
  name: 'app',
  data () {
    return {
      datalist:[
        {
          title:'手机',
          level:1,
          children:[
            {
              title:'三星',
              level:2,
              children:[  
                  {
                   title:'三星1',
                   level:3
                  }
               ]
            },
            {
              title:'华为',
              level:2
            },
            {
              title:'苹果',
              level:2
            }
          ]
        }   
    ]
  }
 },
  components:{
    category
  },
}
</script>
 
<style>
</style>
 


// 子组件 (递归调用)
<template>
  <div id="phone">
 
  	 <div v-for="(item ,index) in datalist" :key="index">
  	 	{{item.title}}
  	 	<div v-if="item.children" class="item-chilren">
  	 		<phone :datalist="item.children"></phone>
  	 	</div>
  	 </div>
  
  </div>
</template>
 
<script>
export default {
  name: 'phone',
  data () {
    return {
    }
  },
  props:{
  	datalist:Array
  },
}
</script>
 
<style>
.item-chilren{	
}
 
.item-chilren div{
	padding: 2px;
	padding-left: 20px;
	margin-bottom: 2px;
}
</style>
 

在这里插入图片描述

什么要给名字?这个名字是干什么用呢?这个名字很大的一个用处,就是为了我们使用递归组件的时候来使用 。
如果一个组件要使用自己的时候 ,我就可以通过自己的名字来使用自己。

<phone :datalist="item.children"></phone>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 3使用`v-bind="$attrs"`可以将父组件传递的非props属性传递给子组件。如果你在子组件对这些属性进行了二次封装,你可以通过以下两种方式来调用: 1. 直接使用`$attrs`属性名来调用 假设你在子组件对`click`事件进行了二次封装: ``` <template> <button @click="handleClick"> {{ text }} </button> </template> <script> export default { props: { text: String, }, methods: { handleClick(event) { // 二次封装的事件处理函数 this.$emit('my-click', event); }, }, }; </script> ``` 在父组件,你可以这样使用: ``` <template> <my-button text="Click Me" v-bind="$attrs" @my-click="handleMyClick" /> </template> <script> import MyButton from './MyButton.vue'; export default { components: { MyButton, }, methods: { handleMyClick(event) { console.log('My Click Event:', event); }, }, }; </script> ``` 注意,你需要使用`@my-click`来监听`MyButton`组件的`$emit('my-click')`事件。 2. 使用`$listeners`来调用 在Vue 3,你还可以通过`$listeners`来访问所有父组件传递给子组件的事件监听器。你可以在子组件使用`$listeners`来继承父组件的事件监听器,然后在组件内部进行二次封装。例如: ``` <template> <button @click="handleClick"> {{ text }} </button> </template> <script> export default { props: { text: String, }, methods: { handleClick(event) { // 二次封装的事件处理函数 this.$emit('my-click', event); }, }, mounted() { // 继承所有父组件传递的事件监听器 Object.keys(this.$listeners).forEach((eventName) => { this.$el.addEventListener(eventName, this.$listeners[eventName]); }); }, }; </script> ``` 在父组件,你可以这样使用: ``` <template> <my-button text="Click Me" v-bind="$attrs" @my-click="handleMyClick" /> </template> <script> import MyButton from './MyButton.vue'; export default { components: { MyButton, }, methods: { handleMyClick(event) { console.log('My Click Event:', event); }, }, }; </script> ``` 注意,你不需要使用`@my-click`来监听`MyButton`组件的`$emit('my-click')`事件,因为`$listeners`已经继承了父组件的事件监听器。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值