就在今天凌晨 4 点左右,vue-next v3.0.0-beta.1 版本发布,这意味着 Vue 3.0 全家桶正式登场,发布内容包括:javascript
能够看到 Vue 3.0 beta 版本是一个项目系列,包含了咱们在开发过程当中须要的套件、webpack 插件等等,本文将带你们快速搭建基于 Vue 3.0 的项目框架,这和以前不少 Vue 3.0 的 Demo 不一样,是具有商业化项目能力的框架,本文将包括如下内容:css
说个题外话,今天中午我搭建 Vue 3.0 项目时,发现了 vue-router-next 一个 block 级别的 BUG,想在 vue-router-next 项目 issue 中反馈时,发现已经有人提交了类似问题,随后晚上测试时,bug 已经被 fixed,为 Vue 团队的高效点赞,issue 地址,因此当你们发现使用中问题时,能够及时到项目 issue 下进行反馈,这是一支能够信赖的团队!html
Vue 3.0 项目初始化过程和 Vue 2.0 相似,具体步骤以下:vue
第一步,安装 vue-cli:java
npm install -g @vue/cli
复制代码
注意如下命令是错误的!webpack
npm install -g vue
npm install -g vue-cli
复制代码
安装成功后,咱们便可使用 vue 命令,测试方法:git
$ vue -V
@vue/cli 4.3.1
复制代码
第二步,初始化 vue 项目:github
vue create vue-next-test
复制代码
输入命令后,会出现命令行交互窗口,这里咱们选择 Manually select features:web
Vue CLI v4.3.1
? Please pick a preset:
default (babel, eslint)
❯ Manually select features
复制代码
随后咱们勾选:Router、Vuex、CSS Pre-processors 和 Linter / Formatter,这些都是开发商业级项目必须的:vue-router
Vue CLI v4.3.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
复制代码
注意:Vue 3.0 项目目前须要从 Vue 2.0 项目升级而来,因此为了直接升级到 Vue 3.0 全家桶,咱们须要在 Vue 项目建立过程当中勾选 Router 和 Vuex,因此避免手动写初始化代码
回车后会自动安装依赖,为了加速安装速度,咱们可使用淘宝源来加快初始化速度:
vue create -r https://registry.npm.taobao.org vue-next-test
复制代码
项目建立完毕后,目录结构以下:
.
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
└── src
├── App.vue
├── assets
│ └── logo.png
├── components
│ └── HelloWorld.vue
├── main.js
├── router
│ └── index.js
├── store
│ └── index.js
└── views
├── About.vue
└── Home.vue
复制代码
目前建立 Vue 3.0 项目须要经过插件升级的方式来实现,vue-cli 尚未直接支持,咱们进入项目目录,并输入如下指令:
cd vue-next-test
vue add vue-next
复制代码
执行上述指令后,会自动安装 vue-cli-plugin-vue-next 插件(查看项目代码),该插件会完成如下操做:
完成上述操做后,项目正式升级到 Vue 3.0,注意该插件还能支持 typescript,用 typescript 的同窗还得再等等。
下面咱们从项目开发的角度逐步体验 Vue 3.0 的开发流程
项目开发中,咱们一般须要建立新页面,而后添加路由配置,咱们在 /src/views 目录下建立 Test.vue:
<template>
<div class="test">
<h1>test page</h1>
</div>
</template>
<script> export default { } </script>
<style lang="less" scoped> .test { color: red; } </style>
复制代码
以后在 /src/router/index.js 中建立路由配置:
import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: '/test',
name: 'Test',
component: () => import(/* webpackChunkName: "test" */ '../views/Test.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
复制代码
初始化 Vue Router 的过程与 3.0 版本变化不大,只是以前采用构造函数的方式,这里改成使用 createRouter 来建立 Vue Router 实例,配置的方法基本一致,配置完成后咱们还须要在 App.vue 中增长连接到 Test.vue 的路由:
<template>
<div id="app">
<div id="nav">
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link> |
<router-link to="/test">Test</router-link>
</div>
<router-view/>
</div>
</template>
复制代码
启动项目:
npm run serve
复制代码
在浏览器中访问项目地址,此时已经能够跳转到 Test 页面:
Vue 3.0 中定义状态的方法改成相似 React Hooks 的方法,下面咱们在 Test.vue 中定义一个状态 count:
<template>
<div class="test">
<h1>test count: {{count}}</h1>
</div>
</template>
<script> import { ref } from 'vue' export default { setup () { const count = ref(0) return { count } } } </script>
复制代码
Vue 3.0 中初始化状态经过 setup 方法,定义状态须要调用 ref 方法。接下来咱们定义一个事件,用来更新 count 状态:
<template>
<div class="test">
<h1>test count: {{count}}</h1>
<button @click="add">add</button>
</div>
</template>
<script> import { ref } from 'vue' export default { setup () { const count = ref(0) const add = () => { count.value++ } return { count, add } } } </script>
复制代码
这里的 add 方法再也不须要定义在 methods 中,但注意更新 count 值的时候不能直接使用 count++,而应使用 count.value++,更新代码后,点击按钮,count 的值就会更新了:
Vue 3.0 中计算属性和监听器的实现依赖 computed 和 watch 方法:
<template>
<div class="test">
<h1>test count: {{count}}</h1>
<div>count * 2 = {{doubleCount}}</div>
<button @click="add">add</button>
</div>
</template>
<script> import { ref, computed, watch } from 'vue' export default { setup () { const count = ref(0) const add = () => { count.value++ } watch(() => count.value, val => { console.log(`count is ${val}`) }) const doubleCount = computed(() => count.value * 2) return { count, doubleCount, add } } } </script>
复制代码
计算属性 computed 是一个方法,里面须要包含一个回调函数,当咱们访问计算属性返回结果时,会自动获取回调函数的值:
const doubleCount = computed(() => count.value * 2)
复制代码
监听器 watch 一样是一个方法,它包含 2 个参数,2 个参数都是 function:
watch(() => count.value,
val => {
console.log(`count is ${val}`)
})
复制代码
第一个参数是监听的值,count.value 表示当 count.value 发生变化就会触发监听器的回调函数,即第二个参数,第二个参数能够执行监听时候的回调
Vue 3.0 中经过 getCurrentInstance 方法获取当前组件的实例,而后经过 ctx 属性得到当前上下文,ctx.$router 是 Vue 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: {
test: {
a: 1
}
},
mutations: {
setTestA(state, value) {
state.test.a = value
}
},
actions: {
},
modules: {
}
})
复制代码
Vuex 的语法和 API 基本没有改变,咱们在 state 中建立了一个 test.a 状态,在 mutations 中添加了修改 state.test.a 状态的方法: setTestA
第二步,在 Test.vue 中,经过计算属性使用 Vuex 状态:
<template>
<div class="test">
<h1>test count: {{count}}</h1>
<div>count * 2 = {{doubleCount}}</div>
<div>state from vuex {{a}}</div>
<button @click="add">add</button>
</div>
</template>
<script> import { ref, computed, watch, getCurrentInstance } from 'vue' export default { setup () { const count = ref(0) const add = () => { count.value++ } watch(() => count.value, val => { console.log(`count is ${val}`) }) const doubleCount = computed(() => count.value * 2) const { ctx } = getCurrentInstance() console.log(ctx.$router.currentRoute.value) const a = computed(() => ctx.$store.state.test.a) return { count, doubleCount, add, a } } } </script>
复制代码
这里咱们经过计算属性来引用 Vuex 中的状态:
const a = computed(() => ctx.$store.state.test.a)
复制代码
ctx 是上节中咱们提到的当前组件实例
更新 Vuex 状态仍然使用 commit 方法,这点和 Vuex 3.0 版本一致:
<template>
<div class="test">
<h1>test count: {{count}}</h1>
<div>count * 2 = {{doubleCount}}</div>
<div>state from vuex {{a}}</div>
<button @click="add">add</button>
<button @click="update">update a</button>
</div>
</template>
<script> import { ref, computed, watch, getCurrentInstance } from 'vue' export default { setup () { const count = ref(0) const add = () => { count.value++ } watch(() => count.value, val => { console.log(`count is ${val}`) }) const doubleCount = computed(() => count.value * 2) const { ctx } = getCurrentInstance() console.log(ctx.$router.currentRoute.value) const a = computed(() => ctx.$store.state.test.a) const update = () => { ctx.$store.commit('setTestA', count) } return { count, doubleCount, add, a, update } } } </script>
复制代码
这里咱们点击 update a 按钮后,会触发 update 方法,此时会经过 ctx.$store.commit 调用 setTestA 方法,将 count 的值覆盖 state.test.a 的值
经过我第一时间体验 Vue 3.0-beta 版本后,感受 Vue 3.0 已经具有了商业项目开发的必备条件,语法精炼,不论是代码可读性仍是运行效率都很是赞。但因为未深刻使用,目前还没法提出更多问题,须要在项目实战中进一步发现和总结问题,再和你们分享交流。