vue-property-decorator 使用

@Component(options)

這一個(gè)是與另一個(gè) vue 的庫 vue-class-component 一樣的用法. 這個(gè)裝飾器庫源自 class 庫, 只是再封裝了一層, 使代碼更為簡潔明了. options 里面需要配置 decorator 庫不支持的屬性, 哪些是不支持的呢?
那就請看完全文, 凡是沒寫的都是不支持的. 比如components, filters, directives等

  • components

表示該組件引入了哪些子組件

<template>
  <div id="app">
    <HelloWorld />
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component({
  components: {
    HelloWorld, // 聲明子組件的引用
  }
})
export default class App extends Vue {}
</script>
  • filters

filter 表示對數(shù)據(jù)的篩選, 跟 linux 中的管道符十分相似, 數(shù)據(jù)通過 filter 進(jìn)行處理變成新的數(shù)據(jù).注意, 在這里配置時(shí)一定要使用 filters, 不要忘了 s, 否則不會報(bào)錯(cuò)但是也沒作用海洼。

<template>
  <div>{{msg | filterA}}</div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component({
  filters: {
    addWorld: (value: string) => `${value} world`,
  },
})
export default class App extends Vue {
  private msg = 'Hello' // filter 之后顯示 hello world
}
</script>
  • directives

具體的介紹可以看 Vue 的官方介紹 簡單來說就是 DOM 節(jié)點(diǎn)在一些特定鉤子觸發(fā)時(shí)添加一些額外的功能瞎领。

鉤子函數(shù)有:

  • bind 指令綁定到元素時(shí)調(diào)用, 可以進(jìn)行一次性設(shè)置
  • inserted 綁定元素被插入到父節(jié)點(diǎn)時(shí)調(diào)用
  • update VNode 更新時(shí)調(diào)用
  • componentUpdated VNode 及子 VNode 全部更新后調(diào)用
  • unbind 元素解綁時(shí)調(diào)用

如果bind 和 update 時(shí)調(diào)用一樣可以進(jìn)行簡寫, 不用指定某個(gè)鉤子

鉤子函數(shù)參數(shù):

  1. el 對應(yīng)綁定的 DOM

  2. binding

  • name 指令名 v-demo="1+1" 為 "demo"
  • value 綁定的值 v-demo="1+1" 為 2
  • oldValue 在 update componentUpdated 可用
  • expression 字符串形式的表達(dá)式 v-demo="1+1" 為 "1+1"
  • arg 指令的參數(shù) v-demo:foo 為 'foo', 注意要在 modifier 前使用 arg, 不然會將 arg 作為 modifier 的一部分, 如v-demo.a:foo arg 為 undefined, modifier 為{'a:foo': true}
  • modifiers 包含修飾符的對象 比如 v-demo.a 這個(gè)值為 {a:true}
  1. vnode vue 的虛擬節(jié)點(diǎn), 可參考源碼查看可用屬性

  2. oldVnode 上一個(gè)虛擬節(jié)點(diǎn)(update 和 componentUpdated 可用)

看個(gè)簡單的實(shí)例:

<template>
  <span v-demo:foo.a="1+1">test</span>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component({
  directives: {
    demo: {
      bind(el, binding, vnode) {
        console.log(`bindingName: ${binding.name}, value: ${binding.value}, args: ${binding.arg}, expression: ${binding.expression}`); // bindingName: demo, value: 2, args: foo, expression: 1+1
        console.log('modifier:', binding.modifiers); // {a:true}, 無法轉(zhuǎn)為 primitive, 所以單獨(dú)打印
      },
    },
    demoSimplify(el, binding, vnode) {
      // do stuff
    },
  },
})
export default class App extends Vue {}
</script>

@Prop()

父子組件傳遞數(shù)據(jù) props的修飾符

