vue3.0環(huán)境搭建及特性

一扒腕、環(huán)境搭建

1. Node官網(wǎng)安裝Node诲祸,推薦下載長(zhǎng)期支持版。

檢查是否安裝成功Node颗胡,在cmd輸入 node -v八回。若出現(xiàn)版本號(hào)就是安裝成功酷愧。

查看node版本號(hào).png

安裝完node,會(huì)附帶npm命令缠诅。輸入npm -v 就能查看npm的版本溶浴。
查看npm版本號(hào)

若需要cnpm命令,安裝淘寶鏡像 npm install -g cnpm --registry=https://registry.npm.taobao.org
安裝完成后用cnpm -v查看安裝的版本號(hào)管引。
查看cnpm版本號(hào)

windows若出現(xiàn)問(wèn)題——'cnpm' 不是內(nèi)部或外部命令士败,也不是可運(yùn)行的程序或批處理文件。可以根據(jù)cmd上顯示的cnpm安裝的地址谅将,找到cnpm文件夾拷貝到npm文件夾所在的目錄漾狼。
或 npm config set prefix "npm所在的位置"


cnpm與npm在同一個(gè)位置
2. vue環(huán)境
1.安裝vue和vue-cli腳手架
//最新穩(wěn)定版(安裝和更新的代碼相同)
npm install vue@next
npm install -g @vue/cli
//或一起安裝
npm install -g vue @vue/cli

保證vue/cli版本在4.5.0以上,才能更好的支持3.0饥臂。
用vue -V查看安裝的版本號(hào)檢驗(yàn)是都成功安裝逊躁。


vue/cli版本號(hào)
2. 創(chuàng)建vue項(xiàng)目
npm create  <project-name>

如果想構(gòu)建一個(gè)webpack的vue項(xiàng)目

npm init webpack  <project-name>

也可以使用 Vite 快速構(gòu)建 Vue 項(xiàng)目(Vite是一個(gè) web 開(kāi)發(fā)構(gòu)建工具,由于其原生 ES 模塊導(dǎo)入方式隅熙,可以實(shí)現(xiàn)閃電般的冷服務(wù)器啟動(dòng))

npm init vite <project-name> -- --template vue

安裝事項(xiàng):這里會(huì)詢(xún)問(wèn)使用哪個(gè)模板進(jìn)行安裝稽煤,我們選擇自定義安裝的方法Manually select features


安裝方法選擇

根據(jù)需要選擇功能


選擇功能

選擇vue版本及其他
選擇vue版本

image.png

安裝完成,系統(tǒng)默認(rèn)npm run serve運(yùn)行


安裝完成

二囚戚、特性

Vue3.0與Vue2.x比酵熙,
1、性能方面有很大的提升——打包大小減少41%驰坊、初次渲染快55%绿店,更新快133%、內(nèi)存使用減少54%(得益于虛擬DOM的重寫(xiě)和Tree-shaking的優(yōu)化)庐橙。
2、使用Composition API借嗽。Vue2.x使用組件選項(xiàng)來(lái)組織邏輯态鳖,隨著復(fù)雜度上升易讀性比較差,Vue3.0使用Composition API按照邏輯分類(lèi)恶导,代碼維護(hù)和易讀性較好浆竭。雖然Vue2.x給出Mixin來(lái)解決這個(gè)問(wèn)題,但是Mixin會(huì)存在命名沖突的問(wèn)題惨寿,不清楚暴露出來(lái)變量的最用及重用邏輯到其他Component經(jīng)常會(huì)遇到的問(wèn)題邦泄。
3、對(duì)TypeScript的支持更好

Tree-shaking

