直接從項目開始學習vue+typescript+裝飾器(一)

1.vue-property-decorator 

這個組件徹底依賴於vue-class-component,它具有如下幾個屬性

@Prop

// @Prop 裝飾器是用以接收來自父組件的數據
// 子組件
<template>
<h1>收到:{{msg}}</h1>
</template>
<script lang="ts">
import { Component, Vue,Prop,Model } from 'vue-property-decorator';
@Component({})
export default class LangSelect extends Vue {
@Prop() private msg!: string;
}
</script>

// 父組件
<template>
<div class="login-container">
<lang-select msg='父組件的消息'></lang-select>
</div>
</template>
<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator';
import LangSelect from '@/components/LangSelect/index.vue';
@Component({
components: {
LangSelect
}
})
export default class extends Vue {}
</script>複製代碼

@Model

// @Model 裝飾器是用以組件上實現雙向綁定
// 子組件
<template>
<input type="checkbox" v-on:change="$emit('handleChange',$event.target.checked)" v-bind:checked='checked'>
</template>
<script lang="ts">
import { Component, Vue,Prop,Model } from 'vue-property-decorator';
import { AppModule } from '@/store/modules/app';@Component({})
export default class LangSelect extends Vue {
@Model('handleChange', { type: Boolean }) private checked!: boolean;
}
</script>// 父組件
<template>
<div class="login-container">
<el-button type="primary" @click="onAlterFoo">父組件改變foo</el-button>
<lang-select v-model="foo" class="set-language" size="16px"></lang-select>
</div>
</template>
<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator';
import LangSelect from '@/components/LangSelect/index.vue';
@Component({  name: 'Login',  components: {    LangSelect  }})
export default class extends Vue {  
private foo:boolean = true;  
private onAlterFoo() {
this.foo = !this.foo;
}}
</script>
複製代碼

@Watch

// @Watch 裝飾器是用以監控數據是否改變
<template>
<div class="login-container">
<el-button type="primary" @click="onAlterFoo">父組件改變foo</el-button>
val:{{val}}——oldVal:{{oldVal}}
</div>
</template>
<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator';
import LangSelect from '@/components/LangSelect/index.vue';
@Component({
name: 'Login',
components: {
LangSelect
}})
export default class extends Vue {
private foo:boolean = true;
private val:boolean = true;
private oldVal:boolean = true;  
private onAlterFoo() {
this.foo = !this.foo;  
}
@Watch('foo')  
private handleChanged(val:boolean,oldVal:boolean):void{
this.val = val;
this.oldVal = oldVal;
}}
</script>
複製代碼

@Provide 與 @Inject

//@Provide 裝飾器是用以注入數據,@Inject 裝飾器是用以獲取注入的數據。
// 子組件 @Inject
<template>
<h1>收到:{{bar}}</h1>
</template>
<script lang="ts">
import { Component, Vue, Inject } from 'vue-property-decorator';
@Component({})
export default class LangSelect extends Vue {
@Inject() private readonly bar!:string
}
</script>

// 父組件 @Provide
<template>
<div class="login-container">
@provide/@Inject —— 接收來自父組件的數據:{{foo}}
<lang-select></lang-select>
</div>
</template>
<script lang="ts">
import { Component, Vue, Provide } from 'vue-property-decorator'
import LangSelect from '@/components/LangSelect/index.vue';
@Component({
components: {
LangSelect
}
})
export default class extends Vue {
@Provide('bar') private foo = '啥消息';
}
</script>
複製代碼

@Emit

// @Emit 裝飾器是用以子組件觸發父組件的自定義事件
// 子組件
<template>
<el-dropdown trigger="click" class="international" @command="handleParent">
<div class="el-dropdown-link">
<slot>
<i ref="icon" class="el-icon-setting"></i>
</slot>
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item :disabled="language==='zh'" command="zh">中文</el-dropdown-item>
<el-dropdown-item :disabled="language==='en'" command="en">English</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<script lang="ts">
import { Component, Vue,Prop, Watch,Emit } from 'vue-property-decorator';import { AppModule } from '@/store/modules/app';
@Component({})
export default class LangSelect extends Vue {  
@Prop({default:"14px"}) size!:string  
get language() {    return AppModule.language;  
}  
@Emit() 
private handleParent(){}
}
</script>

