Vue 3.0 新特性与使用 一

image

Vue3 新特性

Vue3 的新特性经过 Vue 的做者尤雨溪的视频而来:Vue.js 做者谈 Vue 3.0 beta 现状html

有哪些亮点?

image

  1. 性能提高
  2. Tree-shking 支持,按需打包,更小体积
  3. Composition api 新语法
  4. Fragment,Teleport,Suspense 新组件
  5. 更好的 TypeScript 支持
  6. 自定义渲染器

性能提高

image

image

  1. 重写 Virtual dom,静态标记显著提高性能
  2. 编译时性能优化
  3. 更好的初始化性能
  4. 和 Vue2 相比,更新快了1.2 ~ 2倍
  5. 和 Vue2相比,SSR 快了2 ~ 3倍

Tree-shking

image

  1. 使更多可选的内容能够被 tree-shaking,好比 v-model 和 <transition>如今就能够被tree-shaking了,没有用到的时候,打包就不会被放入项目中;
  2. 模板中只包含一个简单的 Hello World 时,框架为项目带来的大小只增长了 13.5kb。若是采用了 Composition API 支持替代其余 options 的 API 的话,会变成 11.75kb 大小,在 Vue3.0 中为了兼容以前版本,默认不会把 options 的 API 去掉,可是会有开关提供把这些 API 去掉的选项;
  3. 即使是 Vue3.0 的东西都放进去,也只有 22.5kb(包括全部的新功能)。这个大小比 Vue2.x 小,但功能却更多。

Webpack 是有 Tree-shaking 这个功能的,但 Tree Shaking 前提是 ES Module(import…) 来写。Vue 3 在浏览器中,依然会有一个全局的 Vue对象,可是在用 Webpack 的时候,它就没有defualt export,你就不能 import vue,把 Vue 当对象自己去操做,全部的 Api 都要 import 进来。这样使得一些不会被用到的功能不会被引用进来。vue

文件大小变化很明显,22.5KB ~ 13.5KB,若是使用 Composition 新语法,只有 11.75KBreact

Composition api

image

Composition API RFCwebpack

  1. 能和 Options api 一块儿使用,Composition api 能够视为新添加的 Api,不影响已有 Api 的使用,甚至能够跟已有 Api 一块儿使用。
  2. 灵活的逻辑组合与复用,在 Vue2.x 里面,咱们可能会采用 Mixin 来进行逻辑的抽取。Vue3 尽可能使用 Composition api 来抽逻辑。若是是逻辑库的做者,提供可复用逻辑的时候,尽可能也用 Composition api 去提供。

Vue3 在 setup 把一个对象返回,会把对象变成响应式,而后,Vue 在须要的地方去追踪它所用到的响应式的依赖,当依赖变化的时候从新去渲染。(reactive)git

vue 3 里暴露一个新的 Api 叫作 watchEffect,Effect 就是反作用和 React 的 useEffect 相似。github

一些原生的数据结构,好比像数字、Boolean 等,这些就须要用一个东西包装(ref)web

核心:reactive \ ref \ watchEffect \ 其余是这三者的组合使用。算法

Fragment

image

组件再也不须要一个惟一的根节点了vue-cli

Vue 2 模板只有一个单独的根节点。typescript

Vue 3 文字、多个节点、甚至也能够是个v-for,都会自动变成碎片,若是使用渲染函数,也能够直接在渲染函数里面返回一个数组,自动变成一个碎片。

Teleport

image

对标 React Portal

<teleport> 向 Vue 核心添加组件 该组件须要一个目标元素,该元素是经过须要一个 HTMLElementquerySelector 字符串的 prop 提供的。

组件将其子代移动到 DOM 选择器标识的元素 在虚拟 DOM 级别,子级仍然是子代的后代 <teleport>,所以他们能够从其祖先那里得到注入

Suspense

image

异步组件

和 React 的 Suspense 相似

<Suspense>
  <template #default>
    异步的组件
  </template>
  <template #fallback>
    Loading ...(加载状态的组件)
  </template>
</Suspense>
复制代码

更好的 TypeScript 支持

image

image

自定义渲染器

image

Vue3.0 中支持 自定义渲染器 (Renderer):这个 Api 能够用来建立自定义的渲染器, (在以往像 weex 和 mpvue,须要经过 fork 源码的方式进行扩展)

