目录
computed
computed是啥意思呢:根据依赖(就是某个data值或者props值),计算后的某个值。
`computed`是计算属性的意思,是依赖其他的属性计算所得出最后的值。在Vue中,`computed`被定义为函数,但是不能传入任何参数,它只能“依赖”其它`data`或者`props`值。当它依赖的属性值发生改变,就会重新计算 `computed ` 的值,依赖数据不变时会直接从缓存中获取,不会重新计算。`computed`可以拆为`getter`和`setter`,这样的话,可以和`v-model`配合。
运用场景:当一个属性受多个属性影响时,比如我曾经制作过的美元、人民币、日元的换算**,用户可以在任何一个币种的输入框中输入数值,其他输入框要联动。此时用watch就会引发连锁变化的问题,所以使用`computed`,因为`computed`要有一个“依赖值”,我们自然而然用美元当做所有币种的**依赖值**,他们的`getter`都是美元乘汇率,他们的`setter`都是设置美元为`newValue`除汇率。当时那个例子做完之后,我对`computed`有了非常深的理解。
<template>
<div>
<p> 人民币:<input type="text" v-model="rmb"> </p>
<p> 美元:<input type="text" v-model="usDollar"> </p>
<p> 日元:<input type="text" v-model="jpDollar"> </p>
<p> 泰币:<input type="text" v-model="swdkDollar"> </p>
</div>
</template>
<script>
export default {
data() {
return {
usDollar: 1
}
},
computed: {
rmb: {
get() {
return this.usDollar * 6;
},
set(newValue) {
this.usDollar = newValue / 6;
}
},
jpDollar: {
get() {
return this.usDollar * 180;
},
set(newValue) {
this.usDollar = newValue / 180;
}
},
swdkDollar: {
get() {
return this.usDollar * 33.65;
},
set(newValue) {
this.usDollar = newValue / 33.65;
}
}
}
}
</script>
<style lang="scss" scoped>
</style>
watch主要应用场景:
什么时候用:当一条数据影响多条数据
`watch`,主要是监控`v-model`的值的变化,比如再做筛选器(搜索框)时,复选框的`v-model`值可以被`watch`,这样就能当复选框被改变时,发出Ajax了。
methods有什么功能?
答:methods最常见的就是事件处理函数,我们的`@click="clickHandler()"`,这个`clickHandler`就要定义在methods中。methods中定义的函数,也可以直接显示在页面上。
data为什么是一个函数?
JavaScript中的对象是引用类型值的数据,当多个实例引用同一个对象时,只要一个实例对这个对象进行操作,其他实例中的数据也会发生变化。而在Vue中,更多的是想复用组件,那就需要组件都有自己的数据,这样组件之间才不会相互干扰。组件中的data写成一个函数,数据以函数返回值得形式定义,这样每次复用程序的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,他们只负责各自维护的数据,不会造成混乱。
Vue有哪些生命周期?你常用哪些生命周期?
答:Vue一共是11种生命周期,它们是:
- 8个普通生命周期: `beforeCreate`、`created`、`beforeMount`、`mounted`、`beforeUpdate`、`updated`、`beforeDestroy`、`destroyed`。
- 2个和路由相关的生命周期: `active`、`deactived`
- 1个捕获错误的生命周期: `captureError`
我工作中,最常用的生命周期是:
- `created`:这个生命周期用来发出Ajax请求,以及将props的值赋值给data;
- `mounted`: 这个生命周期用来得到DOM元素,比如`echart`图表的盒子,就要在这个生命周期中用`this.$refs`获得;
- `destroyed`: 这个生命周期通常用来配合本地存储,比如当组件消亡时,就命令本地存储器清空。
生命周期 | 作用 |
beforeCreate | 组件创建之前。**没用**。因为这个生命周期,组件还没有创建,所有的`data`值无法访问,比如`this.a`会得到`undefined`。 |
created | 组件已经创建。**非常有用,**`data`值已经可以使用了,`methods`都可以使用,组件的一切都已经就绪了。我们通常在`created`生命周期中,发出Ajax请求。 |
beforeMount | 组件上树之前。**没用**。 |
mounted | 组件已经上树。**非常有用。**比如echarts要得到一个盒子,把图表放里面。就要用mounted生命周期。 |
beforeUpdate | 当data或者props改变之前触发。**没用。** 注意,不能在beforeUpdate生命周期中改变data、props,否则死循环。 |
updated | 当data或者props改变之后触发。**有点用。**注意,不能在updated生命周期中改变data、props,否则死循环。可能在updated时,将组件的数据用Ajax告诉服务器。 |
beforeDestroy | 当组件消亡之前做的事情。**没用。** |
destroyed | 当组件消亡之后做的事情。**有点用。**比如清空本地存储数据。 |
父子组件的生命周期顺序
-
加载渲染过程: 父 beforeCreate → 父 created → 父 beforeMount → 子 beforeCreate → 子 created → 子 beforeMount → 子 mounted → 父 mounted
-
子组件更新过程(父亲的data当做props传给了子组件): 父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
-
销毁过程(当父组件销毁,带着儿子一切销毁):父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
在哪个生命周期内调用异步请求?
理论上,可以在`created`、`beforeMount`、`mounted` 中发出Ajax请求,因为在这三个钩子函数中,`data` 已经创建、`this`也可以使用。(只要不是`beforeCreated`都能用)。
实战中,`created` 钩子函数发出Ajax请求是最多的,因为它有着独一无二的两个优点:
1、是**最快**的可用生命周期,第一时间获取到服务端数据,减少页面 `loading` 时间;
2、服务端渲染(SSR)不支持` beforeMount` 、`mounted`钩子函数,所以放在 `created `中有助于**一致性**;
在什么阶段才能访问操作DOM?
在 `mounted` 中可以访问操作 DOM。使用`this.$refs`这个语法糖,可以快速访问操作DOM。比如Echarts图表,就要在`mounted`中去初始化。
父组件可以监听到子组件的生命周期吗?
比如有父组件`App`和子组件`Zi`,如果父组件监听到子组件`mounted` 就做一些逻辑处理,可以通过以下写法实现:儿子一旦`mounted`了,那么就触发`$emit`了。
// APP.vue
<Zi @iMounted="iMountedHandler()"/>
// Zi.vue
mounted() {
this.$emit("iMounted");
}
Vue提供了更好用的东西:@hook
<Zi @hook:beforeCreate="x1" @hook:created="x2" @hook:beforeMount="x3"/>
这样,儿子就不用别别扭扭的$emit
了。
**v-show和v-if的区别和适用场景?
区别:
v-if
决定元素上树与下树。
① 如果v-if
写在子组件标签上,比如<Zi v-if="m"/>
,那么能引发子组件的销毁和重建;
② v-if
是惰性的:如果在初始渲染时条件为假,则什么也不做,直到条件第一次变为真时,才会开始渲染条件块;
③ v-if
能结合v-else
使用,而v-show
不能。
v-show
决定元素显示与隐藏。
① 如果v-show
写在子组件标签上,不引发子组件的任何生命周期。
②v-show
不是惰性的,不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 display`”属性进行切换。
③ 不能结合v-else
使用。
适用场景:
-
v-if
适用于:-
需要触发子组件的生命周期,特别是销毁子组件时,比如弹出层的表单;
-
需要初始值惰性防错时,比如Ajax值没有返回回来,那么
arr[0].title
就会报错,而如果写在v-if="arr.length != 0"
的盒子中,就没有错误了; -
不适合大型子组件频繁切换。
-
-
v-show
适用于:-
不需惰性防错,只是简单的显示、隐藏特效。
-
v-if后面能够跟上v-else,表示当v-if条件为假的时候,这个盒子上树。
<div v-if="m">A</div> <div v-else>B</div>
m是真,A上树,B下树。m是假,A下树,B上树。
面试题:v-text和v-html的区别
v-text
不会解析HTML标签,而v-html
会解析HTML标签。但要注意的是,v-text
和v-html
中的HTML标签,无法渲染双大括号、指令等Vue的语法。
我曾经用v-html
制作过“智能感应”
<template>
<div>
<input type="text" v-model="keyword" />
<ul>
<li v-for="(item, index) in arr" :key="index" v-html="xianShi(item)"></li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
keyword: "钱",
arr: ["钱队长", "金元宝", "元宝金", "钱多多", "种种钱"],
};
},
methods: {
xianShi(str) {
const index = str.indexOf(this.keyword);
if (index != -1) {
return (
str.slice(0, index) +
"<b>" +
this.keyword +
"</b>" +
str.slice(index + this.keyword.length)
);
}
},
},
};
</script>
<style lang="less">
b {
color: pink;
}
li {
list-style: none;
}
</style>
class 如何动态绑定?
<div :class="{current: index == nowIndex}"></div>
普通class和动态class可以写在一个div中:
<div class="box" :class="{cur: index == nowIndex}"></div>
其实还有数组+对象形式:
<div :class="['cu', 'hong', { xie: 3 > 2, xian: 3 > 500 }]">
你好
</div>
解释:数组中的字符串会被当做一定有的类名,而对象呢?要看表达式是否为真。即,cu这个类名一定有、hong一定有。xie因为表达式是真,也有。xian因为表达式是假,所以没有。
面试题:Style如何动态绑定?
<div :style="{width: a + 'px'}"></div>
其实还有数组+对象形式:
<section :style="[ys1, ys2()]">哈哈哈</section>
ys1定义在data中,是一个对象:
data() {
return {
ys1: {
'color': 'red',
'font-size': '40px'
}
};
},
ys2是一个函数,定义在methods中,返回一个对象:
methods: {
ys2() {
return {
'transform': 'rotate(' + (this.a * 2) + 'deg)'
}
}
},
v-model可以用哪些修饰符?
必须背诵v-model
有三个修饰符:
-
.lazy
- 加上.lazy
之后,拖拽条松手才改变a的值,拖拽过程中不改变a的值。即取代了input
监听change
事件。 -
.number
- 输入字符串转为数字 -
.trim
- 输入首尾空格过滤
比如拖拽条,加了.lazy
,只有松手的时候才触发,拖拽的时候,不触发。
<input type="range" v-model.lazy="a">
比如文本框,加了.number
,输入的东西就是数字了,双向绑定改变a为数字,不是字符串;加了.trim
,输入的东西前后的空格会被自动去掉。
<input type="text" v-model.number="a">
<input type="text" v-model.number.trim="a">
@click有哪些修饰符?
.stop
阻止事件冒泡.prevent
阻止默认行为
例如弹出层应用
<template>
<div>
<div class="mask" v-show="isShow" @click="isShow = false">
<div class="inner" @click.stop></div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
isShow: true,
a: 12,
};
},
};
</script>
<style lang="less">
.mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.668);
display: flex;
justify-content: center;
align-items: center;
}
.inner {
width: 300px;
height: 200px;
background-color: white;
}
</style>
如何将父组件的全部props,都传给子组件?
<child-component v-bind="$props"></child-component>
v-pre指令和v-once指令有什么用?
v-pre
指令跳过这个元素和它的子元素的编译过程。可以用来显示原始标签,内部的所有双大括号和指令都不会执行,适用于跳过大量没有指令的HTML元素,会加快编译过程。
v-once
指令只渲染元素和组件一次。一旦数据渲染了,今后所有的重新渲染,将被视为静态内容并跳过。这可以用于优化更新性能。
面试题:v-bind:is指令有什么用?
is
就表示动态选择用什么组件。:is=""
双引号里面是组件的标签名。
准备三个组件Step1,Step2,Step3
owStep值是1的时候,让Step1组件显示;
nowStep值是2的时候,让Step2组件显示;
nowStep值是3的时候,让Step3组件显示;
<template>
<div>
<el-steps :active="nowStep">
<el-step
title="步骤 1"
description="这是一段很长很长很长的描述性文字"
></el-step>
<el-step
title="步骤 2"
description="这是一段很长很长很长的描述性文字"
></el-step>
<el-step title="步骤 3" description="这段就没那么长了"></el-step>
</el-steps>
<div style="padding: 40px">
<div :is="'Step' + nowStep"></div>
<!-- <Step1 v-if="nowStep == 1" />
<Step2 v-if="nowStep == 2" />
<Step3 v-if="nowStep == 3" /> -->
</div>
<el-button @click="nowStep++">下一步</el-button>
</div>
</template>
<script>
import Step1 from "./Step1.vue";
import Step2 from "./Step2.vue";
import Step3 from "./Step3.vue";
export default {
components: {
Step1,
Step2,
Step3,
},
data() {
return {
nowStep: 1,
a: 12,
};
},
};
</script>
<style lang="less">
.mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.668);
display: flex;
justify-content: center;
align-items: center;
}
.inner {
width: 300px;
height: 200px;
background-color: white;
}
</style>