composition

mixin 缺點(diǎn)

命名沖突

mixin模式在運(yùn)行時(shí)盟庞,會(huì)將mixin對(duì)象和組件對(duì)象合并吃沪,如果他們都有相同的屬性名時(shí),vue組件默認(rèn)的合并策略是將本地選項(xiàng)覆蓋mixin選項(xiàng)(可以配置合并策略)什猖,

隱式依賴

mixin和使用的他的組件之間沒(méi)有層級(jí)關(guān)系票彪,這就意味著組件可以使用mixin里定義的屬性mixin也可以使用組件定義的屬性不狮,這樣子可能輝導(dǎo)致一些問(wèn)題降铸,當(dāng)我們要修一個(gè)組件時(shí),修改mixin的屬性名稱摇零,可能不會(huì)有什么問(wèn)題推掸,如果這個(gè)組件使用了大量的mixin時(shí)候,會(huì)不會(huì)破壞mixin驻仅?

Composition Api

mixin的缺點(diǎn)就是推動(dòng)Composition Api的主要原因之一

Composition Api的主要思想就是:我們將他們定義為從新的 setup函數(shù)返回的JavaScript變量谅畅,而不是將組件功能定義為對(duì)象屬性

setup

setup函數(shù)是vue3新增的方法,可以理解為Composition Api入口噪服,在beforeCreate之后create之前執(zhí)行毡泻。

參數(shù)有,propscontent粘优,props是接受組件props數(shù)據(jù)仇味,context是個(gè)上下文對(duì)象,注意setup中無(wú)法訪問(wèn)this
context對(duì)象包含一下屬性:attrs呻顽、emitslots

reactive

reactive是用來(lái)創(chuàng)建個(gè)響應(yīng)式對(duì)象的邪铲,相當(dāng)于vue2observable

export declare function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
export declare type UnwrapNestedRefs<T> = T extends Ref ? T : UnwrapRef<T>
export declare type UnwrapRef<T> = T extends Ref<infer V> ? UnwrapRefSimple<V> UnwrapRefSimple<T>
泛型T繼承了objec芬位,所以reactive函數(shù)的參數(shù)是對(duì)象類型

例子:

export default {
  name: 'HelloWorld',
  setup() {
    const state = reactive({
      name: '',
      age: ''
    })
    return {
      state,
    }
  },
}

ref

ref是給定植創(chuàng)建個(gè)響應(yīng)式數(shù)據(jù)對(duì)象无拗,ref()函數(shù)返回的是一個(gè)對(duì)象带到,該對(duì)象只包含一個(gè)屬性value。ref函數(shù)的參數(shù)是任意類型

export default {
  name: 'HelloWorld',
  setup() {
    const age = ref(18)
    return {
      age,
    }
  },
}

??注意
如果將ref響應(yīng)式數(shù)據(jù)掛在到reactive中英染,不用使用.value就可以訪問(wèn),

export default {
  name: 'HelloWorld',
  setup() {
    const num = ref (1)
    const obj = reactive({num})
    obj.num++
    console.log(obj.num) //2
    console.log(obj.num.value) //undefined
    console.log(obj.value) // 2 因?yàn)閚um是對(duì)象 對(duì)于掛在的時(shí)候是將地址賦值給objnum了
    return {
      obj
    }
  },
}

isRef

isRef 用來(lái)判斷某個(gè)值是否是ref創(chuàng)建出來(lái)的

isRef<T>(r: Ref<T> | unknown): r is Ref<T> 返回值是個(gè)boolean類型
unknown 類型揽惹,它是 any類型對(duì)應(yīng)的安全類型
isRef函數(shù)的參數(shù)是ref類型或者任意類型

toRefs

toRefs可以將reactive創(chuàng)建出來(lái)的響應(yīng)式對(duì)象轉(zhuǎn)化成普通對(duì)象,只不過(guò)這個(gè)對(duì)象的每個(gè)屬性都是ref類型的響應(yīng)式數(shù)據(jù)
toRefs<T extends object>(object: T): ToRefs<T>
接受參數(shù)是對(duì)象四康,返回值是 ToRefs<T>

