vue3.0 上手体验


Posted in Javascript onSeptember 21, 2020

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.0 上手体验

 可以直接选择默认的 vue3 配置,也可以选择最后一项来手动配置,这里演示手动配置,选择 Manually select features,回车:

vue3.0 上手体验

根据需要选择,注意第一项表明了可以选择 vue 版本,选完后回车:

vue3.0 上手体验

这里选择 vue 的版本,直接选择 3.x 回车即可。这样就能创建一个基于 vue3 搭建的项目了。

vue3.0 特性体验

按照上面步骤升级为 vue3.0 项目后,会自动帮我们将一些文件改成 vue3.0 的写法。

创建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 不改动,等正式版官方文档吧)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jquery中focus()函数实现当对象获得焦点后自动把光标移到内容最后
Sep 29 Javascript
优化Jquery,提升网页加载速度
Nov 14 Javascript
JQuery EasyUI 日期控件如何控制日期选择区间
May 05 Javascript
jqGrid表格应用之新增与删除数据附源码下载
Dec 02 Javascript
JavaScript过滤字符串中的中文与空格方法汇总
Mar 07 Javascript
JavaScript程序中的流程控制语句用法总结
May 23 Javascript
jQuery事件与动画基础详解
Feb 23 Javascript
jQuery插件Echarts实现的双轴图效果示例【附demo源码下载】
Mar 04 Javascript
Kindeditor单独调用单图上传增加预览功能的实例
Jul 31 Javascript
bootstrap-table组合表头的实现方法
Sep 07 Javascript
JS库之Three.js 简易入门教程(详解之一)
Sep 13 Javascript
vue列表单项展开收缩功能之this.$refs的详解
May 05 Javascript
微信小程序实现点击页面出现文字
Sep 21 #Javascript
vue pages 多入口项目 + chainWebpack 全局引用缩写说明
Sep 21 #Javascript
理解JavaScript中的Proxy 与 Reflection API
Sep 21 #Javascript
vue实践---根据不同环境,自动转换请求的url地址操作
Sep 21 #Javascript
vue实践---vue不依赖外部资源实现简单多语操作
Sep 21 #Javascript
js节流防抖应用场景,以及在vue中节流防抖的具体实现操作
Sep 21 #Javascript
微信小程序实现翻牌抽奖动画
Sep 21 #Javascript
You might like
PHP初学入门
2006/11/19 PHP
PHP 5.3.0 安装分析心得
2009/08/07 PHP
Apache无法自动跳转却显示目录的解决方法
2020/11/30 PHP
PHP简单读取PDF页数的实现方法
2016/07/21 PHP
php操作redis常见方法示例【key与value操作】
2020/04/14 PHP
HR vs CL BO3 第二场 2.13
2021/03/10 DOTA
JXTree对象,读取外部xml文件数据,生成树的函数
2007/04/02 Javascript
JS 判断代码全收集
2009/04/28 Javascript
jQuery 使用手册(二)
2009/09/23 Javascript
Ext.get() 和 Ext.query()组合使用实现最灵活的取元素方式
2011/09/26 Javascript
Bootstrap CSS组件之下拉菜单(dropdown)
2016/12/17 Javascript
js评分组件使用详解
2017/06/06 Javascript
js图片上传的封装代码
2017/08/01 Javascript
关于vue中watch检测到不到对象属性的变化的解决方法
2018/02/08 Javascript
vue实现分环境打包步骤(给不同的环境配置相对应的打包命令)
2019/06/04 Javascript
python模拟事件触发机制详解
2018/01/19 Python
Python实现的购物车功能示例
2018/02/11 Python
利用Python模拟登录pastebin.com的实现方法
2019/07/12 Python
使用Python快乐学数学Github万星神器Manim简介
2019/08/07 Python
Python读写文件模式和文件对象方法实例详解
2019/09/17 Python
Django中提示消息messages的设置方式
2019/11/15 Python
用python画一只可爱的皮卡丘实例
2019/11/21 Python
Python通过4种方式实现进程数据通信
2020/03/12 Python
Python3 filecmp模块测试比较文件原理解析
2020/03/23 Python
解决安装新版PyQt5、PyQT5-tool后打不开并Designer.exe提示no Qt platform plugin的问题
2020/04/24 Python
详解CSS3中@media的实际使用
2015/08/04 HTML / CSS
印尼美容产品购物网站:PerfectBeauty.id
2017/12/01 全球购物
Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?用contains来区分是否有重复的对象。还是都不用
2013/07/30 面试题
什么是符号链接,什么是硬链接?符号链接与硬链接的区别是什么?
2014/01/19 面试题
社区健康教育实施方案
2014/03/18 职场文书
《埃及的金字塔》教学反思
2014/04/07 职场文书
关于读书的演讲稿500字
2014/08/27 职场文书
幼儿园小班个人工作总结
2015/02/12 职场文书
python实现的web监控系统
2021/04/27 Python
MySQL删除和插入数据很慢的问题解决
2021/06/03 MySQL
python实现局部图像放大
2021/11/17 Python