// 父組件
<template>
<div class="login-container">
<lang-select @handle-parent='handleMe' class="set-language" size="16px"></lang-select>
</div>
</template>
<script lang="ts">import { Component, Vue, Watch } from 'vue-property-decorator';
import LangSelect from '@/components/LangSelect/index.vue';
@Component({  name: 'Login',  components: {    LangSelect  }})
export default class extends Vue {  
private handleMe(){    console.log('子組件觸發')  }
}
</script>
複製代碼

@Component (徹底繼承於 vue-class-component)

// @Component 裝飾器是用以聲明子組件
// 子組件
<template>
<p>子組件</p>
</template>

<script lang="ts">
import { Component, Vue,Prop, Watch } from 'vue-property-decorator';
@Component
export default class LangSelect extends Vue {}
</script>

// 父組件
<template>
<div class="login-container">
<lang-select class="set-language" @langChanged="changeLanguage" size="16px">{{currentLang}}</lang-select>
</div>
</template>

<script lang="ts">
import { Component, Vue, Watch } from 'vue-property-decorator';
import LangSelect from '@/components/LangSelect/index.vue';
@Component({  name: 'Login',  components: {    LangSelect  }})
export default class extends Vue {}
</script>複製代碼

Mixins (由vue-class-component 提供的名爲mixins的輔助函數) 

// 聲明 resize.ts
import { Component, Vue, Watch } from 'vue-property-decorator';
@Component({  name: 'ResizeMixin'})
export default class extends Vue {
get device() {
return '231323'
}  
get sidebar() {
return '是的'
}
}
// 使用 vue界面
<template>
<div class="login-container"> {{classObj}}  </div>
</template><script lang="ts">
import { mixins } from 'vue-class-component';
import ResizeMixin from '../../layout/mixin/resize';
export default class extends mixins(ResizeMixin) {
get classObj() {
console.log(this.sidebar,this.device)
return this.sidebar;
}
}
</script>
複製代碼

@Ref

// @ref 獲取 DOM 元素
<template>
<div class="login-container">
<input type="text" v-model="value" ref='aButton' />
</div></template><script lang="ts">
import { Vue, Component, Ref } from 'vue-property-decorator';
@Componentexport default class YourComponent extends Vue {
@Ref('aButton') readonly name!: string;  
private value = 'AAA';  
private mounted() {    
console.log(this.name); // <input type="text">  
}
}
</script>複製代碼

@ProvideReactive

參考地址vue

@PropSync

@InjectReactive

2.vuex-module-decorators 

// Vuex 容許咱們將 store 分割成模塊(module)
// 每一個模塊擁有本身的 state、mutation、action、getter、甚至是嵌套子模塊
// index.ts
import Vue from 'vue'import Vuex from 'vuex';
import { IAppState } from './modules/app';
import { IUserState } from './modules/user';
Vue.use(Vuex)
export interface IRootState {
app: IAppState
user: IUserState
}
export default new Vuex.Store<IRootState>({})