type ToRefs<T = any> = {
    [K in keyof T]: T[K] extends Ref ? T[K] : Ref<UnwrapRef<T[K]>>;
};

例子:

<div>{{name}}{{age}}</div>
export default {
  name: 'HelloWorld',
  setup() {
    const obj = reactive({name:'小明',age:18})
    return {
      ...toRefs(obj)
    }
  },
}

toRef

為源響應(yīng)式對(duì)象的某個(gè)屬性創(chuàng)建一個(gè)ref對(duì)象搪搏,相當(dāng)于淺拷貝
區(qū)別ref,ref是深拷貝
export declare function toRef<T extends object, K extends keyof T>(object: T, key: K): ToRef<T[K]>
declare type ToRef<T> = [T] extends [Ref] ? T : Ref<UnwrapRef<T>>;
第一個(gè)參數(shù)是對(duì)象類型闪金,第二個(gè)參數(shù)要是第一個(gè)參數(shù)的屬性疯溺,返回值是ref類型

export default {
  name: 'HelloWorld',
  setup() {
     const obj = reactive({name:'小明',age:18})
     const age1 = toRef(obj, 'age')
     const age2 = ref(obj.age)
     const update = ()=> {
       obj.age ++ //obj會(huì)變,age1也會(huì)變
       age2.value ++ //obj和age1都不會(huì)變
     }
    return {
      update
    }
  },
}

computed

computed哎垦,用來(lái)創(chuàng)建計(jì)算器屬性囱嫩,返回ref值

export default {
  name: 'HelloWorld',
  setup() {
    const num = ref(1)
    const odd = computed(() => num.value * 2)
    //odd 只讀
    return {
      num,
      odd
    }
  },
}

創(chuàng)建可讀可寫的 computed

export default {
  name: 'HelloWorld',
  setup() {
    const num = ref(1)
    const odd = computed({
      // 取值
      get: () => num.value * 2,
      // 賦值
      set: val => num.value = val - 1
    })
    odd.value = 2 //觸發(fā)之后num的值也會(huì)改變
    return {
      num,
      odd
    }
  },
}

watch

監(jiān)聽數(shù)據(jù)的變化
export declare function watch<T extends object, Immediate extends Readonly<boolean> = false>(source: T, cb: WatchCallback<T, Immediate extends true ? (T | undefined) : T>, options?: WatchOptions<Immediate>): WatchStopHandle

第一個(gè)參數(shù)類型是:WatchSource<T = any> = Ref<T> | ComputedRef<T> | (() => T)

第二個(gè)參數(shù)是回調(diào)函數(shù)

第三個(gè)參數(shù)是可選的,類型是: WatchOptions?:{immediate?: Immediate;deep?: boolean;}

返回值是個(gè)函數(shù)調(diào)用返回的函數(shù)會(huì)終止監(jiān)聽漏设,類型:WatchStopHandle = () => void

const state = ref(1)
watch(()=>{
  console.log(state.value);
})
setTimeout(() => {
  state.value ++
}, 1000)

指定監(jiān)聽源

const state = ref(1)
watch(()=>state.value,(newVal,oldVal) => {
  console.log(oldVal,newVal);
})
watch(state,(newVal,oldVal) => {
  console.log(oldVal,newVal);
})
setTimeout(() => {
  state.value++
}, 1000)

監(jiān)聽多個(gè)

const state = reactive({
  count: 0,
  name: '12'
})
watch([() => state.count,() => state.name], ([newCount,newName], [oldCount,oldName]) => {
  console.log('new',newCount,newName);
  console.log('old',oldCount,oldName);
})

setTimeout(() => {
  state.count++
  console.log(state.name )
  state.name = '121'
}, 1000)

