【Vue3官方教程】🎄萬字筆記 | 同步導學視頻

🔥原版視頻 + 楊村長和然叔的總結分析視頻

🔥語雀完整版

⚡️關注公衆號【前端大班車】 回覆 【vue】索取完整代碼

📺 開篇詞 - ⚡戳我⚡ javascript

1、爲何選擇CompositionAPI

📺 VueMastery原版html

📺 然叔與楊村長的深度解讀前端

1. Vue2的侷限性

  • 組件邏輯膨脹致使的可讀性變差
  • 沒法跨組件重用代碼
  • Vue2對TS的支持有限

想象一下若是咱們編寫一個組件包含🔍搜索和排序另兩個功能vue

在傳統的OptionsAPI中咱們須要將邏輯分散到如下六個部分java

OptionsAPIreact

  • components
  • props
  • data
  • computed
  • methods
  • lifecycle methods

這樣會是咱們編輯一個邏輯不得不在代碼中反覆橫跳web

image-20201111093749891

2. 如何使用CompositionAPI解決問題

最佳的解決方法是將邏輯聚合就能夠很好的代碼可讀性。編程

options

這就是咱們的CompositionAPI語法可以實現的功能。CompositionAPI是一個徹底可選的語法與原來的OptionAPI並無衝突之處。他可讓咱們將相同功能的代碼組織在一塊兒,而不須要散落到optionsAPI的各個角落。設計模式

固然可使用符合API並非表明咱們整個頁面只須要使用一個組件徹底用複合API進行組裝。markdown

image-20201111100007382

咱們仍是須要經過組件將頁面進行合理的分拆。

image-20201111100019079

3. 代碼重用方法PK

Vue2中的跨組件重用代碼,咱們大概會有四個選擇。

3.1 Mixin - 混入

Kapture 2020-11-11 at 10.09.29

代碼混入其實就是設計模式中的混合模式,缺點也很是明顯。

能夠理解爲多重繼承,簡單的說就是一我的如何有兩個父親

​ ❌沒法避免屬性名衝突 - 長鼻子隨誰

​ ❌繼承關係不清晰

3.2 Mixin Factory - 混入工廠

返回一個

image-20201111163512254

✅代碼重用方便

✅繼承關係清洗

3.3 ScopeSlots - 做用域插槽

  • ❌可讀性不高
  • ❌配置複雜 - 須要再模板中進行配置
  • ❌性能低 - 每一個插槽至關於一個實例

3.4 CompositionApi - 複合API

image-20201111165818397

  • ✅代碼量少
  • ✅沒有引入新的語法,只是單純函數
  • ✅異常靈活
  • ✅工具語法提示友好 - 由於是單純函數因此 很容易實現語法提示、自動補償

2、 setup & ref

📺 VueMastery原版

📺 然叔與楊村長的深度解讀

1. 使用CompositionAPI理由

  • ✅更好的Typescript支持
  • ✅在複雜功能組件中能夠實現根據特性組織代碼 - 代碼內聚性👍 好比: 排序和搜索邏輯內聚
  • ✅組件間代碼複用

2. setup是什麼

  • 在如下方法前執行:
    • Components
    • Props
    • Data
    • Methods
    • Computed Properties
    • Lifecycle methods
  • 能夠不在使用難於理解的this
  • 有兩個可選參數
    • props - 屬性 (響應式對象 且 能夠監聽(watch))
import {watch} from "vue"
export defalut {
	props: {
		name: String
	},
	setup(props) {
		watch(() => {
			console.log(props.name)
		})
	}
}
複製代碼
  • context 上下文對象 - 用於代替之前的this方法能夠訪問的屬性

    setup (props,context) {
    	const {attrs,slots,parent,root,emit} = context
    }
    複製代碼

3. ref是什麼

This wraps our primitive in an object allowing up to track。

​ 對基本數據類型數據進行裝箱操做使得成爲一個響應式對象,能夠跟蹤數據變化。

4. 總結

image-20201129123333148

可維護性明顯提升

  • 能夠控制哪些變量暴露

  • 能夠跟中哪些屬性被定義 (屬性繼承與引用透明)

3、Methods

📺 VueMastery原版

📺 然叔與楊村長的深度解讀

1. 基礎用法

添加方法以下:

image-20201129124845324

2. 自動拆裝箱總結

image-20201129125456248

  • JS :須要經過.value訪問包裝對象
  • 模板: 自動拆箱

4、 Computed - 計算屬性

📺 VueMastery原版

📺 然叔與楊村長的深度解讀

這個地方實在沒什麼好講的,和Vue2沒變化

<template>
  <div>
    <div>Capacity: {{ capacity }}</div>
    <p>Spases Left: {{ sapcesLeft }} out of {{ capacity }}</p>
    <button @click="increaseCapacity()">Increase Capacity</button>
  </div>
</template>

