vue3.0 上手體驗


vue3.0 beta 版本已經發布有一陣子了,是時候上手體驗一波了~

注意,本文所有演示都是基於 vue3.0 beta 版本,不保證后續正式版 api 不改動。等官方文檔出來后,以官網為准。

 

環境搭建

直接使用腳手架,如果本地沒有安裝的可以執行腳手架安裝命令:

npm install -g @vue/cli

如果本地安裝過的,可以嘗試更新一下:

npm update -g @vue/cli

測試 vue-cli 版本:

vue -V
@vue/cli 4.4.1

 

接下來創建一個vue項目:

vue create vue3-demo

在出現的命令交互窗口選擇 Manually select features :

Vue CLI v4.4.1
? Please pick a preset:
  常用配置 (router, vuex, sass, babel, eslint)
  sass (router, vuex, sass, babel, eslint)
  test (less, babel, eslint)
  default (babel, eslint)
❯ Manually select features

隨后勾選以下選項,一般開發商業項目都需要這些:

Vue CLI v4.4.1
? Please pick a preset: Manually select features
? Check the features needed for your project:
 ◉ Babel
 ◯ TypeScript
 ◯ Progressive Web App (PWA) Support
 ◉ Router
 ◉ Vuex
❯◉ CSS Pre-processors
 ◉ Linter / Formatter
 ◯ Unit Testing
 ◯ E2E Testing

回車后根據自己的習慣選擇好,就開始創建項目。注意這時候還是 vue2 的項目環境,接下來就是升級為 vue3 的運行環境。

 

升級為 vue3.0 項目

vue-cli 還沒有直接支持 vue3.0,需要依賴插件升級,輸入指令:

cd vue3-demo
vue add vue-next

執行完上述命令后,會自動安裝 vue-cli-plugin-vue-next 插件,它會將項目升級為 vue3.0 的依賴環境,包括 vue-router 和 vuex 都會升級為 4.x 的版本。

 

最新版 vue-cli 可以直接創建 vue3 項目了(2020.09更新)

今天將 vue-cli 更新到了 4.5.4 版本,發現可以直接創建 vue3 項目了。使用 vue create vue3-demo 命令創建一個測試項目,會出現以下選項:

 可以直接選擇默認的 vue3 配置,也可以選擇最后一項來手動配置,這里演示手動配置,選擇 Manually select features,回車:

根據需要選擇,注意第一項表明了可以選擇 vue 版本,選完后回車:

這里選擇 vue 的版本,直接選擇 3.x 回車即可。這樣就能創建一個基於 vue3 搭建的項目了。

 

vue3.0 新特性體驗

按照上面步驟升級為 vue3.0 項目后,會自動幫我們將一些文件改成 vue3.0 的寫法。

 

升級 vue3 后還是可以使用 vue2 中的寫法,就是說 vue3 保留了 vue2 的開發模式。當然我們學習 vue3 就是為了它的新特性,所以下面所有介紹只關注新特性的改變。

 

創建vue實例

vue3 創建vue實例不需要使用 new 的方式了,來看 src/main.js 文件:

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

createApp(App).use(router).use(store).mount('#app')

現在是函數式風格來創建vue實例,還記得 vue2 是怎么創建實例的嗎,對比下:

// Vue2 創建實例

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'

new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App)
})

你喜歡哪一種方式?我比較喜歡vue3.0的函數式風格。

 

路由

看看路由配置文件:src/router/index.js