在setup函數(shù)內(nèi)創(chuàng)建的watch在組件銷毀時(shí)墨闲,會(huì)自動(dòng)停止監(jiān)聽,如果想明確的停止監(jiān)聽的話郑口,可以調(diào)用watch函數(shù)的返回值watch函數(shù)返回值(WatchStopHandle = () => void)是一個(gè)函數(shù)

const state = reactive({
  count: 0,
  name: '12'
})
const stop = watch([() => state.count,() => state.name], ([newCount,newName], [oldCount,oldName]) => {
  console.log('new',newCount,newName);
  console.log('old',oldCount,oldName);
})
setInterval(() => {
  state.count++
  state.name = '121'
}, 1000)
setTimeout(() => {
  stop()
}, 2000);

watchEffect

vue3 新增的屬性監(jiān)聽api

watchEffect(effect: WatchEffect, options?: WatchOptionsBase): WatchStopHandl

type WatchEffect = (onInvalidate: InvalidateCbRegistrator) => void;

nterface WatchOptionsBase {
  flush?: 'pre' | 'post' | 'sync';
  onTrack?: ReactiveEffectOptions['onTrack'];
  onTrigger?: ReactiveEffectOptions['onTrigger'];
}

type WatchStopHandle = () => void;

和watch的區(qū)別:
1鸳碧、watchEffect不需要指定監(jiān)聽屬性,可以自動(dòng)收集依賴犬性,只要我們回調(diào)中引用了響應(yīng)式的屬性瞻离,那么這些屬性變更的時(shí)候,這個(gè)回調(diào)都會(huì)執(zhí)行乒裆,而watch只能監(jiān)聽指定的屬性而做出變更(v3中可以同時(shí)監(jiān)聽多個(gè))

2套利、watch可以獲取到新值和舊值,而watchEffect獲取不到

3缸兔、watchEffect會(huì)在組件初始化的時(shí)候就會(huì)執(zhí)行一次與computed同理日裙,而收集到的依賴變化后,這個(gè)回調(diào)才會(huì)執(zhí)行惰蜜,而watch不需要昂拂,除非設(shè)置了指定參數(shù)。

setup(props, contex) {
  const state = reactive({
    num: '121',
    msg: '111'
  })
  const stop = watchEffect(()=>{
    console.log('watchEffect', state.num)
    console.log('watchEffect', state.msg)
  })
  stop()//停止監(jiān)聽
  return {
    state,
  }
}

假設(shè)我們現(xiàn)在用一個(gè)用戶ID去查詢用戶的詳情信息抛猖,然后我們監(jiān)聽了這個(gè)用戶ID格侯, 當(dāng)用戶ID 改變的時(shí)候我們就會(huì)去發(fā)起一次請(qǐng)求鼻听,這很簡(jiǎn)單,用watch 就可以做到联四。 但是如果在請(qǐng)求數(shù)據(jù)的過(guò)程中撑碴,我們的用戶ID發(fā)生了多次變化,那么我們就會(huì)發(fā)起多次請(qǐng)求朝墩,而最后一次返回的數(shù)據(jù)將會(huì)覆蓋掉我們之前返回的所有用戶詳情醉拓。這不僅會(huì)導(dǎo)致資源浪費(fèi),還無(wú)法保證 watch 回調(diào)執(zhí)行的順序收苏。而使用watchEffect我們就可以做到.

onInvalidate(fn)傳入的回調(diào)會(huì)在watchEffect重新運(yùn)行或者watchEffect停止的時(shí)候執(zhí)行亿卤。

watchEffect(()=>{
  //異步調(diào)用api
  const obj= getData(user.id)
  onInvalidate(()=>{
    // 取消API的調(diào)用
    obj.cancel()
  })
})

customRef

創(chuàng)建一個(gè)自定義的ref,并對(duì)其依賴跟蹤和更新觸發(fā)進(jìn)行顯式控制
場(chǎng)景:實(shí)現(xiàn)防抖輸入框