// ./modules/app
import { VuexModule, Module, Mutation, Action, getModule } from 'vuex-module-decorators';
import Cookies from 'js-cookie';
import { getSidebarStatus, setSidebarStatus } from '@/utils/cookies';
const initLang = window.appConf.lang;
import store from '@/store';
export enum DeviceType {  
Mobile,  
Desktop,  
language
}
export interface IAppState {  
device: DeviceType  
language:string  
sidebar: {    
opened: boolean    
withoutAnimation: boolean  
}
}
@Module({ dynamic: true, store, name: 'app' })
class App extends VuexModule implements IAppState {  
public sidebar = {    
opened: getSidebarStatus() !== 'closed',    
withoutAnimation: false  
}  
public device = DeviceType.Desktop  
public language = Cookies.get('language') || initLang;  
@Mutation  
private TOGGLE_SIDEBAR(withoutAnimation: boolean) {    
this.sidebar.opened = !this.sidebar.opened    
this.sidebar.withoutAnimation = withoutAnimation    
if (this.sidebar.opened) {      
setSidebarStatus('opened')    
} else {      
setSidebarStatus('closed')    
}  
}  
@Mutation  
private CLOSE_SIDEBAR(withoutAnimation: boolean) {    
this.sidebar.opened = false    
this.sidebar.withoutAnimation = withoutAnimation    
setSidebarStatus('closed')  
}  
@Mutation  
private TOGGLE_DEVICE(device: DeviceType) {    
this.device = device  
}    
@Mutation  
SET_LANGUAGE(language: string) {    
this.language = language;    
Cookies.set('language', language)  
}  
@Action  
public ToggleSideBar(withoutAnimation: boolean) {    
this.TOGGLE_SIDEBAR(withoutAnimation)  
}  
@Action  
public CloseSideBar(withoutAnimation: boolean) {    
this.CLOSE_SIDEBAR(withoutAnimation)  
}  
@Action  
public ToggleDevice(device: DeviceType) {    
this.TOGGLE_DEVICE(device)  
}  //i18n-setting  
@Action({ commit: 'SET_LANGUAGE' })  
async SetLanguage(language: string) {    
return language;  
}
}
export const AppModule = getModule(App)


// ./modules/user

import { VuexModule, Module, Action, Mutation, getModule } from 'vuex-module-decorators';
import { login, logout, getUserInfo } from '@/api/users';
import { getToken, setToken, removeToken } from '@/utils/cookies';
import store from '@/store';
export interface IUserState {  token: string  name: string  avatar: string  introduction: string  roles: string[]}@Module({ dynamic: true, store, name: 'user' })
class User extends VuexModule implements IUserState {  
public token = getToken() || ''
public name = ''
public avatar = ''
public introduction = ''
public roles: string[] = []  
@Mutation  private SET_TOKEN(token: string) {    
this.token = token  
}  
@Mutation  
private SET_NAME(name: string) {    
this.name = name  
}  
@Mutation  
private SET_AVATAR(avatar: string) {    
this.avatar = avatar  
}  
@Mutation  
private SET_INTRODUCTION(introduction: string) {    
this.introduction = introduction  
}  
@Mutation  
private SET_ROLES(roles: string[]) {    
this.roles = roles  
}  
@Action  
public async Login(userInfo: { username: string, password: string }) {    
let { username, password } = userInfo    
username = username.trim()    
const { data } = await 
login({ username, password })    
setToken(data.accessToken)    
this.SET_TOKEN(data.accessToken)  
}  
@Action  public ResetToken() {    
removeToken()    
this.SET_TOKEN('')    
this.SET_ROLES([])  
}  
@Action  
public async GetUserInfo() {    
if (this.token === '') {      
throw Error('GetUserInfo: token is undefined!')    
}    
const { data } = await getUserInfo({ /* Your params here */ })    
if (!data) {      
throw Error('Verification failed, please Login again.')    
}    
const { roles, name, avatar, introduction } = data.user    
// roles must be a non-empty array    
if (!roles || roles.length <= 0) {      
throw Error('GetUserInfo: roles must be a non-null array!')    
}    
this.SET_ROLES(roles)    
this.SET_NAME(name)    
this.SET_AVATAR(avatar)    
this.SET_INTRODUCTION(introduction)  
}  
@Action  
public async LogOut() {    
if (this.token === '') {      
throw Error('LogOut: token is undefined!')    
}    
await logout()    
removeToken()    
this.SET_TOKEN('')    
this.SET_ROLES([])  
}
}
export const UserModule = getModule(User)
複製代碼


參考地址:www.npmjs.com/package/vue…vuex

參考地址:www.npmjs.com/package/vue…npm

相關文章
相關標籤/搜索