<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
參考:https://github.com/kaorun343/vue-property-decorator
怎麼使vue支援ts寫法呢,我們需要用到vue-property-decorator,這個元件完全依賴於vue-class-component
.
首先安裝: npm i -D vue-property-decorator
<template> <div> foo:{{foo}} defaultArg:{{defaultArg}} | {{countplus}} <button @click="delToCount($event)">點選del emit</button> <HellowWordComponent></HellowWordComponent> <button ref="aButton">ref</button> </div> </template> <script lang="ts"> import { Component, Vue, Prop, Emit, Ref } from 'vue-property-decorator'; import HellowWordComponent from '@/components/HellowWordComponent.vue'; @Component({ components: { HellowWordComponent, }, beforeRouteLeave(to: any, from: any, next: any) { console.log('beforeRouteLeave'); next(); }, beforeRouteEnter(to: any, from: any, next: any) { console.log('beforeRouteLeave'); next(); }, }) export default class DemoComponent extends Vue { private foo = 'App Foo!'; private count: number = this.$store.state.count; @Prop(Boolean) private defaultArg: string | undefined; @Emit('delemit') private delEmitClick(event: MouseEvent) {} @Ref('aButton') readonly ref!: HTMLButtonElement; // computed; get countplus () { return this.count; } created() {} mounted() {} beforeDestroy() {} public delToCount(event: MouseEvent) { this.delEmitClick(event); this.count += 1; // countplus 會累加 } } </script> <style lang="less"> ... </style>
vue-proporty-decorator它具備以下幾個裝飾器和功能:
@Component
裝飾器可以接收一個物件作為引數,可以在物件中宣告 components ,filters,directives
等未提供裝飾器的選項,也可以宣告computed,watch
等
registerHooks:
除了上面介紹的將beforeRouteLeave放在Component中之外,還可以全域性註冊,就是registerHooks
<script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; Component.registerHooks([ 'beforeRouteLeave', 'beforeRouteEnter', ]); @Component export default class App extends Vue { beforeRouteLeave(to: any, from: any, next: any) { console.log('beforeRouteLeave'); next(); } beforeRouteEnter(to: any, from: any, next: any) { console.log('beforeRouteLeave'); next(); } } </script>
@Prop
裝飾器接收一個引數,這個引數可以有三種寫法:
Constructor
,例如String,Number,Boolean
等,指定 prop
的型別;Constructor[]
,指定 prop
的可選型別;PropOptions
,可以使用以下選項:type,default,required,validator
。注意:屬性的ts型別後面需要加上undefined
型別;或者在屬性名後面加上!,表示非null
和 非undefined
的斷言,否則編譯器會給出錯誤提示;
// 父元件: <template> <div class="Props"> <PropComponent :name="name" :age="age" :sex="sex"></PropComponent> </div> </template> <script lang="ts"> import {Component, Vue,} from 'vue-property-decorator'; import PropComponent from '@/components/PropComponent.vue'; @Component({ components: {PropComponent,}, }) export default class PropsPage extends Vue { private name = '張三'; private age = 1; private sex = 'nan'; } </script> // 子元件: <template> <div class="hello"> name: {{name}} | age: {{age}} | sex: {{sex}} </div> </template> <script lang="ts"> import {Component, Vue, Prop} from 'vue-property-decorator'; @Component export default class PropComponent extends Vue { @Prop(String) readonly name!: string | undefined; @Prop({ default: 30, type: Number }) private age!: number; @Prop([String, Boolean]) private sex!: string | boolean; } </script>
@PropSync
裝飾器與@prop
用法類似,二者的區別在於:
@PropSync
裝飾器接收兩個引數:propName: string
表示父元件傳遞過來的屬性名;
options: Constructor | Constructor[] | PropOptions
與@Prop
的第一個引數一致;@PropSync
會生成一個新的計算屬性。注意,使用PropSync的時候是要在父元件配合.sync使用的
// 父元件 <template> <div class="PropSync"> <h1>父元件</h1> like:{{like}} <hr/> <PropSyncComponent :like.sync="like"></PropSyncComponent> </div> </template> <script lang='ts'> import { Vue, Component } from 'vue-property-decorator'; import PropSyncComponent from '@/components/PropSyncComponent.vue'; @Component({components: { PropSyncComponent },}) export default class PropSyncPage extends Vue { private like = '父元件的like'; } </script> // 子元件 <template> <div class="hello"> <h1>子元件:</h1> <h2>syncedlike:{{ syncedlike }}</h2> <button @click="editLike()">修改like</button> </div> </template> <script lang="ts"> import { Component, Prop, Vue, PropSync,} from 'vue-property-decorator'; @Component export default class PropSyncComponent extends Vue { @PropSync('like', { type: String }) syncedlike!: string; // 用來實現元件的雙向繫結,子元件可以更改父元件穿過來的值 editLike(): void { this.syncedlike = '子元件修改過後的syncedlike!'; // 雙向繫結,更改syncedlike會更改父元件的like } } </script>
@Model
裝飾器允許我們在一個元件上自定義v-model
,接收兩個引數:
event: string
事件名。options: Constructor | Constructor[] | PropOptions
與@Prop
的第一個引數一致。注意,有看不懂的,可以去看下vue官網檔案, https://cn.vuejs.org/v2/api/
// 父元件 <template> <div class="Model"> <ModelComponent v-model="fooTs" value="some value"></ModelComponent> <div>父元件 app : {{fooTs}}</div> </div> </template> <script lang="ts"> import { Component, Vue } from 'vue-property-decorator'; import ModelComponent from '@/components/ModelComponent.vue'; @Component({ components: {ModelComponent} }) export default class ModelPage extends Vue { private fooTs = 'App Foo!'; } </script> // 子元件 <template> <div class="hello"> 子元件:<input type="text" :value="checked" @input="inputHandle($event)"/> </div> </template> <script lang="ts"> import {Component, Vue, Model,} from 'vue-property-decorator'; @Component export default class ModelComponent extends Vue { @Model('change', { type: String }) readonly checked!: string public inputHandle(that: any): void { this.$emit('change', that.target.value); // 後面會講到@Emit,此處就先使用this.$emit代替 } } </script>
@Watch
裝飾器接收兩個引數:path: string
被偵聽的屬性名;options?: WatchOptions={} options
可以包含兩個屬性 :immediate?:boolean
偵聽開始之後是否立即呼叫該回撥函數;deep?:boolean
被偵聽的物件的屬性被改變時,是否呼叫該回撥函數;
發生在beforeCreate
勾子之後,created
勾子之前
<template> <div class="PropSync"> <h1>child:{{child}}</h1> <input type="text" v-model="child"/> </div> </template> <script lang="ts"> import { Vue, Watch, Component } from 'vue-property-decorator'; @Component export default class WatchPage extends Vue { private child = ''; @Watch('child') onChildChanged(newValue: string, oldValue: string) { console.log(newValue); console.log(oldValue); } } </script>
@Emit
裝飾器接收一個可選引數,該引數是$Emit
的第一個引數,充當事件名。如果沒有提供這個引數,$Emit
會將回撥函數名的camelCase
轉為kebab-case
,並將其作為事件名;@Emit
會將回撥函數的返回值作為第二個引數,如果返回值是一個Promise
物件,$emit
會在Promise
物件被標記為resolved
之後觸發;@Emit
的回撥函數的引數,會放在其返回值之後,一起被$emit
當做引數使用。// 父元件 <template> <div class=""> 點選emit獲取子元件的名字<br/> 姓名:{{emitData.name}} <hr/> <EmitComponent sex='女' @add-to-count="returnPersons" @delemit="delemit"></EmitComponent> </div> </template> <script lang="ts"> import { Vue, Component } from 'vue-property-decorator'; import EmitComponent from '@/components/EmitComponent.vue'; @Component({ components: { EmitComponent }, }) export default class EmitPage extends Vue { private emitData = { name: '我還沒有名字' }; returnPersons(data: any) { this.emitData = data; } delemit(event: MouseEvent) { console.log(this.emitData); console.log(event); } } </script> // 子元件 <template> <div class="hello"> 子元件: <div v-if="person"> 姓名:{{person.name}}<br/> 年齡:{{person.age}}<br/> 性別:{{person.sex}}<br/> </div> <button @click="addToCount(person)">點選emit</button> <button @click="delToCount($event)">點選del emit</button> </div> </template> <script lang="ts"> import { Component, Vue, Prop, Emit, } from 'vue-property-decorator'; type Person = {name: string; age: number; sex: string }; @Component export default class PropComponent extends Vue { private name: string | undefined; private age: number | undefined; private person: Person = { name: '我是子元件的張三', age: 1, sex: '男' }; @Prop(String) readonly sex: string | undefined; @Emit('delemit') private delEmitClick(event: MouseEvent) {} @Emit() // 如果此處不設定別名字,則預設使用下面的函數命名 addToCount(p: Person) { // 此處命名如果有大寫字母則需要用橫線隔開 @add-to-count return this.person; // 此處不return,則會預設使用括號裡的引數p; } delToCount(event: MouseEvent) { this.delEmitClick(event); } } </script>
@Ref
裝飾器接收一個可選引數,用來指向元素或子元件的參照資訊。如果沒有提供這個引數,會使用裝飾器後面的屬性名充當引數
<template> <div class="PropSync"> <button @click="getRef()" ref="aButton">獲取ref</button> <RefComponent name="names" ref="RefComponent"></RefComponent> </div> </template> <script lang="ts"> import { Vue, Component, Ref } from 'vue-property-decorator'; import RefComponent from '@/components/RefComponent.vue'; @Component({ components: { RefComponent }, }) export default class RefPage extends Vue { @Ref('RefComponent') readonly RefC!: RefComponent; @Ref('aButton') readonly ref!: HTMLButtonElement; getRef() { console.log(this.RefC); console.log(this.ref); } } </script>
@Provide(key?: string | symbol) / @Inject(options?: { from?: InjectKey, default?: any } | InjectKey)
decorator @ProvideReactive(key?: string | symbol)
/ @InjectReactive(options?: { from?: InjectKey, default?: any } | InjectKey)
decorator
提供/注入裝飾器,
key可以為string或者symbol型別,
相同點:Provide/ProvideReactive提供的資料,在內部元件使用Inject/InjectReactive都可取到
不同點:
如果提供(ProvideReactive
)的值被父元件修改,則子元件可以使用InjectReactive
捕獲此修改。
// 最外層元件 <template> <div class=""> <H3>ProvideInjectPage頁面</H3> <div> 在ProvideInjectPage頁面使用Provide,ProvideReactive定義資料,不需要props傳遞資料 然後爺爺套父母,父母套兒子,兒子套孫子,最後在孫子元件裡面獲取ProvideInjectPage 裡面的資訊 </div> <hr/> <provideGrandpa></provideGrandpa> <!--爺爺元件--> </div> </template> <script lang="ts"> import { Vue, Component, Provide, ProvideReactive, } from 'vue-property-decorator'; import provideGrandpa from '@/components/ProvideGParentComponent.vue'; @Component({ components: { provideGrandpa }, }) export default class ProvideInjectPage extends Vue { @Provide() foo = Symbol('fooaaa'); @ProvideReactive() fooReactive = 'fooReactive'; @ProvideReactive('1') fooReactiveKey1 = 'fooReactiveKey1'; @ProvideReactive('2') fooReactiveKey2 = 'fooReactiveKey2'; created() { this.foo = Symbol('fooaaa111'); this.fooReactive = 'fooReactive111'; this.fooReactiveKey1 = 'fooReactiveKey111'; this.fooReactiveKey2 = 'fooReactiveKey222'; } } </script> // ...provideGrandpa呼叫父母元件 <template> <div class="hello"> <ProvideParentComponent></ProvideParentComponent> </div> </template> // ...ProvideParentComponent呼叫兒子元件 <template> <div class="hello"> <ProvideSonComponent></ProvideSonComponent> </div> </template> // ...ProvideSonComponent呼叫孫子元件 <template> <div class="hello"> <ProvideGSonComponent></ProvideGSonComponent> </div> </template> // 孫子元件<ProvideGSonComponent>,經過多層參照後,在孫子元件使用Inject可以得到最外層元件provide的資料哦 <template> <div class="hello"> <h3>孫子的元件</h3> 爺爺元件裡面的foo:{{foo.description}}<br/> 爺爺元件裡面的fooReactive:{{fooReactive}}<br/> 爺爺元件裡面的fooReactiveKey1:{{fooReactiveKey1}}<br/> 爺爺元件裡面的fooReactiveKey2:{{fooReactiveKey2}} <span style="padding-left:30px;">=> fooReactiveKey2沒有些key所以取不到哦</span> </div> </template> <script lang="ts"> import { Component, Vue, Inject, InjectReactive, } from 'vue-property-decorator'; @Component export default class ProvideGSonComponent extends Vue { @Inject() readonly foo!: string; @InjectReactive() fooReactive!: string; @InjectReactive('1') fooReactiveKey1!: string; @InjectReactive() fooReactiveKey2!: string; } </script>
demo地址:https://github.com/slailcp/vue-cli3/tree/master/src/pc-project/views/manage
到此這篇關於一文秒懂vue-property-decorator的文章就介紹到這了,更多相關vue-property-decorator內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45