Vue3最重要的變化之一就是引入了Tree-Shaking裂垦,Tree-Shaking帶來(lái)的bundle體積更小是顯而易見(jiàn)的顺囊。在2.x版本中,很多函數(shù)都掛載在全局Vue對(duì)象上蕉拢,比如nextTick特碳、mixin、set等函數(shù)晕换,因此雖然我們可能用不到午乓,但打包時(shí)只要引入了vue這些全局函數(shù)仍然會(huì)打包進(jìn)bundle中。
而在Vue3中闸准,所有的API都通過(guò)ES6模塊化的方式引入益愈,這樣就能讓webpack或rollup等打包工具在打包時(shí)對(duì)沒(méi)有用到API進(jìn)行剔除,最小化bundle體積夷家;
簡(jiǎn)而言之蒸其,Tree-Shaking這個(gè)打包工具在打包的時(shí)候不會(huì)把沒(méi)用到的API打包進(jìn)去敏释。

//dog.vue
export function dogName(){
  return 'dogName'
}
export function dogAge(){
  return 'dogAge'
}
//index.vue  沒(méi)使用dogAge所以dogAge不會(huì)被打包進(jìn)去
import { dogName,dogAge} from './dog'
dogName()

全局API的修改:main.js中能直接發(fā)現(xiàn)這樣的變化:

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

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

創(chuàng)建app實(shí)例方式從原來(lái)的new Vue()變?yōu)橥ㄟ^(guò)createApp函數(shù)進(jìn)行創(chuàng)建枢里;不過(guò)一些核心的功能比如virtualDOM更新算法和響應(yīng)式系統(tǒng)無(wú)論如何都是會(huì)被打包的训堆;這樣帶來(lái)的變化就是以前在全局配置的組件(Vue.component)、指令(Vue.directive)窗骑、混入(Vue.mixin)和插件(Vue.use)等變?yōu)橹苯訏燧d在實(shí)例上的方法但惶;我們通過(guò)創(chuàng)建的實(shí)例來(lái)調(diào)用耳鸯,帶來(lái)的好處就是一個(gè)應(yīng)用可以有多個(gè)Vue實(shí)例,不同實(shí)例之間的配置也不會(huì)相互影響膀曾,且可以完美的支持tree-shaking:

const app = createApp(App)
app.use(/* ... */)
app.mixin(/* ... */)
app.component(/* ... */)
app.directive(/* ... */)

Vue 2.x 中的這些全局 API 受此更改的影響:


受影響的API
setup

先說(shuō)說(shuō) 選項(xiàng)式API和組合式 API县爬。

選項(xiàng)式API

2.x版本采用的是Options API(選項(xiàng)API)。在 props 里面設(shè)置接收參數(shù)添谊,在 data 里面設(shè)置變量财喳,在 computed 里面設(shè)置計(jì)算屬性,在 watch 里面設(shè)置監(jiān)聽(tīng)屬性斩狱,在 methods 里面設(shè)置事件方法

使用 (data耳高、computed、methods所踊、watch) 組件選項(xiàng)來(lái)組織邏輯通常都很有效泌枪。然而,當(dāng)我們的組件開(kāi)始變得更大時(shí)秕岛,邏輯關(guān)注點(diǎn)的列表也會(huì)增長(zhǎng)碌燕。尤其對(duì)于那些一開(kāi)始沒(méi)有編寫(xiě)這些組件的人來(lái)說(shuō),這會(huì)導(dǎo)致組件難以閱讀和理解继薛。
這種碎片化使得理解和維護(hù)復(fù)雜組件變得困難修壕。選項(xiàng)的分離掩蓋了潛在的邏輯問(wèn)題。此外遏考,在處理單個(gè)邏輯關(guān)注點(diǎn)時(shí)慈鸠,我們必須不斷地“跳轉(zhuǎn)”相關(guān)代碼的選項(xiàng)塊。
如果能夠?qū)⑼粋€(gè)邏輯關(guān)注點(diǎn)相關(guān)代碼收集在一起會(huì)更好灌具。而這正是組合式 API 使我們能夠做到的林束。

組合式 API

