Vue3.0
Vue3.0是2020年4月剛剛發佈了beta版本的全新Vue版本
項目地址:
https://github.com/kaiqiangren/vue-next-ts-preview
一、Vue3.0與Vue2.0的對比:
優點:
- 將Vue內部的絕大部分api對外暴露,使Vue具備開發大型項目的能力,例如compile編譯api等
- webpack的treeshaking支持度友好
- 使用Proxy進行響應式變量定義,性能提高2-3倍
- 可在Vue2.0中單獨使用composition-api插件,或者直接用它開發插件
- 對typescript支持更加友好
- 面向未來:對於尤雨溪最近創新的vite開發服務器(捨棄webpack、底層爲Koa框架的高性能開發服務器),直接使用的Vue3.0語法
缺點:
- 只支持IE11及以上
- 對於習慣了Vue2.0開發模式的開發者來說,增加了心智負擔,對開發者代碼組織能力有考驗
同時也是能力提升的機會吧,特別喜歡Vue作者的設計初心:讓開發者隨着框架一起成長!
二、Vue3.0正確的打開方式
1、項目搭建
- 需要安裝vue-cli4代最新腳手架,可以通過執行如下npm 命令安裝/更新腳手架版本
npm i @vue/cli -g
- 然後在創建項目後,執行vue add vue-next向項目添加Vue3.0
vue create [projectName]
cd [projectName]
vue add vue-next
- 如下例子爲使用typescript + Vue3.0 開發的項目依賴,也可以直接使用
{
"name": "vue-next-ts-preview",
"version": "0.1.0",
"private": true,
"scripts": {
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"dev": "vue-cli-service serve"
},
"dependencies": {
"core-js": "^3.6.4",
"normalize.css": "^8.0.1",
"vue": "^3.0.0-beta.14",
"vue-router": "^4.0.0-alpha.12",
"vuex": "^4.0.0-beta.2"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^2.26.0",
"@typescript-eslint/parser": "^2.26.0",
"@vue/cli-plugin-babel": "~4.3.0",
"@vue/cli-plugin-eslint": "~4.3.0",
"@vue/cli-plugin-router": "~4.3.0",
"@vue/cli-plugin-typescript": "~4.3.0",
"@vue/cli-plugin-vuex": "~4.3.0",
"@vue/cli-service": "~4.3.0",
"@vue/compiler-sfc": "^3.0.0-beta.1",
"@vue/eslint-config-typescript": "^5.0.2",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^7.0.0-alpha.0",
"node-sass": "^4.12.0",
"sass-loader": "^8.0.2",
"typescript": "~3.8.3",
"vue-cli-plugin-vue-next": "~0.1.2"
}
}
2、使用文檔
- 項目入口main.ts
import { createApp } from 'vue';
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')
3、語法相關
- 響應式變量聲明
import { ref, reactive } from 'vue'
// 方式一: 可傳入任意類型的值,改變值的時候必須使用其value屬性,例 refData.value = 2
const refData = ref(0)
// 方式二: 只能傳入引用類型的值
const data = reactive({
tableData: [
{
name: '姓名1'
}
]
})
// 使用響應式變量前,必須在Vue文件的setup函數中 執行/return 出去
setup (props, context){
return {
refData,
data
}
}
- computed
import { watch, watchEffect, computed } from 'vue'
// 1、創建只讀的計算屬性
const computedCount = computed(() => count.value + 1)
// 2、創建可讀可寫的計算屬性
const computedCount2 = computed({
get: () => writeCount.value + 2,
set: (val) => {
return writeCount.value = val + 2
}
})
// 可以直接修改computed的值,在Vue2.x中無法修改
// computedCount2 = 123
- watch & watchEffect
import { ref, watch, watchEffect } from 'vue'
const count = ref(0)
// watchEffect會自動收集響應式依賴
watchEffect(() => console.log(count.value))
// 監聽指定基礎類型數據
watch(count, (now, prev) => {
console.log(now, prev, 'count')
})
const data = reactive({
tableData: [
{
name: '姓名1'
}
]
})
// 監聽reactive創建的響應式變量,可以直接監聽對象,必須使用內聯函數
watch(() => data.tableData, (now, prev) => {
console.log(now, prev, 'tableData')
})
- provide & inject
import { reactive, provide , inject} from 'vue'
const data = reactive({
tableData: [
{
name: '姓名1'
}
]
})
// 根級/父級組件
// provide 這裏如果提供的是響應式變量,inject也會觸發響應
provide('provideName', 'provideData')
provide('provideReactive', data.tableData)
// 子級/孫級組件
setup () {
const provideData = inject('provideName')
const provideReactive = inject('provideReactive')
return {
provideData,
provideReactive
}
}
- 生命週期
Vue3.0生命週期 說明 對應的Vue2.0生命週期
setup | 初始化數據階段的生命週期,介於beforeCreate與created之間 相當於beforeCreate、created的合併
onBeforeMount | 組件掛載前 beforeMount
onMounted | 實例掛載完畢 mounted
onBeforeUpdate | 響應式數據變化前 beforeUpdate
onUpdated | 響應式數據變化完成 updated
onBeforeUnmount | 實例銷燬前 beforeDestroy
onUnmounted | 實例已銷燬 destroyed
onErrorCaptured | 錯誤數據捕捉 --
- 路由
// 組件內部路由攔截器的使用方式
import { useRouter, useRoute } from "vue-router"
setup() {
// 組件內路由
const router = useRouter()
router.beforeEach((to, from, next) => {
next()
})
// 組件內路由信息
const route = useRoute()
}
7.vuex
創建Store
import { createStore } from 'vuex'
const store = createStore({
state: {
userInfo: {
name:'renkq'
}
},
mutations: {
getUserInfo (state, name) {
state.userInfo.name = name
}
},
actions: {
asyncGetUserInfo ({ commit }) {
setTimeout(() => {
commit("getUserInfo", +new Date() + 'action')
},2000)
}
},
getters: {
userInfoGetter (state) {
return state.userInfo.name
}
}
})
export default store
組件內使用store
import {
useStore,
// mapState,
// mapMutations,
// mapActions,
// mapGetters
} from 'vuex'
export default {
name: 'self',
setup() {
const store = useStore()
console.log(store, 'store')
console.log(store.getters, 'getters')
const state = store.state
const getters = store.getters
// console.log(mapState(store.state),'mapState')
// console.log(mapMutations(store._mutations),'mapMutations')
// console.log(mapActions(store._actions),'mapActions')
// console.log(mapGetters(store.getters),'mapGetters')
const methods = {
// 處理commit
handleMutation: () => {
store.commit('getUserInfo', +new Date)
},
// 處理dispatch
handleAction: () => {
store.dispatch('asyncGetUserInfo')
}
}
return {
state,
getters,
...methods
}
}
}
- v-model
// 自定義v-model組件時,需要使用update:modelValue事件進行觸發
setup(props, { emit }){
const handleClick = () => {
emit('update:modelValue', params)
}
return {
handleClick
}
}
- directive
定義指令
import { ObjectDirective } from 'vue'
// 使用ObjectDirective聲明指令類型即可,因爲源碼內部指定了默認類型說明
export const customDirective: ObjectDirective = {
beforeMount(el, binding, vnode, prevVnode) {
console.log(el, binding, vnode, prevVnode)
},
mounted() { console.log('mounted') },
beforeUpdate() { console.log('beforeUpdate') },
updated() { console.log('updated') },
beforeUnmount() { console.log('beforeUnmount') },
unmounted() { console.log('unmounted') }
}
全局註冊指令
const app = createApp(App)
app.use(router)
app.use(store)
app.directive('custom', customDirective)
app.mount('#app')
組件內使用指令
import { customDirective } from '../../directive/directive'
export default {
setup() {
return {}
},
directives: {
custom: customDirective
}
}
- nextTick
import { nextTick, onBeforeMount } from 'vue'
{
setup () {
onBeforeMount(() => {
nextTick(() => {
})
})
}
}
- 定義組件defineAsyncComponent & defineComponent
同步組件與異步組件的區別:
同步組件:在組件加載時自動加載;
異步組件:在渲染時加載;
// 一、定義同步組件
const syncComponent = defineComponent({
setup () {
return () => `我是同步組件`
}
})
// 二、定義異步組件
// 方式1
const asyncComponent = defineAsyncComponent({
loader: () => import("./asyncComponents.vue"),
loadingComponent: loadingComponent,
errorComponent: loadingComponent,
delay: 2000,
timeout: 3000
});
// 方式2
const asyncComponent = defineAsyncComponent(() => import('./syncComponents.vue'));