ts+vue-property-decorator

226 阅读1分钟

记录一下在uniapp中使用ts+vue-property-decorator糟糕的一段时间,这简直就是自我折磨,这篇文章也算是自我总结吧ε≡٩(๑>₃<)۶ 一心向学

安装

npm i typescript
npm i vue-class-decorator
npm i vue-property-decorator

在HBuilderX里写代码真的是卡的不行,求救公司大佬换成了VSCode开发过程忘记了,感觉只有自己是菜鸡(。_ 。) ✎_学习计划走起。换成VSCode后感觉任督二脉都打开了,写代码的速度那就要飞起来。

注意

在.vue文件中使用时一定记得在script上写上ts,@Component在单文件里也一定要写,这个就相当于要

<script lang="ts"></script>

data

ts写法 下边的public其实也不用写,在TS中他是默认,我写主要是因为看着好看(^_-)

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

    @Component // 这里一定要写,不然就不识别下边的代码
    // extends就是继承,这里的意思是说明这个组件继承了vue的特性所以在下边的代码块可以使用vue的东西不知道我自己理解的对不对
    export default class "组件名" extends Vue{
        public valueA: string = 'hello world';
        public valueB: number = 1;
    }
</script>

等同于

<script>
    export default {
        data(){
            return {
                valueA: 'hello world',
                valueB: 1,
            }
        }
    }
</script>

computed

ts写法 计算属性就直接用get把要写的逻辑直接搞里头就完事儿,return不用看这个写的太菜只要知道计算属性怎么用就可。

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

    @Component
    export default class "组件名" extends Vue{
        public get title() {
            return `${{
                  1: '标题一',
                  2: '标题二',
                }[this.type]
              }`;
          }
    }
</script>

等同于

<script>
    export default {
        computed: {
            title() {
                `${{
                  1: '标题一',
                  2: '标题二',
                }[this.type]
              }`;
            }
        }
    }
</script>

@Prop

这个父子组件传值用的很多,刚开始写还不熟悉感觉很别扭,写多了就习惯了。

<script lang="ts">
    import {Vue, Component, Prop} from 'vue-property-decorator';
    import BaseResultResultListZntjNrglMcVO from '@/api/schemas/BaseResultResultListZntjNrglMcVO';

    @Component
    export default class "组件名" extends Vue{
        // !是必传的;?是可传可不传;BaseResultResultListZntjNrglMcVO是规定了类型
        @Prop()
	public data!: BaseResultResultListZntjNrglMcVO;

	@Prop({
            default: true,
	}) imgShow?: Boolean
        @Prop(Number) propsA!: number;
        @Prop({default: 'default value'}) propsB!: string;
        @prop([String, Boolean]) propsC: string | boolean;
    }
</script>


BaseResultResultListZntjNrglMcVO.ts
/**
 * BaseResultResultListZntjNrglMcVO
 */

export default interface BaseResultResultListZntjNrglMcVO {
    /**
     * ID
     */
    id?: string;
    /**
     * 类型(1 .课程 2.图书 3.影视 )
     */
    lx?: number;
    /**
     * 名称
     */
    mc?: string;
    /**
     * 发布人
     */
    fbr?: string;
    /**
     * 封面
     */
    fm?: string;
    type?: string
    width?: string
}

等同于

export default {
  props: {
    imgShow: {
      type: Boolean,
      default: true
    },
    propA: {
      type: Number
    },
    propB: {
      default: 'default value'
    },
    propC: {
      type: [String, Boolean]
    },
  }
}

@Watch

属性参数:@Watch(path: string, options: WatchOptions = {})

参数说明:@Watch 装饰器接收两个参数:

path: string 被侦听的属性名; options?: WatchOptions={} options可以包含两个属性 : immediate?:boolean 侦听开始之后是否立即调用该回调函数; deep?:boolean 被侦听的对象的属性被改变时,是否调用该回调函数;

import {Vue, Component, Watch} from 'vue-property-decorator';

@Watch('imageId')
  // onUrlChange这个名字不可重复
  public async onUrlChange() {
    if (this.imageId) {
      this.blobUrl = await imageSrc(this.imageId);
    } else {
      this.blobUrl = '';
      this.previewUrl = '';
    }
  }
@Watch('showModal')
  onChangeValue(newVal: boolean) {
    if (!newVal) {}
}
@Watch('scheme', {immediate: true, deep: true})
onChangeValue(newVal, oldVal){}

等同于

export default{
    watch: {
        showModal(v){
            console.log(v);
        },
        scheme: {
            handler(val) {
               console.log(val);
            },
            immediate: true,
            deep: true,
        }
    },
}