import { createRouter, createWebHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

這是升級后路由配置方法,可以看到與 vue2 版本有很大的區別。現在創建路由實例需要手動引入 createRouter 方法,創建 history 模式路由也需要手動引入 createWebHistory 方法,這達到 Tree-Shaking 的目的,即不會把所有的 api 都打包進來,只會打包你用到的 api,vue3 將都會使用這種形式。

 

響應式數據、methods、watch 和 computed

這里應該是改動最大的部分,也是爭議最大的部分,來看看怎么回事。

在vue2版本中,我們聲明響應式數據是這樣的:

// Vue2
export default {
  // ....
  data() {
    return {
      state: {
        count: 0
      }
    };
  },
}

在vue3.0中,需要這樣:

// Vue3
import { ref } from 'vue'
export default {
  setup () {
    const count = ref(0) // 聲明 count,初始值為 0
    const str = ref('hello') // 聲明 str,初始值為 'hello'
    return {
      count,
      str
    }
  }
}

我們要先引入 ref 方法,然后使用它來聲明響應式變量。重要的是,這些操作需要在 setup 函數中進行,而且添加 methods,watch 和 computed 都需要在 setup 中進行。這就跟在vue2中有很大的不同,vue2中我們是使用選項的方式來創建 data、methods、watch 和 computed 的。

 

接下來演示一個計數器的功能,結合 methods、watch 和 computed:

<template>
  <div class="home">
   <p>count: {{count}}</p>
   <p>doubleCount: {{doubleCount}}</p>
   <button @click="add">增加</button>
  </div>
</template>

<script>
import { ref, watch, computed } from 'vue'
export default {
  setup () {
    // 聲明 count 變量,初始值為 0
    const count = ref(0)

    // 定義 add 方法
    const add = () => {
      count.value++
    }

    // 定義 watch,需要手動引入 watch 方法
    watch(
      () => count.value,
      (val, oldVal) => { console.log(`new count: ${val},old count: ${oldVal}`) }
    )

    // 定義computed,同樣需要手動引入 computed 方法
    const doubleCount = computed(() => count.value * 2)

    return {
      count,
      add,
      doubleCount
    }
  }
}
</script>

 

來看這個例子,首先定義方法是可以直接定義在 setup 函數中的,然后 return 出去即可,不知可否注意到在方法里訪問 count 時,是使用 .value 方法訪問的,這里要強調一下,在 setup 中訪問已聲明的響應式變量時,需要使用 .value 方式訪問,包括在 watch 和 computed 中。

 

接下來是定義 watch,需要手動引入 watch 方法,這也是達到了 Tree-Shaking 的目的,使用到什么就引入什么,最后打包也只打包用到的 api,后面的 computed 也同理。

watch方法有兩個參數,都是函數,第一個函數返回要監聽的值,第二個函數是回調函數,它兩個參數分別表示新值和舊值。

 

computed 方法返回計算過的值,最后需要 return 出去。用法如上,還是比較好理解的。

 

你也可以這樣聲明響應式數據(使用 reactive)

前面說到聲明響應式數據,需要使用 ref,其實你也可以使用 reactive 來一次聲明多個變量,下面例子:

<template>
  <div class="home">
    <p>str: {{state.str}}</p>
   <p>count: {{state.count}}</p>
   <button @click="add">增加</button>
  </div>
</template>

<script>
import { reactive } from 'vue'
export default {
  setup () {
    // 引入 reactive,同時定義多個變量
    const state = reactive({
      count: 0,
      str: 'hello'
    })

    // 現在訪問變量,不能使用 .value 方式訪問了
    const add = () => {
      // state.count.value++ // 錯誤
      state.count++
    }

    return {
      state,
      add
    }
  }
}
</script>

 

reactive 和 ref

上面說到 ref 和 reactive,這里再簡單說說。reactive 是接收一個普通對象,返回該對象的響應式代理,它等同於 2.x 中的 Vue.observable()。

const obj = reactive({ count: 0 })

// obj 此時是一個響應式的對象
// 訪問或修改,直接基於 obj.count

 

ref 也是接收一個參數並返回一個響應式且可改變的 ref 對象,一般參數是基礎類型,比如數值或字符串等。如果傳入的參數是一個對象,將會調用 reactive 方法進行深層響應轉換。ref 對象擁有一個指向內部值的單一屬性 .value,即當你要訪問它的值時,需要 .value 拿到它的值。但是如果是在 setup 中返回且用到模板中時,在 {{}} 里不需要加 .value 訪問,在返回時已經自動解套。

<template>
  <div>{{ count }}</div>
</template>

<script>
  export default {
    setup() {
      return {
        count: ref(0), // 這里返回,在模板中無需 .value 訪問值
      }
    },
  }
</script>

 

獲取路由信息

vue3.0 中使用 getCurrentInstance 方法獲取當前組件實例,然后通過 ctx 屬性獲取當前上下文,ctx.$router 是路由實例,而 ctx.$router.currentRoute 就包含當前路由信息。

<script>
import { getCurrentInstance } from 'vue'
export default {
  setup () {
    const { ctx } = getCurrentInstance()
    console.log(ctx.$router.currentRoute.value)
  }
}
</script>

 

vuex

查看文件 src/store/index.js:

import Vuex from 'vuex'

export default Vuex.createStore({
  state: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

發現創建 store 實例的方式改變了,vue2 中是使用 new 的方式:

// Vue2 中創建 store 實例
export default new Vuex.Store({
   // ... 
})

 

一個小例子演示 vue3.0 中使用 store。

創建 store:

import Vuex from 'vuex'

export default Vuex.createStore({
  state: {
    count: 0
  },
  mutations: {
    ADD (state) {
      state.count++
    }
  },
  actions: {
    add ({ commit }) {
      commit('ADD')
    }
  },
  modules: {
  }
})

 

組件中使用 store:

<template>
  <div class="home">
    <p>{{count}}</p>
    <button @click="add">增加</button>
  </div>
</template>

<script>
import { computed } from 'vue'
import { useStore } from 'vuex'
export default {
  setup () {
    const store = useStore()
    const count = computed(() => store.state.count)

    const add = () => {
      store.dispatch('add')
    }

    return {
      count,
      add
    }
  }
}
</script>

可以看到 vuex 的 api 基本沒變化,只是在組件中使用時需要引入 useStore 方法返回 store 實例,其實你也可以在當前組件上下文中獲取 store,如下:

import {getCurrentInstance} from 'vue'

// ...
const store = getCurrentInstance().ctx.$store

 

大概就記錄到這吧,基本涵蓋到了日常使用的方面。等待 vue3.0 的正式版吧。(還是那句話,上面所講只是基於目前 vue3.0 beta 版本,不保證后續 api 不改動,等正式版官方文檔吧)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM