前序
Vuejs 3.0 在北京时间2020年9月 19 日凌晨,终于发布了 3.0 版本,代号:One Piece
对于我们日常维护的vue2.5.x版本,尤大并不建议我们来升级它,那么我们又如何快速体验hook带来的体验呢?
用完hook的我,只能说一句真香!!!
再也不担心mixins的乱套,也不用逼逼赖赖的找mixins带来的变量覆盖,找不到变量在哪一次的使用
vue官网也提供了相对应的api,让我们在v2.5.x版本中,可以体验vue3带来的api改变
那就不得不用到vue官网提供的@vue/composition-api了
vue3生命周期
- setup() :开始创建组件之前,在beforeCreate和created之前执行。创建的是data和method
- onBeforeMount() : 组件挂载到节点上之前执行的函数。
- onMounted() : 组件挂载完成后执行的函数。
- onBeforeUpdate(): 组件更新之前执行的函数。
- onUpdated(): 组件更新完成之后执行的函数。
- BeforeUnmount(): 组件卸载之前执行的函数。
- Unmounted(): 组件卸载完成后执行的函数
- Activated(): 被包含在中的组件,会多出两个生命周期钩子函数。被激活时执行。
- onDeactivated(): 比如从 A 组件,切换到 B 组件,A 组件消失时执行。
- onErrorCaptured(): 当捕获一个来自子孙组件的异常时激活钩子函数(以后用到再讲,不好展现)
实践
安装依赖 @vue/composition-api
npm install @vue/composition-api --save
针对现有页面进行改造,举个栗子:login.vue
代码量可能会相对比较多,请耐心查看一下~~~
export default {
data() {
return {
codeUrl: '',
cookiePassword: '',
loginForm: {
username: '',
password: '',
rememberMe: false,
code: '',
uuid: '',
},
loginRules: {
username: [
{ required: true, trigger: 'blur', message: '用户名不能为空' },
],
password: [
{ required: true, trigger: 'blur', message: '密码不能为空' },
],
code: [
{ required: true, trigger: 'change', message: '验证码不能为空' },
],
},
loading: false,
redirect: undefined
}
},
watch: {
$route: {
handler: function (route) {
console.log('111')
},
immediate: true,
},
},
created() {
this.getCode()
this.getCookie()
if (process.env.NODE_ENV !== 'production') {
this.loginForm.username = 'admin'
this.loginForm.password = 'admin123'
}
},
methods: {
getCode() {
getCodeImg().then((res) => {
this.codeUrl = 'data:image/gif;base64,' + res.img
this.loginForm.uuid = res.uuid
})
},
getCookie() {
const username = Cookies.get('username')
const password = Cookies.get('password')
const rememberMe = Cookies.get('rememberMe')
this.loginForm = {
username: username === undefined ? this.loginForm.username : username,
password:
password === undefined ? this.loginForm.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
}
},
handleLogin() {
this.$refs.loginForm.validate((valid) => {
if (valid) {
this.loading = true
if (this.loginForm.rememberMe) {
Cookies.set('username', this.loginForm.username, { expires: 30 })
Cookies.set('password', encrypt(this.loginForm.password), {
expires: 30,
})
Cookies.set('rememberMe', this.loginForm.rememberMe, {
expires: 30,
})
} else {
Cookies.remove('username')
Cookies.remove('password')
Cookies.remove('rememberMe')
}
this.$store
.dispatch('Login', this.loginForm)
.then(() => {
this.$router.push({ path: this.redirect || '/' })
})
.catch(() => {
this.loading = false
this.getCode()
})
}
})
},
}
}
调整 data 方法
为了简单方便演示效果,所以以下处理直接使用reactive,可以根据自己实际项目需要使用
reactive递归监听refshallowRef,shallowReactive非递归监听toRaw不想被监听
等方法,请自行根据api选择
import { reactive, toRefs } from '@vue/composition-api';
export default {
setup() {
let state = reactive({
codeUrl: '',
cookiePassword: '',
loginForm: {
username: '',
password: '',
rememberMe: false,
code: '',
uuid: '',
},
loginRules: {
username: [
{ required: true, trigger: 'blur', message: '用户名不能为空' },
],
password: [
{ required: true, trigger: 'blur', message: '密码不能为空' },
],
code: [
{ required: true, trigger: 'change', message: '验证码不能为空' },
],
},
loading: false,
redirect: undefined,
})
}
return {
...toRefs(state)
}
}
调整 methods 方法
export default {
setup() {
getCode() {
getCodeImg().then(res => {})
}
getCookie() {},
handleLogin() {}
return {
getCode,
getCookie,
handleLogin
}
}
}
调整this.$refs获取
<template>
<el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
</el-form>
</template>
import { onMounted } from '@vue/composition-api'
export default {
setup() {
const loginForm = ref(null)
onMounted(() => {
// 这里就等于我们的 this.$refs
console.log(loginForm.value)
});
return {
loginForm
}
}
}
调整created方法
由于vue3的 beforeCreate 和 created 被调整为 setup,具体生命中取
export default {
setup() {
this.getCode()
this.getCookie()
if (process.env.NODE_ENV !== 'production') {
this.loginForm.username = 'admin'
this.loginForm.password = 'admin123'
}
}
}
调整this
用于vue3的生命周期,setup方法里并没有this概念,因此我们得把页面涉及到this都要做更改
为方便演示,代码中只重写getCode的逻辑写法
<el-form-item prop="code">
<el-input
v-model="loginForm.code"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter.native="handleLogin"
>
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" />
</div>
</el-form-item>
import { ref, reactive, toRefs } from '@vue/composition-api'
export default {
setup() {
let codeUrl = ref('')
// 以下也可以用ref处理,这样在赋值的时候得用 store.value
let store = reactive({
loginForm: {
username: ''
}
})
const getCode = () => {
getCodeImg().then((res) => {
codeUrl.value = 'data:image/gif;base64,' + res.img
store.loginForm.uuid = res.uuid
})
}
return {
codeUrl,
...toRefs(store),
getCode,
}
}
}
$route和$router怎么获取?
由于我们是基于vue2.x版本进行改造的,而vuex,vue-router并没有相对应的升级,所以并不能使用useStore或者Router相关的api方法,因此,$route和$store我们可以从如下获取
setup存在2个参数
export default {
setup(prop, context) {
console.log(prop) // 组件可以拿到父组件传过来的消息
console.log(context) // 当前上下文
let {
$store, // 这个对应 this.$store
$router, // 这个对应 this.$router
$route, // 这个对应 this.$route
$confirm, // 这个是element-ui this.$confirm 的方法
} = context.root;
// 以上变量就可以拿到传递过来的参数了
}
}