vite + ts 快速搭建 vue3 專案 以及介紹相關特性

筱月發表於2020-11-04

部落格地址:https://ainyi.com/98

Vue3.0,One Piece

接下來得抽空好好學習了

vite

尤大在 Vue 3.0 beta 直播中推薦了 vite 的工具,強調:針對Vue單頁面元件的無打包開發伺服器,可以直接在瀏覽器執行請求的 vue 檔案
很新穎,這篇部落格用它來搭建一個 vue3 的專案試試

Vite 是面向現代瀏覽器,基於原生模組系統 ESModule 實現了按需編譯的 Web 開發構建工具。在生產環境下基於 Rollup 打包

  • 快速冷啟動伺服器
  • 即時熱模組更換(HMR)
  • 真正的按需編譯

node >= 10.16.0

搭建

使用 vite 搭建專案

npm init vite-app <project-name>

安裝 typescript、vue-router@next、axios、eslint-plugin-vue、sass 等相關外掛

配置

vite.config.ts

vite.config.ts 相當於 @vue-cli 專案中的 vue.config.js

我這簡單配置一下:

import path from 'path'

module.exports = {
  alias: {
    '/@/': path.resolve(__dirname, './src')
  },
  optimizeDeps: {
    include: ['lodash']
  },
  proxy: {}
}

Router

在 src 下新建 router 資料夾,並在資料夾內建立 index.ts

import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('/@/views/Home.vue')
  },
  {
    path: '/lifeCycle',
    name: 'lifeCycle',
    component: () => import('/@/views/LifeCycle.vue')
  }
]

export default createRouter({
  history: createWebHistory('/krry/'),
  routes
})

ts types

專案根目錄下新建 tsconfig.json 寫入相關配置

{
  "compilerOptions": {
    ...// 其他配置
    "paths": {
      "/@/*": [
        "src/*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "src/types/images.d.ts",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

src 目錄下新建 types 資料夾,裡面需要配置 ts 的型別

shims-vue.d.ts

declare module '*.vue' {}

images.d.ts

declare module '*.svg'
declare module '*.png'
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.gif'
declare module '*.bmp'
declare module '*.tiff'

main.ts

import { createApp } from 'vue'
import router from '/@/router'

import App from '/@/App.vue'

const app = createApp(App)
app.use(router)
app.mount('#app')

然後就可以快樂地寫程式碼了

vue3 知識

setup

vue3 中用 setup 函式整合了所有的 api;只執行一次,在生命週期函式前執行,所以在 setup 函式中拿不到當前例項 this,不能用 this 來呼叫 vue2 寫法中定義的方法

它將接受兩個引數:props、context

// props - 元件接受到的屬性 context - 上下文 
setup(props, context) {
  return {
    // 要繫結的資料和方法
  }
}

props
setup 函式中的 props 是響應式的,當傳入新的 prop 時,它將被更新
但是,因為 props 是響應式的,不能使用 ES6 解構,因為它會消除 prop 的響應性

如果需要解構 prop,可以通過使用 setup 函式中的 toRefs 來安全地完成此操作

import { toRefs } from 'vue'

setup(props) {
  const { title } = toRefs(props)
  console.log(title.value)
}

context
context 暴露三個元件的 property:{ attrs, slots, emit }
它是一個普通的 JavaScript 物件,不是響應式的,這意味著你可以安全地對 context 使用 ES6 解構

生命週期

通過在生命週期鉤子前面加上 “on” 來訪問元件的生命週期鉤子

因為 setup 是圍繞 beforeCreate 和 created 生命週期鉤子執行的,所以不需要顯式地定義它們
換句話說,在這兩個鉤子中編寫的任何程式碼都應該直接在 setup 函式中編寫

setup() {
  onMounted(() => {
    console.log('元件掛載')
  })

  onUnmounted(() => {
    console.log('元件解除安裝')
  })

  onUpdated(() => {
    console.log('元件更新')
  })

  onBeforeUpdate(() => {
    console.log('元件將要更新')
  })

  onActivated(() => {
    console.log('keepAlive 元件 啟用')
  })

  onDeactivated(() => {
    console.log('keepAlive 元件 非啟用')
  })

  return {}
}

ref、reactive

ref 可以將某個普通值包裝成響應式資料,僅限於簡單值,內部是將值包裝成物件,再通過 defineProperty 來處理的
通過 ref 包裝的值,取值和設定值的時候,需用通過 .value來進行設定
可以用 ref 來獲取元件的引用,替代 this.$refs 的寫法

reactive 對複雜資料進行響應式處理,它的返回值是一個 proxy 物件,在 setup 函式中返回時,可以用 toRefs 對 proxy 物件進行結構,方便在 template 中使用

使用如下:

<template>
  <div>
    <div>
      <ul v-for="ele in eleList" :key="ele.id">
        <li>{{ ele.name }}</li>
      </ul>
      <button @click="addEle">新增</button>
    </div>
    <div>
      <ul v-for="ele in todoList" :key="ele.id">
        <li>{{ ele.name }}</li>
      </ul>
      <button @click="addTodo">新增</button>
    </div>
  </div>
</template>

<script>
import { ref, reactive, toRefs } from 'vue'

export default {
  setup() {
    // ref
    const eleList = ref([])
    function addEle() {
      let len = eleList.value.length
      eleList.value.push({
        id: len,
        name: 'ref 自增' + len
      })
    }

    // reactive
    const dataObj = reactive({
      todoList: []
    })
    function addTodo() {
      let len = dataObj.todoList.length
      dataObj.todoList.push({
        id: len,
        name: 'reactive 自增' + len
      })
    }

    return {
      eleList,
      addEle,
      addTodo,
      ...toRefs(dataObj)
    }
  }
}
</script>

computed、watch

// computed
let sum = computed(() => dataObj.todoList.length + eleList.value.length)
console.log('setup引用computed要.value:' + sum.value)

// watch
watch(
  eleList,
  (curVal, oldVal) => {
    console.log('監聽器:', curVal, oldVal)
  },
  {
    deep: true
  }
)

watchEffect

響應式地跟蹤函式中引用的響應式資料,當響應式資料改變時,會重新執行函式

const count = ref(0)
// 當 count 的值被修改時,會執行回撥
const stop = watchEffect(() => console.log(count.value))

// 停止監聽
stop()

還可以停止監聽,watchEffect 返回一個函式,執行後可以停止監聽

與 vue2 一樣:

const unwatch = this.$watch('say', curVal => {})

// 停止監聽
unwatch()

useRoute、useRouter

import {useRoute, useRouter} from 'vue-router'

const route = useRoute() // 相當於 vue2 中的 this.$route
const router = useRouter() // 相當於 vue2 中的 this.$router

route   用於獲取當前路由資料
router  用於路由跳轉

vuex

使用 useStore 來獲取 store 物件 從 vuex 中取值時,要注意必須使用 computed 進行包裝,這樣 vuex 中狀態修改後才能在頁面中響應

import {useStore} from 'vuex'

setup(){
  const store = useStore() // 相當於 vue2 中的 this.$store
  store.dispatch() // 通過 store 物件來 dispatch 派發非同步任務
  store.commit() // commit 修改 store 資料
    
  let category = computed(() => store.state.home.currentCagegory
  return { category }
}

部落格地址:https://ainyi.com/98

相關文章