而Composition API做的就是把同一功能的代碼放到一起維護(hù),這樣我們需要維護(hù)一個(gè)功能點(diǎn)的時(shí)候稽亏,不用去關(guān)心其他的邏輯壶冒,只關(guān)注當(dāng)前的功能。
實(shí)際使用組合式 API 的地方截歉,在 Vue 組件中胖腾,我們將此位置稱(chēng)為 setup。也就是將(生命周期、computed咸作、watch锨阿、provide/inject)寫(xiě)在 setup 里。
注意:
因?yàn)?setup 是圍繞 beforeCreate 和 created 生命周期鉤子運(yùn)行的记罚,所以在生命周期鉤子中編寫(xiě)的任何代碼都應(yīng)該直接在 setup 函數(shù)中編寫(xiě)墅诡。
沒(méi)有this。因?yàn)?code>setup() 是在解析其它組件選項(xiàng)之前被調(diào)用的桐智,所以 setup() 內(nèi)部的 this 的行為與其它選項(xiàng)中的 this 完全不同末早。
setup 選項(xiàng)是一個(gè)接收 propscontext 的函數(shù),此外说庭,我們將 setup 返回的所有內(nèi)容都暴露給組件的其余部分 (計(jì)算屬性然磷、方法、生命周期鉤子等等) 以及組件的模板刊驴。

export default {
  name: "Button",
  setup() {
    const state = reactive({
      count: 1,
    });
    const num = ref(2);
    function add() {
      state.count++;
      num.value += 10;
    }
    const double = computed(() => state.count * 2);
    return {
      state,
      double,
      num,
      add,
    };
  },
};
生命周期

在Vue2.x中有8個(gè)生命周期函數(shù):
beforeCreate姿搜、created、beforeMount捆憎、mounted舅柜、beforeUpdate、updated躲惰、beforeDestroy业踢、destroyed

在vue3中,新增了一個(gè)setup生命周期函數(shù)礁扮,setup執(zhí)行的時(shí)機(jī)是在beforeCreate生命函數(shù)之前執(zhí)行,因此在這個(gè)函數(shù)中是不能通過(guò)this來(lái)獲取實(shí)例的瞬沦;同時(shí)為了命名的統(tǒng)一太伊,將beforeDestroy改名為beforeUnmount,destroyed改名為unmounted逛钻。增加了onRenderTracked,onRenderTriggered兩個(gè)鉤子函數(shù)作追蹤調(diào)試功能僚焦。
同時(shí),我們可以通過(guò)在生命周期函數(shù)前加on來(lái)訪問(wèn)組件的生命周期曙痘。


生命周期鉤子

vue2->vue3.png

三芳悲、新增功能

響應(yīng)式API

要為 JavaScript 對(duì)象創(chuàng)建響應(yīng)式狀態(tài),可以使用 reactive 方法:

import { reactive } from 'vue'

// 響應(yīng)式狀態(tài)
const state = reactive({
  count: 0
})

reactive 相當(dāng)于 Vue 2.x 中的 Vue.observable() API

reactive函數(shù)只接收object和array等復(fù)雜數(shù)據(jù)類(lèi)型边坤。

對(duì)于一些基本數(shù)據(jù)類(lèi)型名扛,比如字符串和數(shù)值等,我們想要讓它變成響應(yīng)式茧痒,我們當(dāng)然也可以通過(guò)reactive函數(shù)創(chuàng)建對(duì)象的方式肮韧,但是Vue3提供了另一個(gè)函數(shù)ref:

import { ref } from 'vue'

const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1

ref 會(huì)返回一個(gè)可變的響應(yīng)式對(duì)象,該對(duì)象作為一個(gè)響應(yīng)式的引用維護(hù)著它內(nèi)部的值,這就是 ref 名稱(chēng)的來(lái)源弄企。該對(duì)象只包含一個(gè)名為 value 的 property超燃。

當(dāng) ref 作為渲染上下文 (從 setup() 中返回的對(duì)象) 上的 property 返回并可以在模板中被訪問(wèn)時(shí),它將自動(dòng)淺層次解包內(nèi)部值拘领。只有訪問(wèn)嵌套的 ref 時(shí)需要在模板中添加 .value

<template>
  <div>
    <span>{{ count }}</span>
    <button @click="count ++">Increment count</button>
    <button @click="nested.count.value ++">Nested Increment count</button>
  </div>
