本文將之前採用Vue2.6開發的todoList小項目改造成為Vue3.0編寫,並介紹一下2.x和3.x之間寫法的不同之處。
點擊體驗[1] Github地址:Vue.js2.6版本todoList[2],Vue.js3.0版本todoList[3]
Vue3.x適配大部分Vue2.x的組件配置,也就是說以前我們在Vue2.x針對組件的一些配置項,例如:
export default {
name: 'test',
components: {},
props: {},
data () {
return {}
},
created(){},
mounted () {},
watch:{},
methods: {}
}在Vue3.x中也是可以適配的,對應的相關生命周期方法也可正常執行,但是Vue3.x的一大核心是引入了Vue Composition API[4](組合式API),這使得組件的大部分內容都可以通過setup()方法進行配置,同時Vue Composition API在Vue2.x也可以使用,需要通過安裝@vue/composition-api來使用:
npm install @vue/composition-api
...
import VueCompositionApi from '@vue/composition-api';
Vue.use(VueCompositionApi);下面主要介紹一下採用Vue Composition API來改造採用2.x開發的todoList項目時的新老代碼對比。
如何創建一個Vue3.0的項目首先,安裝vue cli的最新版本,一般是vue cli 4,安裝成功後,調用:
vue create myapp創建一個基於Vue2.x的項目,然後進入項目的根目錄,執行:
vue add vue-next然後就會自動安裝vue-cli-plugin-vue-next[5]插件,完畢之後,myapp項目就會變成一個基於Vue3.0Beta版本的項目框架。
根實例初始化:在2.x中通過new Vue()的方法來初始化:
import App from './App.vue'
new Vue({
store,
render: h => h(App)
}).$mount('#app')在3.x中Vue不再是一個構造函數,通過createApp方法初始化:
import App from './App.vue'
createApp(App).use(store).mount('#app')
ref或者reactive代替data中的變量:在2.x中通過組件data的方法來定義一些當前組件的數據:
...
data() {
return {
name: 'test',
list: [],
}
},
...在3.x中通過ref或者reactive創建響應式對象:
import {ref,reactive} from 'vue'
...
setup(){
const name = ref('test')
const state = reactive({
list: []
})
return {
name,
state
}
}
...ref將給定的值創建一個響應式的數據對象並賦值初始值(int或者string),reactive可以直接定義複雜響應式對象。
methods中定義的方法也可以寫在setup()中:在2.x中methods來定義一些當前組件內部方法:
...
methods: {
fetchData() {
},
}
...在3.x中直接在setup方法中定義並return:
...
setup(){
const fetchData = ()=>{
console.log('fetchData')
}
return {
fetchData
}
}
...
無法使用EventBus:在2.x中通過EventBus的方法來實現組件通信:
var EventBus = new Vue()
Vue.prototype.$EventBus = EventBus
...
this.$EventBus.$on() this.$EventBus.$emit()在3.x中移除了$on, $off等方法(參考rfc[6]),而是推薦使用mitt[7]方案來代替:
import mitt from 'mitt'
const emitter = mitt()
// listen to an event
emitter.on('foo', e => console.log('foo', e) )
// fire an event
emitter.emit('foo', { a: 'b' })由於3.x中不再支持prototype的方式給Vue綁定靜態方法,可以通過app.config.globalProperties.mitt = () => {}方案。
setup()中使用props和this:在2.x中,組件的方法中可以通過this獲取到當前組件的實例,並執行data變量的修改,方法的調用,組件的通信等等,但是在3.x中,setup()在beforeCreate和created時機就已調用,無法使用和2.x一樣的this,但是可以通過接收setup(props,ctx)的方法,獲取到當前組件的實例和props:
export default {
props: {
name: String,
},
setup(props,ctx) {
console.log(props.name)
ctx.emit('event')
},
}注意ctx和2.x中this並不完全一樣,而是選擇性地暴露了一些property,主要有[attrs,emit,slots]。
watch來監聽對象改變2.x中,可以採用watch來監聽一個對象屬性是否有改動:
...
data(){
return {
name: 'a'
}
},
watch: {
name(val) {
console.log(val)
}
}
...3.x中,在setup()中,可以使用watch來監聽:
...
import {watch} from 'vue'
setup(){
let state = reactive({
name: 'a'
})
watch(
() => state.name,
(val, oldVal) => {
console.log(val)
}
)
state.name = 'b'
return {
state
}
}
...在3.x中,如果watch的是一個數組array對象,那麼如果調用array.push()方法添加一條數據,並不會觸發watch方法,必須重新給array賦值:
let state = reactive({
list: []
})
watch(
() => state.list,
(val, oldVal) => {
console.log(val)
}
)
state.list.push(1) // 不會觸發watch
state.list = [1] // 會觸發watch此問題不知是否是Vue3.x特意加上的,有待正式版出來後在驗證。
computed計算屬性:2.x中:
...
computed: {
storeData () {
return this.$store.state.storeData
},
},
...3.x中:
...
import {computed} from 'vue'
setup(){
const storeData = computed(() => store.state.storeData)
return {
storeData
}
}
...
參考資料[1]點擊體驗: https://link.zhihu.com/?target=https%3A//www.nihaoshijie.com.cn/mypro/vue3todo/index.html
[2]Vue.js2.6版本todoList: https://link.zhihu.com/?target=https%3A//github.com/lvming6816077/vue-todo/
[3]Vue.js3.0版本todoList: https://link.zhihu.com/?target=https%3A//github.com/lvming6816077/vue3todo/
[4]Vue Composition API: https://link.zhihu.com/?target=https%3A//composition-api.vuejs.org/zh/api.html
[5]vue-cli-plugin-vue-next: https://link.zhihu.com/?target=https%3A//github.com/vuejs/vue-cli-plugin-vue-next
[6]rfc: https://link.zhihu.com/?target=https%3A//github.com/vuejs/rfcs/blob/master/active-rfcs/0020-events-api-change.md
[7]mitt: https://link.zhihu.com/?target=https%3A//github.com/developit/mitt%23examples--demos