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>中内容也会修改
v−model是双向绑定的如果这个时候,修改<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>