參數(shù)可以傳

  • Constructor 例如String, Number, Boolean

  • Constructor[], 構(gòu)造函數(shù)的隊(duì)列, 類型在這隊(duì)列中即可

  • PropOptions

    • type 類型不對會報(bào)錯(cuò) Invalid prop: type check failed for prop "xxx". Expected Function, got String with value "xxx".
    • default 如果父組件沒有傳的話為該值, 注意只能用這一種形式來表示默認(rèn)值, 不能@Prop() name = 1來表示默認(rèn)值 1, 雖然看起來一樣, 但是會在 console 里報(bào)錯(cuò), 不允許修改 props 中的值
    • required 沒有會報(bào)錯(cuò) [Vue warn]: Missing required prop: "xxx"
    • validator 為一個(gè)函數(shù), 參數(shù)為傳入的值, 比如(value) => value > 100

父組件:

<template>
  <div id="app">
    <PropComponent :count="count" />
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'

@Component
class Parent extends Vue {
  private count = 101;
}
</script>

子組件:

<template>
  <div>{{ count }}</div>
</template>

<script lang="ts">
import { Component, Vue, Prop } from "vue-property-decorator"

@Component
export default class PropsComponent extends Vue {
  // !表示有值, 否則 ts 會告警未初始化 }
  @Prop({
    type: Number,
    validator: value => {
      return value > 100
    },
    required: true
  })
  private count!: string
}
</script>

@PropSync() 與 Prop 的區(qū)別是子組件可以對 props 進(jìn)行更改, 并同步給父組件,

子組件:

<template>
  <div>
    <p>{{count}}</p>
    <button @click="innerCount += 1">increment</button>
  </div>
</template>
<script lang="ts">
    import { Component, Vue, PropSync } from "vue-property-decorator"

    @Component
    export default class PropSyncComponent extends Vue {
      // 注意@PropSync 里的參數(shù)不能與定義的實(shí)例屬性同名, 因?yàn)檫€是那個(gè)原理, props 是只讀的
      @PropSync('count') private innerCount!: number
    }
</script>

父組件: 注意父組件里綁定 props 時(shí)需要加修飾符 .sync

<template>
  <PropSyncComponent :count.sync="count" />
</template> 

<script lang="ts">
    import { Component, Vue, PropSync } from "vue-property-decorator"

    @Component({ components: PropSyncComponent })

    export default class PropSyncComponent extends Vue {
      // 注意@PropSync 里的參數(shù)不能與定義的實(shí)例屬性同名, 因?yàn)檫€是那個(gè)原理, props 是只讀的.
      @PropSync('count') private innerCount!: number
    }
</script>

也可結(jié)合 input 元素的 v-model 綁定數(shù)據(jù), 實(shí)時(shí)更新. 由讀者自行實(shí)現(xiàn).

@Watch監(jiān)聽屬性發(fā)生更改時(shí)被觸發(fā).

可接受配置參數(shù) options

  • immediate?: boolean 是否在偵聽開始之后立即調(diào)用該函數(shù)
  • deep?: boolean 是否深度監(jiān)聽.
<template>
  <div>
    <button @click="person.name.firstName = '修'">change deeper</button>
    <button @click="person.name = '修'">change deep</button>
  </div>
</template>
<script lang="ts">
    import { Component, Vue, Watch } from 'vue-property-decorator'

    @Component
    export default class PropSyncComponent extends Vue {  
      private person = { name: { firstName: '修' } }  
      @Watch('person', { deep: true })
        private firstNameChange(person: object, oldPerson: object) {   
        console.log(person, oldPerson)
      }
    } 
 </script>

@Emit

  • 接受一個(gè)參數(shù) event?: string, 如果沒有的話會自動將 camelCase 轉(zhuǎn)為 dash-case 作為事件名.
  • 會將函數(shù)的返回值作為回調(diào)函數(shù)的第二個(gè)參數(shù), 如果是 Promise 對象,則回調(diào)函數(shù)會等 Promise resolve 掉之后觸發(fā).
  • 如果$emit 還有別的參數(shù), 比如點(diǎn)擊事件的 event , 會在返回值之后, 也就是第三個(gè)參數(shù).

子組件:

<template>
  <div>
    <button @click="emitChange">Emit!!</button>
  </div>
</template>

<script lang="ts">
    import { Component, Vue, Emit } from "vue-property-decorator";

    @Component
    export default class EmitComponent extends Vue {
      private count = 0
      @Emit("button-click") private emitChange() {
        this.count += 1
        return this.count
      }
    }
</script>

