概述
记录一些在使用Vue
开发中常见的坑。
先声明本人菜鸟一只,一些描述可能会有偏颇,大佬轻锤,欢迎拍砖。
小葵花课堂开课啦!
插槽相关:slot
与slot-scope
单个插槽 | 匿名插槽
以上两种叫法也就说明了它的含义:
- 一个组件中只能有一个该类插槽
- 该类插槽不设置
name
属性
<!-- 父组件 -->
<template>
<div class="father">
<h3>父组件</h3>
<child>
<div class="tmpl">
<span>test1</span>
<span>test2</span>
<span>test3</span>
</div>
</child>
</div>
</template>
<!-- 子组件 -->
<template>
<div class="child">
<h3>子组件</h3>
<slot></slot>
</div>
</template>
复制代码
子组件中定义的slot
将被父组件中child
内包裹的html
模板所替代,即渲染后成:
<div class="father">
<h3>父组件</h3>
<div class="child">
<h3>子组件</h3>
<div class="tmpl">
<span>test1</span>
<span>test2</span>
<span>test3</span>
</div>
</div>
</div>
复制代码
具名插槽
该插槽name
属性不为空,且可以在一个组件中出现多次。
<!-- 父组件 -->
<template>
<div class="father">
<h3>父组件</h3>
<child>
<div class="tmpl" slot="first">
<span>test1</span>
<span>test2</span>
<span>test3</span>
</div>
<div class="tmpl" slot="second">
<span>test4</span>
<span>test5</span>
<span>test6</span>
</div>
<div class="tmpl">
<span>test7</span>
<span>test8</span>
<span>test9</span>
</div>
</child>
</div>
</template>
<!-- 子组件 -->
<template>
<div class="child">
<h3>子组件</h3>
<!-- 具名插槽 -->
<slot name="first"></slot>
<!-- 具名插槽 -->
<slot name="second"></slot>
<!-- 匿名插槽 -->
<slot></slot>
</div>
</template>
复制代码
组件中匿名插槽可与具名插槽同时使用,并且:
- 声明了
name
的具名插槽将在父组件中找到与其对应名称的slot
属性,并将html
模版替换到其中 - 未声明
name
的将找到对应的未声明slot
属性的html
模版做替换。
作用域插槽
观察可以发现,以上两种插槽的html
模版的内容都是由父组件指定的,那如果我想展示来自子组件的内容该怎么办呢?
所以就有了第三种插槽,我们称之为作用域插槽,坊间也叫携带数据的插槽,顾名思义,这种插槽可以携带数据给到父组件中的html
模板。
<!-- 父组件 -->
<template>
<div class="father">
<h3>父组件</h3>
<child>
<template slot-scope='scope'>
<div class="tmpl">
<span v-for='u in scope.data'>test1</span>
</div>
</template>
</child>
</div>
</template>
<!-- 子组件 -->
<template>
<div class="child">
<h3>子组件</h3>
<!-- 作用域插槽 -->
<slot :data="arr"></slot>
</div>
</template>
<script>
export default {
data () {
return {
arr: ['test1','test2','test3']
}
}
}
</script>
复制代码
子组件中定义了一个数组data
传给父组件展示,父组件以${slotScopeName}.data
的格式去接收这个来自子组件的数组加以展示。
想给第三方UI库Event加自定义参数时
<el-date-picker v-model="editForm[item.name]"
placeholder="选择日期"
:editable="false" style="width:100%"
@change="(value) => changeHandler(value, item.name)">
</el-date-picker>
复制代码
如上,使用箭头函数,return
一个新的自定义函数,在自定义函数changeHandler
中加入你想要的参数。
同路由不同参数时
如果由 app/12345
跳转到 app/23456
,两个路由可能都是app/:id
,用的同一个组件,所以vue
并不会重新走一遍生命周期,导致一些可能的数据没更新的bug
。
所以,一个比较好的解决方案是监控路由的变化来刷新一个必要的参数。
watch: {
'$route.params': function (newValue) {
this.init()
}
}
复制代码
watch
如上是我们常用的 watch
,但可能你不知道watch
还有两个比较实用的配置:deep
与immediate
。
deep
deep
,默认值是 false
。顾名思义即表示深入观察,watch
会将obj
一层层往下遍历,给对象的所有属性都添加了监听。可想而知,这一做法的性能耗费比较大。
watch: {
obj: {
handler (newVal, oldVal) {
console.log('obj的属性变化了')
},
deep: true
},
}
// 建议使用
watch: {
'obj.key': {
handler (newVal, oldVal) {
console.log('obj的属性key变化了')
}
},
}
复制代码
immediate
immediate
,默认值为 false
。顾名思义即表示立即监听,在定义了 handler
方法后将立即执行一次。
watch: {
firstName: {
handler (newval, oldVal) {
this.fullName = `${newval} ${this.lastName}`
},
immediate: true
}
}
复制代码
定时器
很多时候我们可能会有写定时器的需求(比如有个轮询任务),当我们离开这个页面时,你会发现定时任务还在跑,性能炸了。
于是我们可以这么干:
data() {
return {
timer: null
}
}
methods: {
timing() {
this.timer = setInterval(() => {
// dosomething
}, 100)
}
}
beforeDestroy() {
clearInterval(this.timer) // 在组件即将销毁时清掉定时任务
this.timer = null // 变量释放
}
复制代码
关键就在当我们离开这个页面(组件销毁前)时清掉定时任务。
路由懒加载
Vue
的首屏渲染慢饱受诟病。
究其原因,在于webpack打出来的包太大,导致在进入首页的时候需要加载的文件大且多。
那么我们就可以使用懒加载将页面切分(vue-router
支持webpack
内置的异步模块加载系统,使用较少的路由组件不再打包到bundles
中,只在路由被访问到时按需加载),随用随载,减少首页加载的负担。
常规非懒加载路由配置
import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/components/Login'
import Home from '@/components/Home'
import Profile from '@/components/Profile'
Vue.use(Router)
export default new Router({
routes: [{
path: '/login',
name: 'Login',
compontent: Login
}, {
path: '/home',
name: 'Home',
compontent: Home
}, {
path: '/profile',
name: 'Profile',
compontent: Profile
}]
})
复制代码
懒加载路由配置
以下列了常用的三种写法,webpack
都支持。
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
routes: [{
path: '/login',
name: 'Login',
compontent: resolve => require(['@/component/Login'], resolve)
}, {
path: '/home',
name: 'Home',
compontent: () => import(/* webpackChunkName: "home" */
'@/component/Home')
}, {
path: '/profile',
name: 'Profile',
compontent: r => require.ensure([], () => r(require('@/component/Profile')), 'profile')
}]
})
复制代码
Computed
先来看一段代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Computed</title>
</head>
<body>
<div id="app">
<label for="">FirstName:<input v-model="firstName"/></label><br>
<label for="">LastName:<input v-model="lastName"/></label><br>
<label for="">NickName<input v-model="nickName"/></label><br>
<p>名称:{{name}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el: '#app',
data: function() {
return {
firstName: '',
lastName: '',
nickName: ''
}
},
computed: {
name: function() {
console.log('触发computed了')
if (this.nickName) {
return this.nickName
} else {
return this.firstName + '.' + this.lastName
}
}
}
})
</script>
</body>
</html>
复制代码
天真时候的我们可能会以为每当nickName
、firstName
或lastName
三者任一变化都将重新触发name
的变更。
其实不然,当nickName
有值(不为空)后,重新触发依赖收集,此后将移除对firstName
与lastName
的依赖;而当nickName
再次为空值时,又将会收集到对firstName
与lastName
等的依赖。
也就是说,依赖收集是动态的。
re-render相关
还是看一段代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Re-render</title>
</head>
<body>
<div id="app">
<div v-for="(item, index) in items" :key="index">
<div v-if="index === 0">
<input v-model="formData[item.key]">
</div>
<div v-else>{{item.key}}:{{Date.now()}}</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el: '#app',
data: function() {
return {
items: [{
key: 'input'
}, {
key: 'Re-render'
}],
formData: {
input: ''
}
}
}
})
</script>
</body>
</html>
复制代码
以上可能是一种常见的场景。我们会惊奇的发现,当input
框中值发生变化,页面re-render
了一个新的时间戳。不难看出问题出在Date.now()
,这是一个方法(虽然没定义在实例的methods
中),故而每当template
重新渲染时会再次触发一次method
,进而引发意料之外的事故。
<div id="app">
<div>
<label>input:<input v-model="model"/></label>
</div>
<div>
<child :items="makeItems()"></child>
</div>
</div>
复制代码
以上可能更能说明问题,一些场景下我们可能没深考虑或下意识地直接使用一个method
做一些props
传给子组件。那么当输入值model
变化时触发父组件模板重新渲染,child
的items
是从method
来的所以会被重新做一遍,产生不必要的麻烦。
所以,一些场景下为了避免这种不必要的麻烦,还是推荐使用computed
,因为计算属性是基于它们的依赖进行缓存的,而method
在触发重新渲染时总会再次执行函数,不做缓存。
...
未完待续。。。
最后
以上就是伶俐酒窝为你收集整理的Vue中那些容易被忽略的~的全部内容,希望文章能够帮你解决Vue中那些容易被忽略的~所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复