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 中的一種跨層級傳參方式

系列

相關文章
相關標籤/搜索