vite

Vue3 提供了一种新工具 vite,它在程序开发阶段,采用了 Koa、Node 开启一个服务和游览器对 import 的支持实现了按需请求加载内容,避免了热更新时长时间的编译过程,这大大提升了开发效率。

固然发布生产的时候,仍是经过 Webpack 进行编译打包流程。

About Vue2.x

image

  1. 最后一个将为版本 2.7
  2. 从 3.0 向后移植兼容的改进
  3. 在 3.0 中删除的功能的弃用警告
  4. LTS(长期支持的版本,会定时发布系统更新) 18个月

Vue3 架构

核心

image

详细

image

Vue3 的三种使用

vue-cli

官方 Cli 工具,记得要升级最新版本

npm install -g @vue/cli
vue create 01-vue3-cli
cd 01-vue3-cli
<!--安装 Vue3 库-->
vue add vue-next
npm run serve
复制代码

webpack

vue-cli 一开始尚未支持的时候,vue 官网整了一个 webpack 的项目配置,直接 clone 便可

git clone https://github.com/vuejs/vue-next-webpack-preview.git 01-vue3-webpack
cd 01-vue3-webpack
npm install 
npm run dev
复制代码

vite

这是一个 Vue 全新的开发工具,是由 Vue 的做者开发的,目的是之后取代 webpack,原理就是利用游览器如今已经支持 ES6 的 import 语法,遇见 import 会发送一个 http 请求去加载文件,vite 拦截这些请求,作一些预编译,就省去了 webpack 漫长的打包时间,提高开发效率。

npm install -g create-vite-app
create-vite-app 01-vue3-vite
cd 01-vue3-vite
npm install
npm run dev
复制代码

运行项目后,打开 http://localhost:3000/ 看一下 network 就会发现,全部的文件都是 import 进行了预编译,而后经过游览器发起请求,作到了天生的按需加载,秒开项目。

Vue3 新语法实战

对比旧 Vue2 Option api

<template>
  <div>
    <h1>{{state.count}} * 2={{double}}</h1>
    <button @click="add">累加</button>
  </div>
</template>
<script>

export default {
  data: () => ({
    state: {
      count: 1
    }
  }),
  computed: {
    double() {
      return this.state.count * 2;
    }
  }
  methods: {
    add() {
      this.state.count++;
    }
  }
}
</script>
复制代码

从上面的简单例子能够看到,在 Vue2 的处理方式就是这样的。

下面咱们看一下改用 Vue3 的 Composition api 模式

Composition api 新语法体验

<template>
  <h1>{{state.count}} * 2={{double}}</h1>
  <button @click="add">累加</button>
</template>
<script>
import {reactive,computed} from 'vue'

export default {
  setup(){
    const state = reactive({
      count:1
    })
    function add(){
      state.count++
    }
    const double = computed(()=>state.count*2)
    return {state,add,double}
  }
}
</script>
复制代码

Composition api 的方式写,从上面例子中,虽然看不出来有什么好处,那是由于组件规模还不是很庞大,其实在组件变得愈来愈庞大以后,优点就会愈来愈明显了,后续会展现出来。

Composition api 相比于 Option api 模式有什么区别

setup

setup 是新的选项,能够理解是 Composition 的入口,函数内部在 beforeCreate 以前调用,函数返回的内容会做为模板渲染的上下文

reactive

其实和 Vue2 里的 Vue.observerable 是同样的,把一个数据变成响应式,这个能力是彻底独立的。

关于 Vue.observerable 的用法看这里:cn.vuejs.org/v2/api/#Vue…

computed

其实就是一个计算属性,和 Vue2 的能力是同样的

功能拆分,全局 import

Vue2 里面的 datamethodscomputed 都是挂载在 this 之上的,有两个明显的缺点

  1. 不利于类型推导
  2. 若是一个项目没有用到 computed 功能,代码也会被打包

Vue3 的按需手动 import 写法更有利于 Tree-shaking 打包

ref

在 Vue3 中 reactive 负责复杂的数据结构,ref 能够吧基本的数据结构包装成响应式的

<template>
  <h1>{{state.count}} * 2={{double}}</h1>
  <h2>{{num}}</h2>
  <button @click="add">累加</button>