</template>

<script>
  import { ref } from 'vue'
  export default {
    setup() {
      const count = ref(0)
      return {
        count,

        nested: {
          count
        }
      }
    }
  }
</script>

注意:reactive主要負(fù)責(zé)復(fù)雜數(shù)據(jù)結(jié)構(gòu)意乓,而ref主要處理基本數(shù)據(jù)結(jié)構(gòu);但是很多童鞋就會(huì)誤解ref只能處理基本數(shù)據(jù)约素,ref本身也是能處理對(duì)象和數(shù)組的届良。
區(qū)別:在語(yǔ)法層面,兩個(gè)有差異业汰。ref定義的響應(yīng)式數(shù)據(jù)需要用[data].value的方式進(jìn)行更改數(shù)據(jù)伙窃;reactive定義的數(shù)據(jù)需要[data].[prpoerty]的方式更改數(shù)據(jù)。
但是在應(yīng)用的層面样漆,還是有差異的为障,通常來(lái)說(shuō):?jiǎn)蝹€(gè)的普通類(lèi)型的數(shù)據(jù),我們使用ref來(lái)定義響應(yīng)式放祟。表單場(chǎng)景中鳍怨,描述一個(gè)表單的key:value這種對(duì)象的場(chǎng)景,使用reactive跪妥;在一些場(chǎng)景下鞋喇,某一個(gè)模塊的一組數(shù)據(jù),通常也使用reactive的方式眉撵,定義數(shù)據(jù)侦香。

訪問(wèn)響應(yīng)式對(duì)象

vue2.0中,通過(guò)vue.set(object, propertyName, value) 方法向嵌套對(duì)象添加響應(yīng)式 property纽疟。因?yàn)閂ue 無(wú)法檢測(cè) property 的添加或移除罐韩。由于 Vue 會(huì)在初始化實(shí)例時(shí)對(duì) property 執(zhí)行 getter/setter 轉(zhuǎn)化,所以 property 必須在 data 對(duì)象上存在才能讓 Vue 將它轉(zhuǎn)換為響應(yīng)式的污朽。

vue3.0散吵,當(dāng) ref 作為響應(yīng)式對(duì)象的 property 被訪問(wèn)或更改時(shí),為使其行為類(lèi)似于普通 property蟆肆,它會(huì)自動(dòng)解包內(nèi)部值:

const count = ref(0)
const state = reactive({
  count
})

console.log(state.count) // 0

state.count = 1
console.log(count.value) // 1

如果將新的 ref 賦值給現(xiàn)有 ref 的 property矾睦,將會(huì)替換舊的 ref:

const otherCount = ref(2)

state.count = otherCount
console.log(state.count) // 2
console.log(count.value) // 1

當(dāng)我們處理一些大型響應(yīng)式對(duì)象的property時(shí),我們很希望使用ES6的解構(gòu)來(lái)獲取我們想要的值:

let book = reactive({
  name: 'Learn Vue',
  year: 2020,
  title: 'Chapter one'
})
let {
  name,
} = book

name = 'new Learn'
console.log(book.name);// Learn Vue

遺憾的是炎功,使用的 property 的響應(yīng)性丟失枚冗。對(duì)于這種情況,我們需要將我們的響應(yīng)式對(duì)象轉(zhuǎn)換為一組 ref蛇损。這些 ref 將保留與源對(duì)象的響應(yīng)式關(guān)聯(lián):

let book = reactive({
  name: 'Learn Vue',
  year: 2020,
  title: 'Chapter one'
})
let {
  name,
} = toRefs(book)

// 注意這里解構(gòu)出來(lái)的name是ref對(duì)象
// 需要通過(guò)value來(lái)取值賦值
name.value = 'new Learn'
console.log(book.name);// new Learn

使用 readonly 防止更改響應(yīng)式對(duì)象

let book = reactive({
  name: 'Learn Vue',
  year: 2020,
  title: 'Chapter one'
})
const copy = readonly(book);
//Set operation on key "name" failed: target is readonly.
copy.name = "new copy";
響應(yīng)式計(jì)算和偵聽(tīng)
計(jì)算值

