该系列是为了让看过Vue官方文件或学过Vue但是却不知道怎麽下手去重构现在有的网站而去规画的系列文章,在这边整理了许多我自己使用Vue重构很多网站的经验分享给读者们。
Vue3 的 Composition Api 可以说是改变了原本的 Option Api 撰写上面的方式,还有撰写 Vue 上面的一些思维的变动。
所以今天如果我们接手了一个 Vue2 的专案要升级成 Veu3 Composition Api 的话,我们可以先从甚麽地方下手,会需要注意那些地方,然後要怎麽去改写 Option Api,我们马上来看一下。
跟以往的 Option Api 不同,我们可以在 setup 函式里面去定义我们所有的东西,包含data
、methods
、computed
、lifecycle
等方法。
<script>
export default {
setup(){
return {}
}
}
</script>
我们在改写的时候会先来看一下有多少被定义的资料,这边是我们在 Option Api 里面定义的资料的部分。
<script>
export default {
data(){
return {
userData: {
name: '',
age: '',
address: '',
},
isOpen: false,
products: []
}
}
}
</script>
我们接下来来用 Vue3 的方式来改写 ,就会像这样。
<script>
import { ref, reactive } from "vue";
export default {
setup() {
const isOpen = ref(false)
const products = ref([])
const userData = reactive({
name: '',
age: '',
address: '',
})
return {}
},
};
</script>
在这边你会看到我定义资料是用 ref
跟 reactive
来定义的,关於我们该如何选用 ref
跟 reactive
呢 ? 在大多数的情况下两者皆可以互相替换使用,主要取决於个人喜好或是团队习惯,根据具体情况来决定要使用哪个好,关於 ref
跟 reactive
的差异我们来看一下 :
ref
: 可以使用任何型态的资料,但是不会对 Object
或是 Array
内部的属性做监听。reactive
: 只接受 Object
或 Array
,可以做深层的监听,以及取资料的时候不用使用 .value
,但是如果对 reactive 的 Object 使用解构的方式取得内容,就会失去了 Vue 更新绑定的机制。我自己个人一般的情况下能尽量使用 ref
就使用ref
,可以更精准地去控制资料的更新,很多人不习惯用 .value
的方式,但是 .value
的方式可以让开发者更明确知道这段 code 再进行资料的更新。
更多具体的细节可以参考我之前写的这篇文章 ref 跟 reactive 我该怎麽选 !?
一般我们要定义 methods 会在 methods 这个栏位里面去定义它的 function,然後要 get
、set
可以透过 this
来使用,这个 this
就是指向 Vue 本身。
<script>
export default {
data(){
return {
userData: {
name: '',
age: '',
address: '',
},
isOpen: false,
products: []
}
},
methods: {
handleTroggle(){
this.isOpen = !this.isOpen
},
setProducts(prod){
this.products = prod
},
showUserKey(){
this.userData.name = 'mike'
console.log(this.userData.name)
}
}
}
</script>
但是改成 Composition Api 的方式就不需要写在 methods 里面,也不需要管 this 指向的部分,整体下来看起来乾净很多。
<script>
import { ref, reactive } from "vue";
export default {
setup() {
const isOpen = ref(false)
const products = ref([])
const userData = reactive({
name: '',
age: '',
address: '',
})
const handleTroggle = () => {
isOpen.value = !isOpen.value
}
const setProducts = (prod) => {
products.value = prod
}
const showUserKey = () => {
userData.name = 'mike'
console.log(userData.name)
}
return {}
},
};
</script>
以前我们会把共用的 function 或是 data 给放到 mixins,但是 mixins 最让人诟病的是对於来源的查找很不明确,只能靠 coding style 来做区别,所以我们要透过 Composition Api 的方式来处理共用的 function 。
先新增一个 myMixin.vue
的档案
// myMixin.vue
<script>
export default {
data(){
return {
point: 0
}
},
methods: {
addPoint() {
this.point += 1
}
}
}
</script>
然後再我们的 Component 去载入 myMixin.vue
// app.vue
<script>
import myMixin from "./myMixin.vue";
export default {
mixins: [myMixin],
data(){
...
},
methods: {
...
}
}
</script>
<template>
<div id="app">
<h1>Point: {{ point }}</h1>
<button @click="addPoint">click</button>
</div>
</template>
上面就是一般我们使用 mixins
的方式,虽然方便,但是如果多个 Component 的引入跟使用也会造成管理上的不方便,所以接下来我们使用 composition Api 来包装它。
先新增一个名叫 useAddPoints.js
的档案
import { ref, readonly } from "vue"
export function useAddPoints(){
const point = ref(0)
const addPoint = () => {
point.value += 1
}
return {
point: readonly(point),
addPoint
}
}
这边使用了 readonly
最主要是希望这个传出去的值是只可以get
读取的,所以在这边把它给用 readonly
包起来,关於 readonly
的细节可以参考官方的文件
官方文件 : https://v3.vuejs.org/api/basic-reactivity.html#readonly
然後要使用的话就像是这样,非常的简单明了,完全解决了使用 mixins
上面来源不清楚的问题。
<script>
import { useAddPoints } from "../composition/useAddPoints.js"
export default {
setup() {
const { point, addPoint } = useAddPoints();
return {
point,
addPoint
}
},
};
</script>
<template>
<div id="app">
<h1>Point: {{ point }}</h1>
<button @click="addPoint">click</button>
</div>
</template>
我们在 Option Api 里面有许多的 lifecycle
可以用,但是到了 composition Api
里面就有了一些变化,所以今天让我们来稍微看一下这些变化,也好在转移程序码的时候避免发生一些问题。
<script>
export default {
beforeCreate(){},
created(){},
beforeMount(){},
mounted(){},
updated(){},
destroyed(){}
}
</script>
但是在 composition Api
里面我们要从 vue 里面把 lifecycle
取出来在setup
使用。
<script>
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onUnmounted
} from "vue"
export default {
setup() {
onBeforeMount(()=> {})
onMounted(()=> {})
onBeforeUpdate(()=> {})
onUpdated(()=> {})
onUnmounted(()=> {})
return {}
},
};
</script>
不过这边要特别注意,原本 Veu2 里面 destroyed
这个生命周期函式再 Vue3 里面 改名叫做 onUnmounted
,然後原本的 beforeCreate
、created
没了, 现在的 setup
这个函式就等同於 beforeCreate
、created
这两个效果一样,合再一起了。
更多完整的生命周期函式可以参考官方文件的部份
https://v3.vuejs.org/guide/composition-api-lifecycle-hooks.html#lifecycle-hooks
所以我今天如果是要在 created
里面去打 API,我就可以直接在 setup
里面去做操作
<script>
import { ref } from 'vue'
import axios from "axios"
export default {
setup() {
const userData = ref([])
// 等同於再 created 执行
axios.get("https://test.demo.com/api/getUser").then((res)=> {
userData.value = res.data
})
return {
userData
}
},
};
</script>
或是今天你要移除原生 JS 监听的时候,就可以改用 onUnmounted
<script>
import { onMounted, onUnmounted } from 'vue'
import axios from "axios"
export default {
setup() {
const handleWinReSize = (e) => {
console.log(e)
}
onMounted(()=> {
window.addEventListener("resize", ,handleWinReSize)
})
// 等同於 Vue2 的 destroyed
onUnmounted(()=> {
window.removeEventListener("resize", ,handleWinReSize)
})
return { }
},
};
</script>
以前在 Option Api 上面的时候都要透过 this 的方式来取得 props 还有使用 emit,但是在 Composition Api 里面可以统一透过 setup 函式来取得这两个物件。
定义好 props 传入的内容,我们就可以从 setup 正确的取得 props ,它会从 setup 的第一个参数传入。
<script>
import { onMounted } from 'vue'
export default {
props: {
userType: {
type: String,
default: "user"
}
},
setup(props) {
onMounted(()=> {
console.log(props.userType)
})
return { props }
},
};
</script>
<template>
<h1>{{ props.userType }}</h1>
</template>
emit 再 setup 的第二个参数的物件里面,我们可以透过解构的方式直接取出,然後使用。
<script>
export default {
emits: ['userName'],
setup(props, { emit }) {
const getUserName = (name) => {
emit("userName", name)
}
return { getUserName }
},
};
</script>
<template>
<button @click="getUserName('mike')">mike</button>
<button @click="getUserName('jacky')">jacky</button>
<button @click="getUserName('andy')">andy</button>
<button @click="getUserName('scars')">scars</button>
<button @click="getUserName('ash')">ash</button>
</template>
重构这件事情不是一个小工程,它里面有很多需要注意的细节在里面,包括如何读懂人家的逻辑以及理解这个功能开发上面的前因後果,还有就是你的经验的展现,各种问题、各种情境,除了程序码语法版本上面的差异外,还有很多都是要下功夫的,再後面的章节,我会再一一的跟大家介绍关於重构专案上面其他需要注意的地方,还有我的思考规划的方式,以及选用技术的考量等。
Ps. 购买的时候请登入或注册该平台的会员,然後再使用下面连结进入网站点击「立即购课」,这样才可以让我获得更多的课程分润,还可以帮助我完成更多丰富的内容给各位。
我有开设了一堂专门针对Vue3从零开始教学的课程,如果你觉得不错的话,可以购买我课程来学习
https://hiskio.com/bundles/9WwPNYRpz?s=tc
那如果对於JS基础不熟的朋友,我也有开设JS的入门课程,可以参考这个课程
https://hiskio.com/bundles/b9Rovqy7z?s=tc
Mike 的 Youtube 频道
Mike的medium
MIke 的官方 line 帐号,好友搜寻 @mike_cheng
<<: Genero:源於4GL的低代码开发平台(Low Code Development Platform)
>>: Day 02 注册 Azure 帐号与套件安装- 免费体验30天
前言 本章节,将会介绍本系列文章的实验操作环境以及一些设定与建置的步骤。 实验操作环境介绍 实验操作...
元件介绍 Progress bar 是能够展示当前进度的进度条元件。当一个操作需要显示目前百分比,或...
今天来做储存帐密和自动登入的功能。 提醒:今天的内容缺少了加密储存密码,是极度危险的功能,这部份预计...
嘿~~ 各位好,我是菜市场阿龙! Youtube 频道:https://www.youtube.co...
这次写了自己刚学一年半左右的前端框架搭配测试, 小菜鸟的技术上还没有到很成熟,还请各位看官多多见谅呀...