美文网首页Vue
vue cli3+typscript 项目(开发篇)

vue cli3+typscript 项目(开发篇)

作者: 偶余杭 | 来源:发表于2020-01-09 12:14 被阅读0次
    image.png

    vue cli3 + typescript 如何进行开发?以下是开发方式小记,还未配置的先看vue cli3+typescript 项目(配置篇)

    组件开发:vue-property-decorator

    在我们使用vue cli3vue create命名创建了包含typescript依赖的项目之后,打开app.vue,我们会发现以前熟悉的代码变样了:

    <template>
    <div id="app"></div>
    </template>
    
    <script lang="ts">
    import { Component, Vue } from "vue-property-decorator";
    import HelloWorld from "./components/HelloWorld.vue";
    
    @Component({
      components: {
        HelloWorld
      }
    })
    export default class App extends Vue {}
    </script>
    

    可以看到项目自动引入了vue-property-decorator这个库,默认使用这个库来进行ts开发。
    它把vue的语句用对应的“装饰器”或方法来实现,有以下装饰器/方法:

    这里挑常用的记录一下

    数据定义

    以前的:

    <template>
      <div>{{msg}}</div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          msg: "这是一条测试数据"
        };
      }
    };
    </script>
    
    <style lang="scss" scoped>
    </style>
    

    现在的:

    <template>
      <div class="hello">{{ msg }}</div>
    </template>
    
    <script lang="ts">
    import { Component, Vue } from "vue-property-decorator";
    
    @Component
    export default class HelloWorld extends Vue {
      msg: string = "这是一条测试数据";
    }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped lang="scss"></style>
    
    
    组件与子组件

    子组件传参用到@prop装饰器:
    以前的:

    <template>
      <div>{{msg2}}</div>
    </template>
    
    <script>
    export default {
      props: {
        msg1: {
          type: Number
        },
        msg2: {
          type: string,
          default: "default value"
        },
        msg3: {
          type: string | boolean
        }
      }
    };
    </script>
    
    <style lang="scss" scoped>
    </style>
    

    对应现在的:

    <template>
      <div class="hello">{{ msg2 }}</div>
    </template>
    
    <script lang="ts">
    //引入Prop
    import { Component, Prop, Vue } from "vue-property-decorator";
    
    @Component
    export default class HelloWorld extends Vue {
      @Prop(Number) readonly msg1: number | undefined;
      @Prop({ default: "default value" }) readonly msg2!: string;
      @Prop([String, Boolean]) readonly msg3: string | boolean | undefined;
    }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped lang="scss"></style>
    
    

    父组件引用子组件的方式:
    以前的

    
    <template>
      <div>
        <HelloWorld :msg1="msg1" msg3="第二条信息"></HelloWorld>
      </div>
    </template>
    
    <script>
    import HelloWorld from "./components/HelloWorld.vue";
    export default {
      components: {
        HelloWorld
      },
      data() {
        return {
          msg: 1
        };
      }
    };
    </script>
    
    <style lang="scss" scoped>
    </style>
    

    对应现在的

    <template>
      <div id="app">
        <HelloWorld :msg1="msg1" msg3="第二条信息"></HelloWorld>
      </div>
    </template>
    
    <script lang="ts">
    //引入Component
    import { Component, Vue } from "vue-property-decorator";
    import HelloWorld from "./components/HelloWorld.vue";
    
    //使用装饰器声明
    @Component({
      components: {
        HelloWorld
      }
    })
    export default class App extends Vue {
      msg1: number = 1;
    }
    </script>
    
    监视 : watch

    watch方法以前的:

    <template>
      <div>
        <HelloWorld :msg1="msg1" msg3="第二条信息"></HelloWorld>
      </div>
    </template>
    
    <script>
    import HelloWorld from "./components/HelloWorld.vue";
    export default {
      components: {
        HelloWorld
      },
      data() {
        return {
          msg: 1,
          person: {
            name: "Amy",
            age: 11
          }
        };
      },
      watch: {
        msg(newValue, oldValue) {},
        person: {
          hander(newValue, oldValue) {},
            immediate: true,
            deep: true
        }
      }
    };
    </script>
    
    <style lang="scss" scoped>
    </style>
    

    对应现在的:

    <template>
      <div id="app">
        <HelloWorld :msg1="msg1" msg3="第二条信息"></HelloWorld>
      </div>
    </template>
    
    <script lang="ts">
    //引入Watch
    import { Component, Vue, Watch } from "vue-property-decorator";
    import HelloWorld from "./components/HelloWorld.vue";
    
    interface Person {
      name: string;
      age: number;
    }
    @Component({
      components: {
        HelloWorld
      }
    })
    export default class App extends Vue {
      msg1: number = 1;
      person: Person = {
        name: "Amy",
        age: 11
      };
      //使用
      @Watch("msg1")
      onChildChanged(val: string, oldVal: string) {}
    
      @Watch("person", { immediate: true, deep: true })
      onPersonChanged1(val: Person, oldVal: Person) {}
      mounted() {}
    }
    </script>
    
    
    计算属性 computed

    以前的:

    <template>
      <div>{{msg2}}</div>
    </template>
    
    <script>
    export default {
      props: {
        msg1: {
          type: Number
        }
      },
      computed: {
        msg2() {
          return this.msg1*2 
        }
      },
    };
    </script>
    
    <style lang="scss" scoped>
    </style>
    

    等同于现在:

    <template>
      <div class="hello">{{ msg2 }}</div>
    </template>
    
    <script lang="ts">
    import { Component, Prop, Vue } from "vue-property-decorator";
    
    @Component
    export default class HelloWorld extends Vue {
      @Prop({ default: 1 }) readonly msg1!: number;
     //设置计算属性,使用get
      get msg2() {
        return this.msg1 * 2;
      }
    }
    </script>
    
    
    事件:emit

    emit事件的写法也有了不同
    以前:

    export default {
      data() {
        return {
          count: 0
        }
      },
      methods: {
        addToCount(n) {
          this.count += n
          this.$emit('add-to-count', n)
        },
        resetCount() {
          this.count = 0
          this.$emit('reset')
        },
        returnValue() {
          this.$emit('return-value', 10)
        },
        onInputChange(e) {
          this.$emit('on-input-change', e.target.value, e)
        },
        promise() {
          const promise = new Promise(resolve => {
            setTimeout(() => {
              resolve(20)
            }, 0)
          })
     
          promise.then(value => {
            this.$emit('promise', value)
          })
        }
      }
    }
    

    现在:

    import { Vue, Component, Emit } from 'vue-property-decorator'
     //不解释了,官网例子
    @Component
    export default class YourComponent extends Vue {
      count = 0
     
      @Emit()
      addToCount(n: number) {
        this.count += n
      }
     
      @Emit('reset')
      resetCount() {
        this.count = 0
      }
     
      @Emit()
      returnValue() {
        return 10
      }
     
      @Emit()
      onInputChange(e) {
        return e.target.value
      }
     
      @Emit()
      promise() {
        return new Promise(resolve => {
          setTimeout(() => {
            resolve(20)
          }, 0)
        })
      }
    }
    

    不过,直接使用以前的写法也是完全没有问题的。

    过滤器:filter

    过滤器用法和以前一样,无改变

    mixin

    mixin的写法:
    以前的:
    mixins写法:

    const test = {
        methods:{
              test(str){
                console.log(str)
              }
        }
    }
    export default test;
    

    引入:

    <template>
      <div>{{ msg2 }}</div>
    </template>
    
    <script>
    import test from "@/mixins/test";
    export default {
      mixins: [test],
      props: {
        msg1: {
          type: Number
        }
      },
      computed: {
        msg2() {
          return this.msg1 * 2;
        }
      },
      mounted() {
        this.test("这是一个mixins");
      }
    };
    </script>
    
    <style lang="scss" scoped></style>
    
    

    等同于现在的:
    mixins写法:

    //test.ts
    import { Vue, Component } from "vue-property-decorator";
    
    @Component
    export default class test extends Vue {
      test(str: string) {
        console.log(str);
      }
    }
    
    

    mixins引入:

    <template>
      <div class="hello">{{ msg2 }}</div>
    </template>
    
    <script lang="ts">
    import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
    import test from "@/mixins/test.ts";
    //注意,不加Component无法引入
    @Component
    export default class HelloWorld extends Mixins(test) {
      @Prop({ default: 1 }) readonly msg1!: number;
      get msg2() {
        return this.msg1 * 2;
      }
      mounted() {
        this.test("这是一个mixins");
      }
    }
    </script>
    
    

    引入多个mixins:

      <div class="hello">{{ msg2 }}</div>
    </template>
    
    <script lang="ts">
    import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
    import test from "@/mixins/test.ts";
    import test1 from "@/mixins/test1.ts";
    
    @Component
    export default class HelloWorld extends Mixins(test,test1) {
      @Prop({ default: 1 }) readonly msg1!: number;
      get msg2() {
        return this.msg1 * 2;
      }
      mounted() {
        this.test("这是一个mixins");
      }
    }
    </script>
    
    
    指令

    指令的引入方式改变了
    以前的引入方式:

    <template>
      <div>{{ msg2 }}</div>
    </template>
    
    <script>
    import test from "@/mixins/test";
    import clickfocus from "@/directives/clickfocus";
    export default {
      mixins: [test],
      directives: { clickfocus },
      props: {
        msg1: {
          type: Number
        }
      },
      computed: {
        msg2() {
          return this.msg1 * 2;
        }
      },
      mounted() {
        this.test("这是一个mixins");
      }
    };
    </script>
    

    现在的:

    <template>
      <div class="hello">{{ msg2 }}</div>
    </template>
    
    <script lang="ts">
    import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
    import test from "@/mixins/test.ts";
    import clickfocus from "@/directives/clickfocus";
    //引入指令
    @Component({
      directives: { clickfocus }
    })
    export default class HelloWorld extends Mixins(test) {
      @Prop({ default: 1 }) readonly msg1!: number;
      get msg2() {
        return this.msg1 * 2;
      }
      mounted() {
        this.test("这是一个mixins");
      }
    }
    </script>
    

    vuex 数据管理

    vuex-class

    使用vuex-class来进行vuex数据管理
    安装:

    npm i vuex-class -D
    

    编辑store:

    image.png
    //store例子:/store/modules/test.ts
    const state: any = {
      name: "测试store"
    };
    
    const mutations: any = {
      setName(state: any, name: string) {
        state.name = name;
      }
    };
    
    const actions: any = {};
    
    export default {
      //namespaced为false的时候,state,mutations,actions全局可以调用
      //为true,生成作用域,引用时要声明模块名称
      namespaced: true, 
      state,
      mutations,
      actions
    };
    
    /store/index.ts
    import Vue from "vue";
    import Vuex from "vuex";
    import testStore from "./modules/test";
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      modules: { testStore }
    });
    
    

    引用:

    <template>
      <div class="hello">{{ msg2 }}</div>
    </template>
    
    <script lang="ts">
    import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
    import test from "@/mixins/test.ts";
    import { State, Getter, Action, Mutation, namespace } from "vuex-class";
    //使用namespace具名引入store
    const testStore = namespace("testStore");
    @Component
    export default class HelloWorld extends Mixins(test) {
      //导入store :testStore中state的name
      @testStore.State(state => state.name) name: any;
      @testStore.Mutation("setName") setName: any;
      readonly msg1!: number;
      get msg2() {
        return this.msg1 * 2;
      }
      mounted() {
        console.log(this.name);
        this.setName("Jake");
        console.log(this.name);
      }
    }
    </script>
    
    vuex-module-decorators

    除了vuex-class,还可以使用vuex-module-decorators管理store
    安装:

    npm i vuex-module-decorators -D
    

    store分模块:

    //store/modules/test.ts
    import { Module, VuexModule, Mutation } from "vuex-module-decorators";
    
    @Module({ name: "testStore", namespaced: true })
    export default class User extends VuexModule {
      name = "测试store";
      @Mutation
      setRight(name: string) {
        this.name = name;
      }
    }
    
    //store/index.ts
    import Vue from "vue";
    import Vuex from "vuex";
    import testStore from "./modules/test";
    
    Vue.use(Vuex);
    
    export default new Vuex.Store({
      modules: { testStore }
    });
    
    

    引用:

    <template>
      <div class="hello">{{ testName }}</div>
    </template>
    
    <script lang="ts">
    import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
    import test from "@/mixins/test.ts";
    import store from "@/store";
    import { getModule } from "vuex-module-decorators";
    import testStore from "@/store/modules/test";
    const test1: any = getModule(testStore, store);
    @Component
    export default class HelloWorld extends Mixins(test) {
     //使用计算属性获取store变量,用来在模板中使用
      get testName() {
        return test1.name;
      }
      @Prop({ default: 1 })
      readonly msg1!: number;
      get msg2() {
        return this.msg1 * 2;
      }
      mounted() {
        console.log(test1.name);
        //调用mutation方法
        test1.setName("Amy");
        console.log(test1.name);
      }
    }
    </script>
    

    如果你觉得这样做比较麻烦,也可以引用时通过vuex-class管理:

    <template>
      <div class="hello">{{ name}}</div>
    </template>
    
    <script lang="ts">
    import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
    import test from "@/mixins/test.ts";
    import { State, Getter, Action, Mutation, namespace } from "vuex-class";
    //使用namespace具名引入store
    const testStore = namespace("testStore");
    @Component
    export default class HelloWorld extends Mixins(test) {
      //导入store :testStore中state的name
      @testStore.State(state => state.name) name: any;
      @testStore.Mutation("setName") setName: any;
      readonly msg1!: number;
      get msg2() {
        return this.msg1 * 2;
      }
      mounted() {
        console.log(this.name);
        this.setName("Jake");
        console.log(this.name);
      }
    }
    </script>
    

    效果一样

    接口发送:axios

    axios的安装配置看vue cli3+typescript 项目(配置篇)
    使用axios进行接口发送:

    <template>
      <div class="hello">{{ msg1}}</div>
    </template>
    
    <script lang="ts">
    import { Component, Prop, Vue, Mixins } from "vue-property-decorator";
    import test from "@/mixins/test.ts";
    @Component
    export default class HelloWorld extends Mixins(test) {
      $get: any;
      $post: any;
      path: string = "api";
      readonly msg1: number = 1;
      get msg2() {
        return this.msg1 * 2;
      }
      getData() {
        this.$get(`${this.path}/getData`, {}).then((d: any) => {
          //返回数据处理
        });
      }
      postData() {
        this.$post(`${this.path}/postData`, {}).then((d: any) => {
          //返回数据处理
        });
      }
      mounted() {
        this.getData();
        this.postData();
      }
    }
    </script>
    

    ts声明

    关于ts声明,声明对象类型:

    interface Data{
      a:string,
      b:number
    }
    

    对于需要有动态变量的对象,即键值名称不固定,声明如下:

    interface Data{
      [key: string]: any;
    }
    

    对于对象中非必有得值,声明中要加问号:

    interface Data{
      a:string,//必有,没有会报错
      b?:number//非必有
    }
    

    对于你实在控制不了类型的变量,直接加any:

    let a:any
    

    相关文章

      网友评论

        本文标题:vue cli3+typscript 项目(开发篇)

        本文链接:https://www.haomeiwen.com/subject/hotkactx.html