有時(shí)我們需要的值依賴(lài)于其他值的狀態(tài)官紫。在vue2.x中我們使用computed函數(shù)來(lái)進(jìn)行計(jì)算屬性肛宋,在vue3中將computed功能進(jìn)行了抽離,它接受一個(gè)getter函數(shù)束世,并為getter返回的值創(chuàng)建了一個(gè)不可變的響應(yīng)式ref對(duì)象:

const num = ref(0);
const double = computed(() => num.value * 2);
num.value++;

console.log(double.value);// 2
double.value = 4// Warning: computed value is readonly

或者酝陈,它可以使用一個(gè)帶有 get 和 set 函數(shù)的對(duì)象來(lái)創(chuàng)建一個(gè)可寫(xiě)的 ref 對(duì)象。

const num = ref(0);
const double = computed({
  get: () => num.value * 2,
  set: (val) => (num.value = val / 2),
});

num.value++;
console.log(double.value);// 2

double.value = 8
console.log(num.value);// 4
偵聽(tīng)

和computed相對(duì)應(yīng)的就是watch毁涉,computed是多對(duì)一的關(guān)系沉帮,而watch則是一對(duì)多的關(guān)系;vue3也提供了兩個(gè)函數(shù)來(lái)偵聽(tīng)數(shù)據(jù)源的變化:watch和watchEffect贫堰。

watch穆壕,它的用法和組件的watch選項(xiàng)用法完全相同,它需要監(jiān)聽(tīng)某個(gè)數(shù)據(jù)源其屏,然后執(zhí)行具體的回調(diào)函數(shù):

import { reactive, ref, watch } from "vue";

const state = reactive({
  count: 0,
});

//偵聽(tīng)時(shí)返回值得getter函數(shù)
watch(
  () => state.count,
  (count, prevCount) => {
    console.log(count, prevCount);  // 1 0
  }
);
state.count++;

const count = ref(0);
//直接偵聽(tīng)ref
watch(count, (count, prevCount) => {
  console.log(count, prevCount, "watch");// 2 0
});
count.value = 2;

如果我們來(lái)偵聽(tīng)一個(gè)深度嵌套的對(duì)象屬性變化時(shí)喇勋,需要設(shè)置deep:true。

一般偵聽(tīng)都會(huì)在組件銷(xiāo)毀時(shí)自動(dòng)停止偎行,但是有時(shí)候我們想在組件銷(xiāo)毀前手動(dòng)的方式進(jìn)行停止川背,可以調(diào)用watch返回的stop函數(shù)進(jìn)行停止。

const count = ref(0);

const stop = watch(count, (count, prevCount) => { 
  console.log(count, prevCount);// 打印1 0蛤袒,2 1 后不執(zhí)行
});

setInterval(()=>{
   count.value++;
}, 1000);
// 停止watch
setTimeout(()=>{
   stop();
}, 2500);

還有一個(gè)函數(shù)watchEffect也可以用來(lái)進(jìn)行偵聽(tīng)熄云,但是都已經(jīng)有watch了,這個(gè)watchEffect和watch有什么區(qū)別呢妙真?他們的用法主要有以下幾點(diǎn)不同:
1缴允、watchEffect不需要手動(dòng)傳入依賴(lài)
2、每次初始化時(shí)watchEffect都會(huì)執(zhí)行一次回調(diào)函數(shù)來(lái)自動(dòng)獲取依賴(lài)
3珍德、watchEffect無(wú)法獲取到原值练般,只能得到變化后的值

const count = ref(0);
const state = reactive({
  year: 2021,
});

watchEffect(() => {
  console.log(count.value);
  console.log(state.year);//0 2021,1,2022...
});
watch([() => state.year, count], (newVal, oldVal) => {
  //[2022, 1]  [2021, 0]
  //[2023, 2]  [2022, 1]...
  console.log(newVal, oldVal);
});
setInterval(() => {
  count.value++;
  state.year++;
}, 1000);
Fragment

