Vue 开发技巧
记录一下开发中使用的 vue
技巧
# 路由参数解耦
一般在组件内使用路由参数, 大多数人会这样做:
export default {
methods: {
getParamsId() {
return this.$route.params.id
}
}
}
2
3
4
5
6
7
在组件中使用 $route
会使之与其对应路由形成高度耦合, 从而使组件只能在某些特定的 URL
上使用, 限制了其灵活性.
正确的做法是通过 props
解耦
const router = new VueRouter({
routes: [
{
path: '/user/:id',
component: User,
props: true
}
]
})
2
3
4
5
6
7
8
9
将路由的 props
属性设置为 true
后, 组件内可通过 props
接收到 params
参数
export default {
props: ['id'],
methods: {
getParamsId() {
return this.id
}
}
}
2
3
4
5
6
7
8
另外你还可以通过函数模式来返回 props
const router = new VueRouter({
routes: [
{
path: '/user/:id',
component: User,
props: route => ({
id: route.query.id
})
}
]
})
2
3
4
5
6
7
8
9
10
11
文档: 路由组件传参 | Vue Router (opens new window)
# 函数式组件
函数式组件是无状态, 它无法实例化, 没有任何的生命周期和方法. 创建函数式组件也很简单, 只需要在模板添加 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>
2
3
4
5
6
7
8
父组件使用
<template>
<div>
<List :list="list" :itemClick="item => (currentItem = item)"></List>
</div>
</template>
2
3
4
5
import List from '@/components/List.vue'
export default {
components: {
List
},
data() {
return {
list: [
{
title: 'title',
content: 'content'
}
],
currentItem: ''
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# watch
# 触发 watch 监听执行多个方法
使用数组可以设置多项, 形式包括字符串、函数、对象
export default {
data: {
name: 'Joe'
},
watch: {
name: [
'sayName1',
function(newVal, oldVal) {
this.sayName2()
},
{
handler: 'sayName3',
immediate: true
}
]
},
methods: {
sayName1() {
console.log('sayName1==>', this.name)
},
sayName2() {
console.log('sayName2==>', this.name)
},
sayName3() {
console.log('sayName3==>', this.name)
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# watch 监听多个变量
watch 本身无法监听多个变量. 但我们可以将需要监听的多个变量通过计算属性返回对象, 再监听这个对象来实现 "监听多个变量"
export default {
data() {
return {
msg1: 'apple',
msg2: 'banana'
}
},
computed: {
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
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 程序化的事件侦听器
比如, 在页面挂载时定义计时器, 需要在页面销毁时清除定时器. 这看起来没什么问题. 但仔细一看 this.timer
唯一的作用只是为了能够在 beforeDestroy
内取到计时器序号, 除此之外没有任何用处.
export default {
mounted() {
this.timer = setInterval(() => {
console.log(Date.now())
}, 1000)
},
beforeDestroy() {
clearInterval(this.timer)
}
}
2
3
4
5
6
7
8
9
10
如果可以的话最好只有生命周期钩子可以访问到它. 这并不算严重的问题, 但是它可以被视为杂物.
我们可以通过 $on
或 $once
监听页面生命周期销毁来解决这个问题:
export default {
mounted() {
this.createInterval('hello')
this.createInterval('world')
},
createInterval(msg) {
let timer = setInterval(() => {
console.log(msg)
}, 1000)
this.$once('hook:beforeDestroy', function() {
clearInterval(timer)
})
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
使用这个方法后, 即使我们同时创建多个计时器, 也不影响效果. 因为它们会在页面销毁后程序化的自主清除.
文档: 程序化的事件侦听器 (opens new window)
# 外部监听生命周期函数
当我们使用一个第三方组件时, 可能需要监听组件数据的变化, 但是组件又没有提供 change
事件, 那我们怎么在外部监听组件的 updated
的变化呢?
<template>
<!--通过 @hook:updated 监听组件的 updated 生命钩子函数-->
<!--组件的所有生命周期钩子都可以通过 @hook:钩子函数名 来监听触发-->
<custom-select @hook:updated="$_handleSelectUpdated" />
</template>
<script>
import CustomSelect from 'custom-select'
export default {
components: {
CustomSelect
},
methods: {
$_handleSelectUpdated() {
console.log('custom-select 组件的 updated 钩子函数被触发')
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 小项目使用 Vue.observable 替换 Vuex
在前端项目中, 有许多数据需要在各个组件之间进行传递共享, 这时候就需要有一个状态管理工具, 一般情况下, 我们都会使用 Vuex
, 但对于小型项目来说, 就像 Vuex
官网所说: "如果您不打算开发大型单页应用, 使用 Vuex 可能是繁琐冗余的. 确实是如此------如果您的应用够简单, 您最好不要使用 Vuex". 这时候我们就可以使用 Vue2.6
提供的新 API Vue.observable
手动打造一个 Vuex
# 创建 store
import Vue from 'vue'
// 通过 Vue.observable 创建一个可响应的对象
export const store = Vue.observable({
userInfo: {},
roleIds: []
})
// 定义 mutations, 修改属性
export const mutations = {
setUserInfo(userInfo) {
store.userInfo = userInfo
},
setRoleIds(roleIds) {
store.roleIds = roleIds
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 在组件中引用
<template>
<div>
{{ userInfo.name }}
</div>
</template>
<script>
import { store, mutations } from 'store'
export default {
computed: {
userInfo() {
return store.userInfo
}
},
created() {
mutations.setUserInfo({
name: 'Henry'
})
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# api 代理
一般我们都需要在开发环境中设置代理来避免跨域问题, 类似下面这种:
proxyTable: {
// 用 '/api' 开头, 代理所有请求到目标服务器
'/api': {
target: 'https://xxx.com', // 接口域名
changeOrigin: true // 是否启用跨域
}
}
2
3
4
5
6
7
一般项目都是 /api
开头的请求, 但也有项目有多个不同开头的请求, 如 /base
, /user
; 但我们也不能在代理中把这些都写一遍
但我们可以更改 axios
的默认配置 axios.defaults.baseURL = '/api'
, 再在代理中利用路径改写来将 /api
替换为空即可
proxyTable: {
// 用 '/api' 开头, 代理所有请求到目标服务器
'/api': {
target: 'https://xxx.com', // 接口域名
changeOrigin: true, // 是否启用跨域
pathRewrite: { // 路径改写
'^/api': ''
}
}
}
2
3
4
5
6
7
8
9
10
- 01
- 搭配 Jenkins 实现自动化打包微前端多个项目09-15
- 02
- 自动化打包微前端多个项目09-15
- 03
- el-upload 直传阿里 oss 并且显示自带进度条和视频回显封面图06-05