前言
个别在组件内应用路由参数,大多数人会这样做:
先赞再看,养成习惯~
明天分享十个 vue 开发技巧给大家,中级前端工程师
1. 路由参数解耦
export default {
methods: {getParamsId() {return this.$route.params.id}
}
}
在组件中应用 $route 会使之与其对应路由造成高度耦合,从而使组件只能在某些特定的 URL 上应用,限度了其灵活性。
正确的做法是通过 props 解耦
const router = new VueRouter({
routes: \[{
path: '/user/:id',
component: User,
props: true
}\]
})
将路由的 props 属性设置为 true 后,组件内可通过 props 接管到 params 参数
export default {props: \['id'\],
methods: {getParamsId() {return this.id}
}
}
另外你还能够通过函数模式来返回 props
const router = new VueRouter({
routes: \[{
path: '/user/:id',
component: User,
props: (route) => ({id: route.query.id})
}\]
})
文档:https://router.vuejs.org/zh/guide/essentials/passing-props.html
对于想要学习前端,然而不晓得从何动手的小伙伴们,我特意筹备了个 qun,整顿了一份最全面的前端学习材料(最根底的【HTML+css+JavaScript】到挪动端的 HTML5 的我的项目实战教程视频),想学习的都能够退出 https://jq.qq.com/?_wv=1027&k…
喜爱的敌人还请点个 star+ 关注~
2. 函数式组件
函数式组件是无状态,它无奈实例化,没有任何的生命周期和办法。创立函数式组件也很简略,只须要在模板增加 functional 申明即可。个别适宜只依赖于内部数据的变动而变动的组件,因其轻量,渲染性能也会有所提高。
组件须要的一切都是通过 context 参数传递。它是一个上下文对象,具体属性查看文档。这里 props 是一个蕴含所有绑定属性的对象。
函数式组件
<template functional>
<div class="list">
<div class="item" v-for="item in props.list" :key="item.id" @click="props.itemClick(item)">
<p>{{item.title}}</p>
<p>{{item.content}}</p>
</div>
</div>
</template>
父组件应用
<template>
<div>
<List :list="list" :itemClick="item => (currentItem = item)" />
</div>
</template>
import List from '@/components/List.vue'
export default {
components: {List},
data() {
return {
list: \[{
title: 'title',
content: 'content'
}\],
currentItem: ''
}
}
}
文档:渲染函数 & JSX — Vue.js
3. 款式穿透
在开发中批改第三方组件款式是很常见,但因为 scoped 属性的款式隔离,可能须要去除 scoped 或是另起一个 style。这些做法都会带来副作用(组件款式净化、不够优雅),款式穿透在 css 预处理器中应用才失效。
咱们能够应用 >>> 或 /deep/ 解决这一问题:
<style scoped>
外层 >>> .el-checkbox {
display: block;
font-size: 26px;
.el-checkbox\_\_label {font-size: 16px;}
}
</style>
<style scoped>
/deep/ .el-checkbox {
display: block;
font-size: 26px;
.el-checkbox\_\_label {font-size: 16px;}
}
</style>
4.watch 高阶应用
立刻执行
watch 是在监听属性扭转时才会触发,有些时候,咱们心愿在组件创立后 watch 可能立刻执行
可能想到的的办法就是在 create 生命周期中调用一次,但这样的写法不优雅,或者咱们能够应用这样的办法
export default {data() {
return {name: 'Joe'}
},
watch: {
name: {
handler: 'sayName',
immediate: true
}
},
methods: {sayName() {console.log(this.name)
}
}
}
深度监听
在监听对象时,对象外部的属性被扭转时无奈触发 watch,咱们能够为其设置深度监听
export default {
data: {
studen: {
name: 'Joe',
skill: {
run: {speed: 'fast'}
}
}
},
watch: {
studen: {
handler: 'sayName',
deep: true
}
},
methods: {sayName() {console.log(this.studen)
}
}
}
触发监听执行多个办法
应用数组能够设置多项,模式包含字符串、函数、对象
export default {
data: {name: 'Joe'},
watch: {
name: \[
'sayName1',
function(newVal, oldVal) {this.sayName2()
},
{
handler: 'sayName3',
immaediate: true
}
\]
},
methods: {sayName1() {console.log('sayName1==>', this.name)
},
sayName2() {console.log('sayName2==>', this.name)
},
sayName3() {console.log('sayName3==>', this.name)
}
}
}
文档:API — Vue.js
5.watch 监听多个变量
watch 自身无奈监听多个变量。但咱们能够将须要监听的多个变量通过计算属性返回对象,再监听这个对象来实现“监听多个变量”
export default {data() {
return {
msg1: 'apple',
msg2: 'banana'
}
},
compouted: {msgObj() {const { msg1, msg2} = this
return {
msg1,
msg2
}
}
},
watch: {
msgObj: {handler(newVal, oldVal) {if (newVal.msg1 != oldVal.msg1) {console.log('msg1 is change')
}
if (newVal.msg2 != oldVal.msg2) {console.log('msg2 is change')
}
},
deep: true
}
}
}
6. 事件参数 $event
$event 是事件对象的非凡变量,在一些场景能给咱们实现简单性能提供更多可用的参数
原生事件
在原生事件中体现和默认的事件对象雷同
<template>
<div>
<input type="text" @input="inputHandler('hello', $event)" />
</div>
</template>
export default {
methods: {inputHandler(msg, e) {console.log(e.target.value)
}
}
}
自定义事件
在自定义事件中体现为捕捉从子组件抛出的值
my-item.vue :
export default {
methods: {customEvent() {this.$emit('custom-event', 'some value')
}
}
}
App.vue
<template>
<div>
<my-item v-for="(item, index) in list" @custom-event="customEvent(index, $event)">
</my-list>
</div>
</template>
export default {
methods: {customEvent(index, e) {console.log(e) // 'some value'
}
}
}
文档:事件处理 — Vue.js
https://cn.vuejs.org/v2/guide/components.html#%E4%BD%BF%E7%94%A8%E4%BA%8B%E4%BB%B6%E6%8A%9B%E5%87%BA%E4%B8%80%E4%B8%AA%E5%80%BC
7. 自定义组件双向绑定
组件 model 选项:
容许一个自定义组件在应用 v-model 时定制 prop 和 event。默认状况下,一个组件上的 v-model 会把 value 用作 prop 且把 input 用作 event,然而一些输出类型比方单选框和复选框按钮可能想应用 value prop 来达到不同的目标。应用 model 选项能够回避这些状况产生的抵触。input 默认作为双向绑定的更新事件,通过 $emit 能够更新绑定的值
<my-switch v-model="val"></my-switch>
export default {
props: {
value: {
type: Boolean,
default: false
}
},
methods: {switchChange(val) {this.$emit('input', val)
}
}
}
批改组件的 model 选项,自定义绑定的变量和事件
<my-switch v-model="num" value="some value"></my-switch>
export default {
model: {
prop: 'num',
event: 'update'
},
props: {
value: {
type: String,
default: ''
},
num: {
type: Number,
default: 0
}
},
methods: {numChange() {this.$emit('update', this.num++)
}
}
}
文档:API — Vue.js
8. 监听组件生命周期
通常咱们监听组件生命周期会应用 $emit,父组件接管事件来进行告诉
子组件
export default {mounted() {this.$emit('listenMounted')
}
}
父组件
<template>
<div>
<List @listenMounted="listenMounted" />
</div>
</template>
其实还有一种简洁的办法,应用 @hook 即可监听组件生命周期,组件内无需做任何扭转。同样的,created、updated 等也能够应用此办法。
<template>
<List @hook:mounted="listenMounted" />
</template>
9. 程序化的事件侦听器
比方,在页面挂载时定义计时器,须要在页面销毁时革除定时器。这看起来没什么问题。但认真一看 this.timer 惟一的作用只是为了可能在 beforeDestroy 内取到计时器序号,除此之外没有任何用途。
export default {mounted() {this.timer = setInterval(() => {console.log(Date.now())
}, 1000)
},
beforeDestroy() {clearInterval(this.timer)
}
}
如果能够的话最好只有生命周期钩子能够拜访到它。这并不算重大的问题,然而它能够被视为杂物。
咱们能够通过 $on 或 $once 监听页面生命周期销毁来解决这个问题:
export default {mounted() {this.creatInterval('hello')
this.creatInterval('world')
},
creatInterval(msg) {let timer = setInterval(() => {console.log(msg)
}, 1000)
this.$once('hook:beforeDestroy', function() {clearInterval(timer)
})
}
}
应用这个办法后,即便咱们同时创立多个计时器,也不影响成果。因为它们会在页面销毁后程序化的自主革除。
文档:解决边界状况 — Vue.js
10. 手动挂载组件
在一些需要中,手动挂载组件可能让咱们实现起来更加优雅。比方一个弹窗组件,最现实的用法是通过命令式调用,就像 elementUI 的 this.$message。而不是在模板中通过状态切换,这种实现真的很蹩脚。
先来个最简略的例子:
import Vue from 'vue'
import Message from './Message.vue'
// 结构子类
let MessageConstructor = Vue.extend(Message)
// 实例化组件
let messageInstance = new MessageConstructor()
// $mount 能够传入选择器字符串,示意挂载到该选择器
// 如果不传入选择器,将渲染为文档之外的的元素,你能够设想成 document.createElement() 在内存中生成 dom
messageInstance.$mount()
// messageInstance.$el 获取的是 dom 元素
document.body.appendChild(messageInstance.$el)
上面实现一个繁难的 message 弹窗组件
Message/index.vue
`<template>
<div class="wrap">
<div class="message" :class="item.type" v-for="item in notices" :key="item.\_name">
<div class="content">{{item.content}}</div>
</div>
</div>
</template> `
// 默认选项
const DefaultOptions = {
duration: 1500,
type: 'info',
content: '这是一条提示信息!',
}
let mid = 0
export default {data() {
return {notices: \[\]
}
},
methods: {add(notice = {}) {
// name 标识 用于移除弹窗
let \_name = this.getName()
// 合并选项
notice = Object.assign({\_name}, DefaultOptions, notice)
this.notices.push(notice)
setTimeout(() => {this.removeNotice(\_name)
}, notice.duration)
},
getName() {return 'msg\_' + (mid++)
},
removeNotice(\_name) {let index = this.notices.findIndex(item => item.\_name === \_name)
this.notices.splice(index, 1)
}
}
}
.wrap {
position: fixed;
top: 50px;
left: 50%;
display: flex;
flex-direction: column;
align-items: center;
transform: translateX(-50%);
}
.message {
--borderWidth: 3px;
min-width: 240px;
max-width: 500px;
margin-bottom: 10px;
border-radius: 3px;
box-shadow: 0 0 8px #ddd;
overflow: hidden;
}
.content {
padding: 8px;
line-height: 1.3;
}
.message.info {border-left: var(--borderWidth) solid #909399;
background: #F4F4F5;
}
.message.success {border-left: var(--borderWidth) solid #67C23A;
background: #F0F9EB;
}
.message.error {border-left: var(--borderWidth) solid #F56C6C;
background: #FEF0F0;
}
.message.warning {border-left: var(--borderWidth) solid #E6A23C;
background: #FDF6EC;
}
Message/index.js
import Vue from 'vue'
import Index from './index.vue'
let messageInstance = null
let MessageConstructor = Vue.extend(Index)
let init = () => {messageInstance = new MessageConstructor()
messageInstance.$mount()
document.body.appendChild(messageInstance.$el)
}
let caller = (options) => {if (!messageInstance) {init()
}
messageInstance.add(options)
}
export default {
// 返回 install 函数 用于 Vue.use 注册
install(vue) {vue.prototype.$message = caller}
}
main.js
import Message from '@/components/Message/index.js'
Vue.use(Message)
应用
this.$message({
type: 'success',
content: '胜利信息提醒',
duration: 3000
})
文档:API — Vue.js
对于想要学习前端,然而不晓得从何动手的小伙伴们,我特意筹备了个 qun,整顿了一份最全面的前端学习材料(最根底的【HTML+css+JavaScript】到挪动端的 HTML5 的我的项目实战教程视频),想学习的都能够退出 https://jq.qq.com/?_wv=1027&k…
喜爱的敌人还请点个 star+ 关注~