所謂的Fragment,就是片段锈候;在vue2.x中薄料,要求每個(gè)模板必須有一個(gè)根節(jié)點(diǎn),所以我們代碼要這樣寫(xiě):

<template>
  <div>
    <span></span>
    <span></span>
  </div>
</template>

或者在Vue2.x中還可以引入vue-fragments庫(kù)晴及,用一個(gè)虛擬的fragment代替div;在React中嫡锌,解決方法是通過(guò)的一個(gè)React.Fragment標(biāo)簽創(chuàng)建一個(gè)虛擬元素虑稼;在Vue3中我們可以直接不需要根節(jié)點(diǎn):

<template>
    <span>hello</span>
    <span>world</span>
</template>
Teleport

可以將插槽中的元素或者組件傳送到頁(yè)面的其他位置。就是在一些嵌套比較深的組件來(lái)轉(zhuǎn)移模態(tài)框的位置势木。雖然在邏輯上模態(tài)框是屬于該組件的蛛倦,但是在樣式和DOM結(jié)構(gòu)上,嵌套層級(jí)后較深后不利于進(jìn)行維護(hù)(z-index等問(wèn)題)啦桌;因此我們需要將其進(jìn)行剝離出來(lái):

<template>
  <button @click="showDialog = true">打開(kāi)模態(tài)框</button>

  <teleport to="#modal">
    //to可以定義最后組件在哪里顯示
    <div class="modal" v-if="showDialog" style="position: fixed">
      我是一個(gè)模態(tài)框
      <button @click="showDialog = false">關(guān)閉</button>
      <child-component :msg="msg"></child-component>
    </div>
  </teleport>
</template>
<script>
export default {
  data() {
    return {
      showDialog: false,
      msg: "hello"
    };
  },
};
</script>
<!DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title></title>
  </head>
  <body>
    <noscript>
    </noscript>
    <div id="app"></div>
    <div id="modal"></div>//teleport組件將加載在這里
    <!-- built files will be auto injected -->
  </body>
</html>

Suspense

Suspense是Vue3推出的一個(gè)內(nèi)置組件溯壶,它允許我們的程序在等待異步組件時(shí)渲染一些后備的內(nèi)容及皂,可以讓我們創(chuàng)建一個(gè)平滑的用戶(hù)體驗(yàn);Vue中加載異步組件其實(shí)在Vue2.x中已經(jīng)有了且改,我們用的vue-router中加載的路由組件其實(shí)也是一個(gè)異步組件:

export default {
  name: "Home",
  components: {
    AsyncButton: () => import("../components/AsyncButton"),
  },
}

在Vue3中重新定義验烧,異步組件需要通過(guò)defineAsyncComponent來(lái)進(jìn)行顯示的定義:

// 全局定義異步組件
//src/main.js
import { defineAsyncComponent } from "vue";
const AsyncButton = defineAsyncComponent(() =>
  import("./components/AsyncButton.vue")
);
app.component("AsyncButton", AsyncButton);


// 組件內(nèi)定義異步組件
// src/views/Home.vue
import { defineAsyncComponent } from "vue";
export default {
  components: {
    AsyncButton: defineAsyncComponent(() =>
      import("../components/AsyncButton")
    ),
  },
};

同時(shí)對(duì)異步組件的可以進(jìn)行更精細(xì)的管理:

export default {
  components: {
    AsyncButton: defineAsyncComponent({
      delay: 100,
      timeout: 3000,
      loader: () => import("../components/AsyncButton"),
      errorComponent: ErrorComponent,
      onError(error, retry, fail, attempts) {
        if (attempts <= 3) {
          retry();
        } else {
          fail();
        }
      },
    }),
  },
};

這樣我們對(duì)異步組件加載情況就能掌控,在加載失敗也能重新加載或者展示異常的狀態(tài)又跛。

四碍拆、非兼容的功能

非兼容的功能主要是一些和Vue2.x版本改動(dòng)較大的語(yǔ)法,在Vue3上可能存在兼容問(wèn)題慨蓝。

v-model