export declare function customRef<T>(factory: CustomRefFactory<T>): Ref<T>;

declare type CustomRefFactory<T> = (track: () => void, trigger: () => void) => {
    get: () => T;
    set: (value: T) => void;
};

customRef參數(shù)類型是CustomRefFactory<T>,參數(shù)是個(gè)函數(shù)鹿霸,返回值是個(gè)對(duì)象{get: () => T;set: (value: T) => void;}
customRef 返回值是 Ref<T> 類型排吴,說(shuō)明返回值是個(gè)ref對(duì)象

例子:

let keyworld = useDebouncedRef('')
    function useDebouncedRef(value, t = 500) {
      let tims = null;
      return customRef((track, trigger) => {
        return {
          get: () => {
            track();
            return value;
          },
          set: (newValue) => {
            clearTimeout(tims);
            setTimeout(() => {
              value = newValue;
              trigger();
            }, t);
          },
        };
      });
    };

自定義Hook函數(shù)

相當(dāng)于vue2的mixin,相對(duì)于vue2的mixin技術(shù)懦鼠,自定義hook函數(shù)知道代碼來(lái)源钻哩,方便復(fù)用
例子:

//hooks.js
import { reactive } from 'vue';

export default function () {
  const state = reactive({
    num: 1,
    msg: 'text'
  })
  return {
    state
  }
}
//引用
import hooks from '../utils/hooks.js';
export default {
  name: 'HelloWorld',
  props: {
    msg: String,
  },
  setup(props, contex) {
    const { state } = hooks();
    return {
      state,
    };
  },
};

readonly與shallowReadonly

readonly 深度只讀
shallowReadonly 淺度只讀

template ref

通過(guò)ref() 可以拿到頁(yè)面上的元素和組件
例子:

<template>
  <button @click="tap">點(diǎn)擊</button>
  <p ref="pRef">測(cè)試</p>
  <HelloWorld ref="helloRef"></HelloWorld>
</template>

setup(props, contex) {
    const pRef = ref(null)
    const helloRef = ref(null)
    const tap = ()=>{
      helloRef.value.divClick() //調(diào)用組件的方法
      helloRef.value.count //獲取組件的值
      pRef.value //dom節(jié)點(diǎn)
    }
    return {
      pRef,
      helloRef,
      tap
    };
  },

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市肛冶,隨后出現(xiàn)的幾起案子街氢,更是在濱河造成了極大的恐慌,老刑警劉巖淑趾,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件阳仔,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡扣泊,警方通過(guò)查閱死者的電腦和手機(jī)近范,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)延蟹,“玉大人评矩,你說(shuō)我怎么就攤上這事≮迤” “怎么了斥杜?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)沥匈。 經(jīng)常有香客問(wèn)我蔗喂,道長(zhǎng),這世上最難降的妖魔是什么高帖? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任缰儿,我火速辦了婚禮,結(jié)果婚禮上散址,老公的妹妹穿的比我還像新娘乖阵。我一直安慰自己宣赔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布瞪浸。 她就那樣靜靜地躺著儒将,像睡著了一般。 火紅的嫁衣襯著肌膚如雪对蒲。 梳的紋絲不亂的頭發(fā)上钩蚊,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音齐蔽,去河邊找鬼两疚。 笑死床估,一個(gè)胖子當(dāng)著我的面吹牛含滴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播丐巫,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼谈况,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了递胧?” 一聲冷哼從身側(cè)響起碑韵,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缎脾,沒(méi)想到半個(gè)月后祝闻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡遗菠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年联喘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辙纬。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡豁遭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出贺拣,到底是詐尸還是另有隱情蓖谢,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布譬涡,位于F島的核電站闪幽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏涡匀。R本人自食惡果不足惜盯腌,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望渊跋。 院中可真熱鬧腊嗡,春花似錦着倾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至客们,卻和暖如春崇决,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背底挫。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工恒傻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人建邓。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓盈厘,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親官边。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沸手,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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