1.如何将获取data
中某一个数据的初始状态?
export default {
data() {
return {
price: 100
}
},
methods: {
changePrice() {
this.price = 101
},
getInitPrice() {
// 可以通过this.$options.data().xxx来获取初始值
console.log('初始price', this.$options.data().price)
}
},
mounted() {
this.getInitPrice()
}
}
2.为什么不建议v-for
和v-if
同时存在
<div v-for="item in list" :key="item.id" v-if="item.name === '诸葛亮'">
{{item.name}}
</div>
export default {
data() {
return {
list: [
{ id: 1, name: '刘备' },
{ id: 2, name: '张飞' },
{ id: 3, name: '诸葛亮' }
]
}
}
}
v-for
的优先级比v-if
高,会优先执行v-for
,即会先把所有个元素都遍历出来,然后再一个个判断是否符合条件,这样的坏处就是,渲染了无用点,增加无用的dom
操作,建议使用computed
来解决这个问题。
<div v-for="item in resultList" :key="item.id">
{{item.name}}
</div>
export default {
computed: {
resultList() {
return this.list.filter(v => v.name === '诸葛亮')
}
},
data() {
return {
list: [
{ id: 1, name: '刘备' },
{ id: 2, name: '张飞' },
{ id: 3, name: '诸葛亮' }
]
}
}
}
3.相同的路由组件如何重新渲染?
多个路由解析为同一个Vue组件,Vue出于性能原因,默认情况下共享组件将不会重新渲染,如果你尝试在使用相同组件的路由之间进行切换,则不会发生任何变化。
const routes = [
{
path: '/a',
component: MyComponent
},
{
path: '/b',
component: MyComponent
},
];
如果依然想重新渲染,怎么办呢?可以使用key
<template>
<router-view :key="$route.path"></router-view>
</template>
4.使用动态指令和参数
<my-component @[someEvent]="handleSomeEvent()" [someProp]="prop"></my-component>
export default {
computed: {
someEvent() {
return this.condition ? 'click' : 'dblclick'
},
someProp() {
return this.condition ? 'propA' : 'propB'
}
},
data() {
return {
condition: false
}
}
}
5.hook
的使用
-
优化定时器的使用方式
这是我们常用的使用定时器的方式
export default {
data() {
return {
timer: null
}
},
mounted(){
this.timer = setInterval(() => {
//具体执行内容
console.log('优化定时器的使用方式');
}, 2000);
},
beforeDestory(){
clearInterval(this.timer);
this.timer = null;
}
}
上面做法不好的地方在于:得全局多定义一个timer
变量,可以使用hook
这么做:
export default {
methods: {
fn() {
let timer = setInterval(() => {
//具体执行内容
console.log('优化定时器的使用方式');
}, 2000);
this.$once('hook:beforeDestroy', () => {
clearInterval(timer);
timer = null;
})
}
},
mounted() {
this.fn()
}
}
- 子组件在特定生命周期触发父组件函数(向父组件传值)
如子组件需要在mounted
时触发父组件的某一个函数,平时都会这么写:
<!-- 父组件 -->
<my-child @someEvent="handleEvent()" />
// 父组件
export default {
methods: {
handleEvent(e) {
// 逻辑代码
}
},
}
// 子组件
export default {
mounted() {
this.$emit('someEvent', '子组件数据')
}
}
使用hook
的话可以更方便:
<!-- 父组件 -->
<my-child @hook:mounted="handleEvent()" />
// 父组件
export default {
methods: {
handleEvent(e) {
// 逻辑代码
}
},
}
6.computed
传参
返回一个带参数的匿名函数,该匿名函数返回计算最终的结果值
<span>{{totalMoney(3)}}</span>
export default {
computed: {
totalMoney() {
return n => n * this.price
}
},
data() {
return {
price: 100
}
},
}
7. watch
监听对象newVal
和oldVal
相同
<div>
<button @click="handleClick('a')">改变a</button>
<button @click="handleClick('b')">改变b</button>
<button @click="handleClick('c')">改变c</button>
<button @click="handleClick('d')">改变d</button>
</div>
export default {
watch: {
params: {
handler(newVal, oldVal) {
// 这里日志打印的newVal和oldVal相同。因为它们索引同一个对象/数组。Vue 不会保留修改之前值的副本。
console.log('newVal', newVal);
console.log('oldVal', oldVal);
}
},
},
data() {
return {
params: {
a: 1,
b: 2,
c: 3,
d: 4,
}
}
},
methods: {
handleClick(type) {
for (const key in this.params) {
if (key === type) {
// 修改属性值
this.params[type] = 100
}
}
},
},
}
深度复制对象,使得引用类型的地址不是同一个地址。
export default {
watch: {
params: {
handler(newVal, oldVal) {
console.log('newVal', newVal);
console.log('oldVal', this.newParams);
}
},
},
data() {
return {
params: {
a: 1,
b: 2,
c: 3,
d: 4,
},
newParams: null,
}
},
methods: {
handleClick(type) {
// newParams 为 params 的深克隆副本,用于记录修改之前的值
this.newParams = JSON.parse(JSON.stringify(this.params))
for (const key in this.params) {
if (key === type) {
// 修改属性值
this.params[type] = 100
}
}
},
},
}
8. 用到scroll
和resize
等事件监听,利用防抖函数做性能优化处理时,解除事件绑定失效。
/* 防抖函数 */
const throttle = (fn, time) => {
let timer = null
return (...args) => {
if (!timer) {
timer = setTimeout(() => {
timer = null
fn.apply(this, args)
}, time)
}
}
}
mounted() {
window.addEventListener('scroll', throttle(this.doSomething, 300))
}
destroyed() {
window.removeEventListener('scroll', throttle(this.doSomething, 300))
}
此时,removeEventListener
解除事件绑定并不会生效,因为addEventListener
和removeEventListener
第二个参数的函数必须是同一函数才行,也就是这两个函数他们的地址指针指向同一个地址。由于防抖函数返回的是一个匿名函数,所以此时他们俩个是不同的函数,导致removeEventListener
不起作用。
解决方法是用一个变量接收throttle
函数的返回结果。
methods: {
fn: throttle(this.doSomething, 300)
}
mounted() {
window.addEventListener('scroll', this.fn)
}
destroyed() {
window.removeEventListener('scroll',this.fn)
}
当然你不想挂一个属性在this上,也可以直接这样写(比较推荐这种写法)
mounted() {
const fn = throttle(this.doSomething, 300)
this.$refs['xxx'].addEventListener('scroll', fn)
this.$on('hook:beforeDestroy', () => {
this.$refs['xxx'].removeEventListener('scroll', fn)
})
}