父組件, 父組件的對應(yīng)元素上綁定事件即可:

<template>
  <EmitComponent v-on:button-click="listenChange" />
</template>

<script lang="ts">
    import { Component, Vue } from "vue-property-decorator"

    @Component({ components: { EmitComponent } })
    export default class App extends Vue {
      private listenChange(value: number, event: any) {
        console.log(value, e)
      }
    }
</script>

@Ref 跟 react 中的一樣, ref 是用于引用實(shí)際的 DOM 元素或者子組件.應(yīng)盡可能避免直接使用, 但如果不得不用 ref 比 document 拿要方便很多, 參數(shù)傳一個(gè)字符串refKey?:string, 注意這里如果省略傳輸參數(shù), 那么會自動將屬性名作為參數(shù), 注意與@Emit的區(qū)別, @Emit在不傳參數(shù)的情況下會轉(zhuǎn)為 dash-case, 而 @Ref不會轉(zhuǎn), 為原屬性名

<template>
  <div>
    <span>Name:</span>
    <input type="text" v-model="value" ref="name" />
  </div>
</template>
<script lang="ts"> 
    import { Component, Vue, Ref } from 'vue-property-decorator'

    @Component 
    export default class RefComponent extends Vue { 
      @Ref('name') readonly name!: string
      private value = '修'  
      private mounted() {   
        console.log(this.name)
      }
    }
</script>

@Provide/@inject && @ProvideReactive/@InjectReactive

其本質(zhì)是轉(zhuǎn)換為 inject 和 provide, 這是 vue 中元素向更深層的子組件傳遞數(shù)據(jù)的方式.兩者需要一起使用.與 react 的 context 十分的像

任意代的子組件:

<template>
  <span>Inject deeper: {{ bar }}</span>
</template> 
<script lang="ts">
    import { Component, Vue, Inject } from "vue-property-decorator";

    @Component
    export default class InjectComponent extends Vue {
      @Inject()
      private bar!: string
      private mounted() {
        console.log(this.bar)
      }
    }
</script>

任意祖先元素:

<script lang="ts">
    import { Component, Vue, Provide } from "vue-property-decorator"
    export default class App extends Vue {
      @Provide()
      private bar = "deeper 修"
    }
</script>

方便很多, 如果為了避免命名沖突, 可以使用 ES6 的 Symbol 特性作為 key, 以祖先元素舉例:

需要注意的是避免相互引用的問題, symbol 的引用最好放到組件外單獨(dú)有個(gè)文件存起來.

export const s = Symbol()

父組件:

<script lang="ts">
    import { Component, Vue, Provide } from "vue-property-decorator"

    export const s = Symbol()

    @Component
    export default class App extends Vue {
      @Provide(s)
      private bar = "deeper 修"
    }
</script>

子組件:

<script lang="ts">
    import { Component, Vue, Inject } from "vue-property-decorator";

    import { s } from 'xxx'

    @Component
    export default class App extends Vue {
      @Inject(s) private baz = "deeper 修"
    }
</script>

@ProvideReactive/@InjectReactive 顧名思義就是響應(yīng)式的注入, 會同步更新到子組件中.比如下例可以實(shí)現(xiàn)在 input 中的輸入實(shí)時(shí)注入到子組件中 父組件

<template>
  <div id="app">
    <input type="text" v-model="bar" />
    <InjectComponent />
  </div>
</template> 
<script lang="ts">
    import { Component, Vue, ProvideReactive } from "vue-property-decorator"

    export const s = Symbol();

    @Component({ InjectComponent })
    export default class App extends Vue {
      @ProvideReactive(s) private bar = "deeper 修"
    }
</script>

子組件:

<script lang="ts">
   import { Component, Vue, InjectReactive } from "vue-property-decorator"

   @Component
   export default class InjectComponent extends Vue {
     @InjectReactive(s) private baz!: string
   }
</script>

@Model

Vue組件提供model: {prop?: string, event?: string}讓我們可以定制propevent.

默認(rèn)情況下萝风,一個(gè)組件上的v-model 會把 value用作 prop且把 input用作 event开泽,但是一些輸入類型比如單選框和復(fù)選框按鈕可能想使用 value prop來達(dá)到不同的目的。使用model選項(xiàng)可以回避這些情況產(chǎn)生的沖突。

  • 下面是Vue官網(wǎng)的例子