<script> import { ref, computed, watch } from "vue"; export default { setup(props, context) { const capacity = ref(3); const attending = ref(["Tim", "Bob", "Joe"]); function increaseCapacity() { capacity.value++; } const sapcesLeft = computed(() => { return capacity.value - attending.value.length; }); return { capacity, increaseCapacity, attending, sapcesLeft }; }, }; </script>

複製代碼

5、Reactive - 響應式語法

📺 VueMastery原版

📺 然叔與楊村長的深度解讀

以前reactive 的 Ref 去聲明全部的響應式屬性

import { ref,computed } from 'vue'
export default {
  setup(){
    const capacity = ref(4);
    const attending = ref(["Tim","Bob","Joe"]);
    const spacesLeft = computed(()=>{
      return capacity.value - attending.value.length
    })
    function increaseCapacity(){ capacity.value ++;}
    return { capacity,increaseCapacity,attending,spacesLeft}
  }
}
複製代碼

可是有另外一個等效的方法用它去代替 reactive 的Ref

import { reactive,computed } from 'vue'
export default {
  setup(){
    const event = reactive({
      capacity:4,
      attending:["Tim","Bob","Joe"],
      spacesLeft:computed(()=>{
        return event.capacity - event.attending.length;
      })
    })
  }
}
複製代碼

過去咱們用vue2.0的data來聲明響應式對象,可是如今在這裏每個屬性都是響應式的包括computed 計算屬性

這2種方式相比於第一種沒有使用.

接下來 咱們再聲明method 這2種語法都ok,取決於你選擇哪種

setup(){
  const event = reactive(){
    capacity:4,
    attending:["Tim","Bob","Joe"],
    spacesLeft:computed(()=>{
      return event.capacity - event.attending.length;
    })
    function increaseCapacity(){event.capacity++}
    //return整個對象
    return {event,increaseCapacity}
  }
}
複製代碼
<p>Spaces Left:{{event.spacesLeft}} out of {{event.capacity}}</p>
<h2>Attending</h2>
<ul>>
	<li v-for="(name,index) in event.attending" :key="index">
     {{name}}
  </li>
</ul>
<button @click="increaseCapacity()"> Increase Capacity</button>
複製代碼

在這裏咱們使用對象都是.屬性的方式,可是若是 這個結構變化了,event分開了編程了一個個片斷,這個時候就不能用.屬性的方式了

//在這裏可使用toRefs
import {reactive,computed,toRefs} from 'vue'
export default{
  setup(){
    const event = reactive({
      capacity:4,
      attending:["Tim","Bob","Joe"],
      spacesLeft:computed(()=>{
        return event.capacity -event.attending.length;
        
      })
    })
    function increaseCapacity(){ event.capacity ++ }
    return {...toRefs(event),increaseCapacity}
  }
}
複製代碼

若是沒有 increaseCapacity() 這個方法 直接能夠簡化爲

return toRefs(event)
複製代碼

完整代碼

<div>
   <p>Space Left : {{event.spacesLeft}} out of {{event.capacity}} </p>
   <h2>Attending</h2>
   <ul>
      <li v-for="(name,index)" in event.attending :key="index">{{name}}
      </li></ul>
   <button @click="increaseCapacity">Increase Capacity</button>
   </div>
</template>

<script> //第一種 import {ref,computed } from 'vue' export default { setup(){ const capacity = ref(4) const attending = ref(["Tim","Bob","Joe"]) const spaceLeft = computed(()=>{ return capacity.value - attending.value.length; }); function increaseCapacity(){ capacity.value++; } return {capacity,increaseCapacity,attending,spaceLeft} } } //返回一個響應式函數 第二種 import { reactive,computed } from 'vue' export default { setup(){ const event = reactive({ capacity:4, attending:["Tim","Bob","Joe"], spaceLeft:computed(()=>{ return event.capacity - event.attending.length; }) }) //咱們再也不使用.value function increaseCapacity() { event.capacity++; } //把這個event放入到template中 return { event,increaseCapacity} } } </script>
複製代碼

6、 Modularizing

📺 VueMastery原版

📺 然叔與楊村長的深度解讀

使用CompositionAPI的兩個理由

  • 能夠按照功能組織代碼

    image-20201130163125995

  • 組件間功能代碼複用

image-20201130163206869

image-20201130163458085

7、 LifecycleHooks - 生命週期鉤子

📺 VueMastery原版

📺 然叔與楊村長的深度解讀

Vue2 Vue3
beforeCreate ❌setup(替代)
created ❌setup(替代)
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeDestroy onBeforeUnmount
destroyed onUnmounted
errorCaptured onErrorCaptured
🎉onRenderTracked
🎉onRenderTriggered

setup中調用生命週期鉤子

import { onBeforeMount,onMounted } from "vue";
export default {
  setup() {
    onBeforeMount(() => {
        console.log('Before Mount!')
    }) 
    onMounted(() => {
        console.log('Before Mount!')
    }) 
  },
};

複製代碼

8、Watch - 監聽器

📺 VueMastery原版

📺 然叔與楊村長的深度解讀