</template>
<script>
import {reactive,computed,ref,onMounted} from 'vue'

export default {
  setup(){
    const state = reactive({
      count:1
    })
    const num = ref(2)

    function add(){
      state.count++
      num.value+=10
    }
    const double = computed(()=>state.count*2)

    onMounted(()=>{
      console.log('mouted')
    })
    

    return {state,add,double,num}
  }
}
</script>
复制代码

能够看到,当要包装独立基本数据类型的时候,就可使用上 ref

抽离功能块

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


export default {
  setup(){

    const {state,double} = useCounter(1)
    const num = ref(2)
    function add(){
      state.count++
      num.value+=10
    }
    onMounted(()=>{
      console.log('mouted')
    })
    return {state,add,double,num}
  }
}

function useCounter(count,n){
    const state = reactive({
      count
    })
    const double = computed(()=>state.count*2)
    return {state,double}
}
</script>
复制代码

这里能够看到,这样写的话,就很像 React 的 Hook 写法了,这样的作法在后续项目愈来愈庞大的时候就能体现出很好的优点出来了。

总结

看了上面的各类写法后,当咱们在开发一个组件的时候,须要把数据放到 data,把计算属性放到 computed,把方法放到 methods,这种作法虽说将不一样的功能对应放到响应的位置,但也带来了一个问题,当组件十分庞大的时候,会发现对组件的维护变得十分难受,当修改一个功能时须要在组件上下处处去翻腾,先后修改代码,这也是 大圣老师 所说的上下反复横跳的问题。

能够看看官方的例子:

Vue2 组件 VS Vue3 组件

// 更改成 Vue3 写法后
export default {
  setup () {
    // Network
    const { networkState } = useNetworkState()
    // Folder
    const { folders, currentFolderData } = useCurrentFolderData(networkState)
    const folderNavigation = useFolderNavigation({ networkState, currentFolderData })
    const { favoriteFolders, toggleFavorite } = useFavoriteFolders(currentFolderData)
    const { showHiddenFolders } = useHiddenFolders()
    const createFolder = useCreateFolder(folderNavigation.openFolder)
    // Current working directory
    resetCwdOnLeave()
    const { updateOnCwdChanged } = useCwdUtils()
    // Utils
    const { slicePath } = usePathUtils()
    return {
      networkState,
      folders,
      currentFolderData,
      folderNavigation,
      favoriteFolders,
      toggleFavorite,
      showHiddenFolders,
      createFolder,
      updateOnCwdChanged,
      slicePath
    }
  }
}
复制代码

优点就因而可知了。

新事物

Fragment

这个功能呢就是 Vue 组件能够不用必定要一个根节点了,能够这样写:

<template>
    <h1>H1</h1>
    <div>Div</div>
</template>
复制代码

这种写法在 Vue2 中是会报错的

下面再来看一个快速排序算法组件小例子:

<template>
   <quick :data="left" v-if="left.length"></quick>
   <li>{{flag}}</li>
   <quick :data="right" v-if="right.length"></quick>
</template>
<script>
export default {
    name:'quick',
    props:['data'],
    setup(props){
        let flag = props.data[0]
        let left = []
        let right = []
        props.data.slice(1).forEach(v=>{
            v>flag? right.push(v): left.push(v)
        })
        return {left, right, flag}
    }
}
</script>
复制代码
<ul>
  <FragmentDemo :data="[5,3,1,6,9,4,2,8]" />
</ul>
复制代码

运行后的结果呈现出来是这样的:

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
</ul>
复制代码

Teleport

这个组件和 React 的 Portal 组件是相似的,用起来比较简单,就是能够渲染 vue 组件的内容,到指定的 dom 节点中。

在作弹窗的时候,比较有用,由于每每,咱们的弹窗都须要渲染到最外层的 body 下面,不然嵌套过多,蒙层可能会被父元素的 transform 影响。

经常使用场景:公共的模态框 Modal

下面来看一下小例子:

<template>
	<h1>{{ msg }}</h1>
	<div class="confirm-modal">
		<button @click="isOpen = true">打开</button>
		<!-- 注意这一块代码 -->
		<Teleport to="#modal-container">
			<div class="modal-warp" v-if="isOpen">
				<div class="cover"></div>
				<div class="content">
					<p>我在外部哦</p>
					<button @click="isOpen = false">取消</button>
				</div>
			</div>
		</Teleport>
	</div>