@Ref

属性参数:@Ref(refKey?: string)

参数说明:@Ref 装饰器接收一个可选参数,用来指向元素或子组件的引用信息。如果没有提供这个参数,会使用装饰器后面的属性名充当参数

<template>
  <view>
  <u-form labelPosition="top" :model="formData" ref="form" :rules="formRule" label-width="60pt">
          <u-form-item label="上传附件:" prop="fileList">
              <multi-upload-file v-model="formData.fileList"
                ref="fileUploader"></multi-upload-file>
        </u-form-item>
      </u-form>
  </view>
</template>
 
<script lang="ts">
import { Vue, Component, Ref } from 'vue-property-decorator';
import MultiUploadFile from '@/components/MultiUploadFile.vue';
 
type UFrom = {
  validate(): Promise<void>,
}
 
@Component({
  components: { RefComponent },
})
export default class RefPage extends Vue {
  @Ref()
  public readonly form!: UFrom;
  
  @Ref()
  public fileUploader!: MultiUploadFile; // 下面使用可直接this.fileUploader获取到组件实例
  
  public async handleSubmit(): Promise<void> {
    // 判断是否校验通过
    await this.form.validate();
  }
}
</script>

@Emit

属性参数:@Emit(event?: string)

参数说明: @Emit 装饰器接收一个可选参数,充当事件名。如果没有提供这个参数,@Emit会将回调函数名的camelCase转为kebab-case,并将其作为事件名; @Emit的回调函数的参数,会在回调函数没有返回值的情况下,被emit当做第二个参数使用。@Emit会将回调函数的返回值作为第二个参数,如果返回值是一个Promise对象,emit当做第二个参数使用。@Emit会将回调函数的返回值作为第二个参数,如果返回值是一个Promise对象,emit会在Promise对标记为resolved之后触发。 说实话还不如原生的this.$emit好用

        import { Vue, Component, Prop } from 'vue-property-decorator';
        // 这完全是反着来的还只能传两个参数没有this.$emit传的多 ̄へ ̄
        // @Emit('cardClick')
	// handlePageClick(part: string) :BaseResultResultListZntjNrglMcVO {
	// 	return this.data;
	// }
	//  卡片点击事件
	public handlePageClick(part: string) {
		this.$emit('cardClick', part, this.data);
	}

@Model

双向绑定这就不多说了直接上代码

    import { Vue, Component, Prop, Model } from 'vue-property-decorator';
    @Model('change', { default: () => [] })
    fileList!: { blobPath: string; fileName: string }[];
    
    public async chooseFile() {
    // 这里的代码本来想省去,但是还是想看看有没有大佬可以提供一下优化意见的
    const chooseRes = await new Promise<UniNamespace.ChooseFileSuccessCallbackResult>((resolve, reject) => {
      uni.chooseFile({
        complete: (res) => resolve(res),
        fail: (err) => reject(err),
      })
    });

    const blobPaths = chooseRes.tempFilePaths as string[];
    this.files.push(...blobPaths.map((blobPath, index) => {
      const fileName = (chooseRes.tempFiles as File[])[index].name;
      return { blobPath, fileName };
    }));
    const uploadResult = await this.upload();
    // 这个是主要代码
    this.$emit('change', uploadResult);
  }

Mixins

这个混入和原来的写法差不多了,都需要在根目录下创建mixins文件了 文件是mixins/pageBack.ts这个文件主要是解决uniapp打包H5后再页面中刷新返回上一页会失效,文件内容这样写主要可以有两种写法

// 定义要混合的类 mixins.ts
import { Vue, Component } from 'vue-property-decorator';

@Component // 一定要用Component修饰
export default class PageBackMixins extends Vue {
        // 页面返回
	public handleUNavbarLeftClick() {
		let canNavBack = getCurrentPages();
		if (canNavBack && canNavBack.length > 1) {
			uni.navigateBack({
				delta: 1
			});
		} else {
			history.back();
		}
	}
}


在页面中引用 第一种:

import { Vue, Component, Prop } from 'vue-property-decorator';
import PageBackMixins from '@/mixins/pageBack';
@Component({
    mixins: [PageBackMixins],
})

第二种:

import { Vue, Component, Prop } from 'vue-property-decorator';
import PageBackMixins from '@/mixins/pageBack';
export default class MultiUploadFile extends PageBackMixins {
    // 这里可直接使用方法
}

到此文章结束,希望我能坚持的住记录自己项目中遇到的坑 …φ(๑˃∀˂๑)♪ 学习是我的全部

672f973cecf341eba21b874362384bc6.jpg