Vue3.0+vue-router-next+vuex4.0+typescript專案搭建

happy任發表於2020-04-29

Vue3.0

Vue3.0是2020年4月剛剛釋出了beta版本的全新Vue版本

專案地址:

https://github.com/kaiqiangren/vue-next-ts-preview

一、Vue3.0與Vue2.0的對比:

優點:

  1. 將Vue內部的絕大部分api對外暴露,使Vue具備開發大型專案的能力,例如compile編譯api等
  2. webpack的treeshaking支援度友好
  3. 使用Proxy進行響應式變數定義,效能提高2-3倍
  4. 可在Vue2.0中單獨使用composition-api外掛,或者直接用它開發外掛
  5. 對typescript支援更加友好
  6. 面向未來:對於尤雨溪最近創新的vite開發伺服器(捨棄webpack、底層為Koa框架的高效能開發伺服器),直接使用的Vue3.0語法

缺點:

  1. 只支援IE11及以上
  2. 對於習慣了Vue2.0開發模式的開發者來說,增加了心智負擔,對開發者程式碼組織能力有考驗

同時也是能力提升的機會吧,特別喜歡Vue作者的設計初心:讓開發者隨著框架一起成長!

二、Vue3.0正確的開啟方式

1、專案搭建

  1. 需要安裝vue-cli4代最新腳手架,可以通過執行如下npm 命令安裝/更新腳手架版本
npm i @vue/cli -g
  1. 然後在建立專案後,執行vue add vue-next向專案新增Vue3.0
vue create [projectName]
cd [projectName]
vue add vue-next
  1. 如下例子為使用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、使用文件

  1. 專案入口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、語法相關

  1. 響應式變數宣告
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
  }
}
  1. 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 
  1. 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')
})
  1. 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
  }
}
  1. 生命週期
Vue3.0生命週期         說明                                                   對應的Vue2.0生命週期
setup               | 初始化資料階段的生命週期,介於beforeCreate與created之間  相當於beforeCreate、created的合併
onBeforeMount       | 元件掛載前                                          beforeMount
onMounted           | 例項掛載完畢                                         mounted
onBeforeUpdate      | 響應式資料變化前                                      beforeUpdate
onUpdated           | 響應式資料變化完成                                    updated
onBeforeUnmount     | 例項銷燬前                                           beforeDestroy
onUnmounted         | 例項已銷燬                                           destroyed
onErrorCaptured     | 錯誤資料捕捉                                            --
  1. 路由
// 元件內部路由攔截器的使用方式
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
    }
  }
}
  1. v-model
// 自定義v-model元件時,需要使用update:modelValue事件進行觸發
setup(props, { emit }){
   const handleClick = () => {
      emit('update:modelValue', params)
   }
   return {
      handleClick
  }
}
  1. 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
  }
}
  1. nextTick
import { nextTick, onBeforeMount } from 'vue'

{
  setup () {
    
    onBeforeMount(() => {
      nextTick(() => {
        
      })
    })
    
  }
}
  1. 定義元件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'));

相關文章