非兼容:用于自定義組件時(shí)感混,v-model prop 和事件默認(rèn)名稱(chēng)已更改:
prop:value -> modelValue;
event:input -> update:modelValue礼烈;
非兼容:v-bind 的 .sync 修飾符和組件的 model 選項(xiàng)已移除弧满,可用 v-model 作為代替;
新增:現(xiàn)在可以在同一個(gè)組件上使用多個(gè) v-model 進(jìn)行雙向綁定此熬;
新增:現(xiàn)在可以自定義 v-model 修飾符庭呜。

<ChildComponent v-model:title="pageTitle" />

<!-- 是以下的簡(jiǎn)寫(xiě): -->

<ChildComponent :title="pageTitle" @update:title="pageTitle = $event" />
v-if 與 v-for 的優(yōu)先級(jí)對(duì)比

2.x 版本中在一個(gè)元素上同時(shí)使用 v-if 和 v-for 時(shí),v-for 會(huì)優(yōu)先作用
3.x 版本中 v-if 總是優(yōu)先于 v-for 生效摹迷。

v-bind合并

在 2.x疟赊,如果一個(gè)元素同時(shí)定義了 v-bind="object" 和一個(gè)相同的單獨(dú)的 property,那么這個(gè)單獨(dú)的 property 總是會(huì)覆蓋 object 中的綁定峡碉。

<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="red"></div>

在 3.x近哟,如果一個(gè)元素同時(shí)定義了 v-bind="object" 和一個(gè)相同的單獨(dú)的 property,那么聲明綁定的順序決定了它們?nèi)绾魏喜Ⅵ昙摹Q句話(huà)說(shuō)吉执,相對(duì)于假設(shè)開(kāi)發(fā)者總是希望單獨(dú)的 property 覆蓋 object 中定義的內(nèi)容,現(xiàn)在開(kāi)發(fā)者對(duì)自己所希望的合并行為有了更好的控制地来。

<!-- template -->
<div id="red" v-bind="{ id: 'blue' }"></div>
<!-- result -->
<div id="blue"></div>

<!-- template -->
<div v-bind="{ id: 'blue' }" id="red"></div>
<!-- result -->
<div id="red"></div>
v-for中ref

在 Vue 2 中戳玫,在 v-for 中使用的 ref attribute 會(huì)用 ref 數(shù)組填充相應(yīng)的 $refs property。當(dāng)存在嵌套的 v-for 時(shí)未斑,這種行為會(huì)變得不明確且效率低下咕宿。

<template>
  <div v-for="item in list" :ref="setItemRef"></div>
</template>
<script>
export default {
  data(){
    list: [1, 2]
  },
  mounted () {
    console.log(this.$refs.setItemRef)  // [div, div]
  }
}
</script>

在 Vue 3 中,此類(lèi)用法將不再自動(dòng)創(chuàng)建 $ref 數(shù)組蜡秽。要從單個(gè)綁定獲取多個(gè) ref府阀,請(qǐng)將 ref 綁定到一個(gè)更靈活的函數(shù)上 (這是一個(gè)新特性):

<template>
  <div v-for="item in 3" :ref="setItemRef"></div>
</template>
<script>
import { reactive, onUpdated } from 'vue'
export default {
  setup() {
    let itemRefs = reactive([])

    const setItemRef = el => {
      itemRefs.push(el)
    }

    onUpdated(() => {
      console.log(itemRefs)
    })

    return {
      itemRefs,
      setItemRef
    }
  }
}
</script>
Data

非兼容:組件選項(xiàng) data 的聲明不再接收純 JavaScript object,而是接收一個(gè) function芽突。
非兼容:當(dāng)合并來(lái)自 mixin 或 extend 的多個(gè) data 返回值時(shí)试浙,合并操作現(xiàn)在是淺層次的而非深層次的 (只合并根級(jí)屬性)。