// 全部依賴響應式對象監聽
watchEffect(() => {
   results.value = getEventCount(searchInput.value);
 });

// 特定響應式對象監聽
watch(
  searchInput,
  () => {
    console.log("watch searchInput:");
  }
);

// 特定響應式對象監聽 能夠獲取新舊值
watch(
  searchInput,
 (newVal, oldVal) => {
    console.log("watch searchInput:", newVal, oldVal);
  },
);

// 多響應式對象監聽
watch(
  [firstName,lastName],
 ([newFirst,newLast], [oldFirst,oldlast]) => {
   // .....
  },
  
);

// 非懶加載方式監聽 能夠設置初始值
watch(
  searchInput,
  (newVal, oldVal) => {
    console.log("watch searchInput:", newVal, oldVal);
  },
  {
    immediate: true, 
  }
);

複製代碼

9、Sharing State - 共享狀態

📺 VueMastery原版

📺 然叔與楊村長的深度解讀

image-20201201113328715

編寫一個公共函數usePromise函數需求以下:

  • results : 返回Promise執行結果

  • loading: 返回Promise運行狀態

    • PENDING :true
    • REJECTED : false
    • RESOLVED: false
  • error : 返回執行錯誤

loading

import { ref } from "vue";

export default function usePromise(fn) {
  const results = ref(null);
  // is PENDING
  const loading = ref(false);
  const error = ref(null);

  const createPromise = async (...args) => {
    loading.value = true;
    error.value = null;
    results.value = null;
    try {
      results.value = await fn(...args);
    } catch (err) {
      error.value = err;
    } finally {
      loading.value = false;
    }
  };
  return { results, loading, error, createPromise };
}

複製代碼

應用

import { ref, watch } from "vue";
import usePromise from "./usePromise";
export default {
  setup() {
    const searchInput = ref("");
    function getEventCount() {
      return new Promise((resolve) => {
        setTimeout(() => resolve(3), 1000);
      });
    }

    const getEvents = usePromise((searchInput) => getEventCount());

    watch(searchInput, () => {
      if (searchInput.value !== "") {
        getEvents.createPromise(searchInput);
      } else {
        getEvents.results.value = null;
      }
    });

    return { searchInput, ...getEvents };
  },
};
複製代碼

10、Suspense - 懸念

📺 VueMastery原版

📺 然叔與楊村長的深度解讀

1. 複雜的Loading實現

咱們考慮一下當你加載一個遠程數據時,如何顯示loading狀態

一般咱們能夠在模板中使用v-if

image-20201201221313907

可是在一個組件樹中,其中幾個子組件須要遠程加載數據,當加載完成前父組件但願處於Loading狀態時咱們就必須藉助全局狀態管理來管理這個Loading狀態。

image-20201201221108667

![image-20201201221336107](/Users/xiaran/Library/Application Support/typora-user-images/image-20201201221336107.png)

2. Suspense基礎語法

這個問題在Vue3中有一個全新的解決方法。

這就是Suspense Component,懸念組件。

image-20201201221927963

<template>
  <div>
    <div v-if="error">Uh oh .. {{ error }}</div>
    <Suspense>
      <template #default>
        <div>
          <Event />
          <AsyncEvent />
        </div>
      </template>
      <template #fallback> Loading.... </template>
    </Suspense>
  </div>
</template>

<script> import { ref, onErrorCaptured, defineAsyncComponent } from "vue"; import Event from "./Event.vue"; const AsyncEvent = defineAsyncComponent(() => import("./Event.vue")); export default { components: { Event, AsyncEvent, }, setup() { const error = ref(null); onErrorCaptured((e) => { error.value = e; // 阻止錯誤繼續冒泡 return true; }); return { error }; }, }; </script>

複製代碼

3. 骨架屏實現

11、Teleport - 傳送門

📺 VueMastery原版

📺 然叔與楊村長的深度解讀

1. 功能

相似React中的Portal, 能夠將特定的html模板傳送到Dom的任何位置

image-20201202164954276

2. 基礎語法

經過選擇器QuerySelector配置

image-20201202171235123

3. 示例代碼

Kapture 2020-12-07 at 16.23.16

<template>
  <div>
    <teleport to="#end-of-body" :disabled="!showText">
      <!-- 【Teleport : This should be at the end 】 -->
      <div>
        <video src="../assets/flower.webm" muted controls="controls" autoplay="autoplay" loop="loop">
          
        </video>
      </div>
    </teleport>
    <div>【Teleport : This should be at the top】</div>
    <button @click="showText = !showText">Toggle showText</button>
  </div>
</template>
<script> import { ref } from "vue"; export default { setup() { const showText = ref(false); setInterval(() => { showText.value = !showText.value; }, 1000); return { showText }; }, }; </script>
複製代碼

關注全棧然叔

⚡️關注公衆號【前端大班車】 回覆 【vue】索取完整代碼

近期文章(感謝掘友的鼓勵與支持🌹🌹🌹)

歡迎拍磚,一塊兒探討更優雅的實現

相關文章
相關標籤/搜索