</template>

<script>
import { ref } from 'vue';

export default {
	name: 'HelloWorld',
	props: {
		msg: {
			type: String,
			default: 'Teleport 使用案例',
		},
	},
	setup() {
		const isOpen = ref(false);
		return { isOpen };
	},
};
</script>
<style>
.modal-warp {
	position: fixed;
	width: 100%;
	height: 100%;
	top: 0;
	left: 0;
	display: flex;
	justify-content: center;
	align-items: center;
}
.cover {
	position: absolute;
	width: 100%;
	height: 100%;
	background-color: rgba(0, 0, 0, 0.2);
}
.content {
	position: absolute;
	padding: 16px 32px;
	background-color: white;
	border-radius: 4px;
}
</style>
复制代码

上面的 <Teleport to="#modal-container"> 表示,接下来将会把里面的内容渲染到 id 为 modal-container 的 dom 节点中。

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<link rel="icon" href="/favicon.ico" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Vite App</title>
	</head>
	<body>
		<div id="app"></div>
		<div id="modal-container"></div>
		<script type="module" src="/src/main.js"></script>
	</body>
</html>
复制代码

运行的效果就是这样滴:

image  image

Suspense

Suspense 的功能是一个异步组件加载的功能,这个在 React 中也存在一个相似

React

import React, { Suspense } from 'react';

const OtherComponent = React.lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <OtherComponent />
      </Suspense>
    </div>
  );
复制代码

Vue3

<Suspense>
  <template #default>
    异步的组件
  </template>
  <template #fallback>
    加载状态的组件
  </template>
</Suspense>
复制代码

这里也将展现一个小例子:

父组件

<template>
	<h1>Supense</h1>
	<Suspense>
		<template #default>
			<AsyncComponent :timeout="3000" />
		</template>
		<template #fallback>
			<h1>加载中</h1>
		</template>
	</Suspense>
</template>

<script>
import AsyncComponent from './AsyncComponent.vue';
export default {
	components: {
		AsyncComponent,
	},
};
</script>
复制代码

AsyncComponent 组件

<template>
	<h1>一个异步小组件</h1>
</template>

<script>
function sleep(timeout) {
	return new Promise((resolve) => setTimeout(resolve, timeout));
}
export default {
	name: 'AsyncComponent',
	props: {
		timeout: {
			type: Number,
			required: true,
		},
	},
	async setup(props) {
		await sleep(props.timeout);
	},
};
</script>
复制代码

这样基本就能体现出来了,运行结果以下:

 

Vue3 相关问题

一、vue3 中新增 setup() 函数代替了 2.x 版本的什么函数?

答:

  1. beforeCreate
  2. created

二、vue3 对 vue2 进行了那些改变?

答:

  1. 使用了 proxy 代替了 Object.defineProperty
  2. 新增 Composition Api
  3. 让 vue 更快的优化
  4. 更好的 ts 支持,vue3 直接用 ts 重写

三、vue3 有哪些优势

答:

  1. 更容易维护
  2. 更多的原生支持
  3. 更易于开发使用

四、Vue3 更新内容

答:

  1. Vue3 会兼容以前的写法,Composition API 也是可选的
  2. 为了继续支持 IE11,Vue3 将发布一个支持旧观察者机制和新 Proxy 版本的构建
  3. Vue3 不只会使用 TypeScript,并且许多软件包将被解耦,使全部内容更加模块化

五、Vue3 将使用 ES2015 Proxy 做为其观察者机制?

答:

七、关于 Vue 的生命周期

答:

页面首次加载会触发 beforeCreate、created、beforeMount、mounted、beforeUpdate、updated

正确的是:

beforeCreate、created、beforeMount、mounted

八、如下属于 Vue 组件通讯方式正确项是?

  1. props
  2. context
  3. provide / inject
  4. a t t r s / attrs / listeners

答:

  1. props
  2. provide / inject
  3. a t t r s / attrs / listeners

解析:

context 属于 react 中的一种跨层级传参方式

系列

相关文章
相关标签/搜索