在 2.x 中寞蚌,開(kāi)發(fā)者可以通過(guò) object 或者是 function 定義 data 選項(xiàng)田巴。但是我們知道在組件中如果data是object的話(huà)會(huì)出現(xiàn)數(shù)據(jù)互相影響钠糊,因?yàn)閛bject是引用數(shù)據(jù)類(lèi)型。
在Vue3中壹哺,data只接受function類(lèi)型抄伍,通過(guò)function返回對(duì)象;同時(shí)Mixin的合并行為也發(fā)生了改變斗躏,當(dāng)mixin和基類(lèi)中data合并時(shí)逝慧,會(huì)執(zhí)行淺拷貝合并:

const Mixin = {
  data() {
    return {
      user: {
        name: 'Jack',
        id: 1
      }
    }
  }
}

const CompA = {
  mixins: [Mixin],
  data() {
    return {
      user: {
        id: 2
      }
    }
  }
}
//2.x
{
  "user": {
    "id": 2,
    "name": "Jack"
  }
}
//3.x
{
  "user": {
    "id": 2
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市啄糙,隨后出現(xiàn)的幾起案子笛臣,更是在濱河造成了極大的恐慌,老刑警劉巖隧饼,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沈堡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡燕雁,警方通過(guò)查閱死者的電腦和手機(jī)诞丽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拐格,“玉大人僧免,你說(shuō)我怎么就攤上這事∧笞牵” “怎么了懂衩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)金踪。 經(jīng)常有香客問(wèn)我浊洞,道長(zhǎng),這世上最難降的妖魔是什么胡岔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任法希,我火速辦了婚禮,結(jié)果婚禮上靶瘸,老公的妹妹穿的比我還像新娘苫亦。我一直安慰自己,他們只是感情好怨咪,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布屋剑。 她就那樣靜靜地躺著,像睡著了一般惊暴。 火紅的嫁衣襯著肌膚如雪饼丘。 梳的紋絲不亂的頭發(fā)上趁桃,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天辽话,我揣著相機(jī)與錄音肄鸽,去河邊找鬼。 笑死油啤,一個(gè)胖子當(dāng)著我的面吹牛典徘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播益咬,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼逮诲,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了幽告?” 一聲冷哼從身側(cè)響起梅鹦,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎冗锁,沒(méi)想到半個(gè)月后齐唆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡冻河,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年箍邮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叨叙。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锭弊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出擂错,到底是詐尸還是另有隱情味滞,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布马昙,位于F島的核電站桃犬,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏行楞。R本人自食惡果不足惜攒暇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望子房。 院中可真熱鬧形用,春花似錦、人聲如沸证杭。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)解愤。三九已至镇饺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間送讲,已是汗流浹背奸笤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工惋啃, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人监右。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓边灭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親健盒。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绒瘦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Vue3官網(wǎng)文檔[https://vue3js.cn/docs/zh/guide/introduction.htm...
    一蘇沨來(lái)閱讀 3,273評(píng)論 0 7
  • 以下文章來(lái)源于程序員成長(zhǎng)指北 ,作者koala 前言 Vue3.0 在去年9月正式發(fā)布了扣癣,也有許多小伙伴都熱情的擁...
    kangaroo_v閱讀 1,703評(píng)論 0 7
  • 性能提升 打包大小減少41% 初次渲染快55%惰帽,更新快133% 內(nèi)存使用減少54% 原因:重寫(xiě)虛擬dom的優(yōu)化和t...
    violet_syls閱讀 3,642評(píng)論 0 6
  • 前言 Vue3.0的步伐越來(lái)越近了,是時(shí)候了解起來(lái)了父虑,雖然嘴上還喊學(xué)不動(dòng)了善茎,但是,身體還得誠(chéng)實(shí)起來(lái)频轿,接著學(xué)垂涯。。航邢。通...
    Mstian閱讀 9,942評(píng)論 1 9
  • 16宿命:用概率思維提高你的勝算 以前的我是風(fēng)險(xiǎn)厭惡者耕赘,不喜歡去冒險(xiǎn),但是人生放棄了冒險(xiǎn)膳殷,也就放棄了無(wú)數(shù)的可能操骡。 ...
    yichen大刀閱讀 6,033評(píng)論 0 4