Vue.component('my-checkbox', {
    model: {
        prop: 'checked',
        event: 'change'
    }, props: {    // this allows using the `value` prop for a different purpose  
        value: String,
        checked: { // use `checked` as the prop which take the place of `value`
            type: Number, default: 0
        }
    },  // ... 
})
<template>
  <my-checkbox v-model="foo" value="some value"></my-checkbox>
</template>

上述代碼相當(dāng)于:

<template>
  <my-checkbox  :checked="foo"  @change="val => { foo = val }"  value="some value" />
</template>

即foo雙向綁定的是組件的checke, 觸發(fā)雙向綁定數(shù)值的事件是change

使用vue-property-decorator提供的@Model改造上面的例子.

<script lang="ts">
    import { Vue, Component, Model } from "vue-property-decorator"
    @Component
    export class myCheck extends Vue {
      @Model("change", { type: Boolean }) checked!: boolean
    }
</script>
  • 總結(jié), @Model()接收兩個(gè)參數(shù), 第一個(gè)是event值, 第二個(gè)是prop的類型說明, 與@Prop類似, 這里的類型要用JS的. 后面在接著是prop和在TS下的類型說明.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末骚灸,一起剝皮案震驚了整個(gè)濱河市期虾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌踊淳,老刑警劉巖假瞬,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異迂尝,居然都是意外死亡笨触,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門雹舀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來芦劣,“玉大人,你說我怎么就攤上這事说榆⌒橐鳎” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵签财,是天一觀的道長串慰。 經(jīng)常有香客問我,道長唱蒸,這世上最難降的妖魔是什么邦鲫? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮神汹,結(jié)果婚禮上庆捺,老公的妹妹穿的比我還像新娘。我一直安慰自己屁魏,他們只是感情好滔以,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著氓拼,像睡著了一般你画。 火紅的嫁衣襯著肌膚如雪抵碟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天坏匪,我揣著相機(jī)與錄音拟逮,去河邊找鬼。 笑死适滓,一個(gè)胖子當(dāng)著我的面吹牛唱歧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播粒竖,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼颅崩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蕊苗?” 一聲冷哼從身側(cè)響起沿后,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎朽砰,沒想到半個(gè)月后尖滚,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞧柔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年漆弄,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片造锅。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡撼唾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哥蔚,到底是詐尸還是另有隱情倒谷,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布糙箍,位于F島的核電站渤愁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏深夯。R本人自食惡果不足惜抖格,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望咕晋。 院中可真熱鬧雹拄,春花似錦、人聲如沸捡需。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽站辉。三九已至呢撞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饰剥,已是汗流浹背殊霞。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留汰蓉,地道東北人绷蹲。 一個(gè)月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像顾孽,于是被迫代替她去往敵國和親祝钢。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

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

  • Vue 實(shí)例 屬性和方法 每個(gè) Vue 實(shí)例都會代理其 data 對象里所有的屬性:var data = { a:...
    云之外閱讀 2,209評論 0 6
  • 一若厚、了解Vue.js 1.1.1 Vue.js是什么拦英? 簡單小巧、漸進(jìn)式测秸、功能強(qiáng)大的技術(shù)棧 1.1.2 為什么學(xué)習(xí)...
    蔡華鵬閱讀 3,323評論 0 3
  • 1. Vue 實(shí)例 1.1 創(chuàng)建一個(gè)Vue實(shí)例 一個(gè) Vue 應(yīng)用由一個(gè)通過 new Vue 創(chuàng)建的根 Vue 實(shí)...
    王童孟閱讀 1,021評論 0 2
  • 什么是組件疤估? 組件 (Component) 是 Vue.js 最強(qiáng)大的功能之一。組件可以擴(kuò)展 HTML 元素霎冯,封裝...
    youins閱讀 9,480評論 0 13
  • Vue 3.0 性能提升主要是通過哪幾方面體現(xiàn)的铃拇? vue2在初始化的時(shí)候,對data中的每個(gè)屬性使用define...
    Smallbore閱讀 1,161評論 0 8