TypeScript


# TypeScript 基础

安装 npm install -g typescript
运行 tsc xx.ts

# 基础类型

js 是弱类型,ts 是强类型
布尔值 数字 字符串 数组 元组 枚举 any void null undefined Never object

  • 类型案例

    /* function greeter(person: string) {
    return "Hello, " + person;
    }
    
    let user = "毛茸茸";
    // 如果改成了 数字1,下边的user会报错
    
    document.body.innerHTML = greeter(user); */
    
    // 使用 :类型 规定数据类型
    // 布尔值
    let bool: boolean = true;
    bool = false;
    
    // 数字
    let num: number = 6;
    
    // 字符串
    let username: string = "bob";
    username = "cxh";
    
    // 数组
    // 数字数组
    let arr: number[] = [1, 2, 3];
    // arr[0] = '1'; //错误写法
    arr[0] = 1;
    
    // 字符串数组
    // let arr1: string[] = ["a", "b", "c"];
    // 数组泛型写法
    let arr1: Array<string> = ["a", "b", "c"];
    
    // 元组
    // 元组类型允许表示一个已知元素数量和类型的数组
    let x: [string, number] = ["hello", 100];
    x[1] = 2;
    // x[1] = '2';// 错误写法
    // 越界的元组数据,默认可以使用联合类型替代
    // 比如 x[3] 可以赋值成 数字或字符串
    
    // 枚举 enum
    // 枚举数据类型 Color
    // 需要先创建一个枚举类型的数据
    // 通过编号能拿到名字 通过名字能拿到编号
    enum Color {
      Red,
      Green,
      Blue,
    }
    let c: Color = Color.Green;
    console.log(c); //1
    console.log(Color);
    /* {0: "Red"
    1: "Green"
    2: "Blue"
    Blue: 2
    Green: 1
    Red: 0} */
    // console.log(Color[1]); // Green
    
    // enum Color {Red = 1, Green, Blue} // 编号就成了1,2,3
    // enum Color {Red = 1, Green = 2, Blue = 4} // 编号自定义
    
    // any(任何一种类型) 赋值的时候可以随意赋值
    // let notSure: any = 0;
    // notSure = "嘿嘿嘿";
    
    let list: any[] = [1, true, "free"];
    list[1] = 100;
    
    // void 无类型,和 any 相反
    // 一般只有在函数的返回值类型设置 void
    // 或者创建 undefined 和 null 的时候使用
    
    // undefined 和 null
    // 很少声明 null 或 undefined 类型
    // undefined 和 null 可以赋值给任意类型
    let n: undefined = undefined;
    let u: null = null;
    
    let str = "123";
    let str = undefined; // 不会报错
    
    // Never
    // 基本用不到
    
    // object
    // 很少用下面的方式创建对象
    /* let obj: object = {
    a: 10,
    b: 20,
    }; */
    
    // 类型断言
    // let someValue: any = "this is a string";
    
    // let strLength: number = (<string>someValue).length;
    // <string>someValue 就是类型断言 将 someValue 当成 string 类型
    // 另一种写法
    let someValue: any = "this is a string";
    
    let strLength: number = (someValue as string).length;
    // 两种形式是等价的。 至于使用哪个大多数情况下是凭个人喜好;
    // 然而,当你在TypeScript里使用JSX时,只有 as语法断言是被允许的。
  • 异步输出小案例

    for (var i = 0; i < 5; i++) {
      // var 改成 let 之后 结果变成了 0,1,2,3,4
      // 因为 let 是块级作用域,每个 i 都有一个 setTimeout
      setTimeout(function () {
        // 循环执行完毕之后执行setTimeout
        // 因为同步先执行,异步后执行
        console.log(i);
      }, 100 * i);
      // 100 * i 相当于函数调用 从0开始
    }
    // 5个5 间隔 100毫秒 依次触发

# 类型推论

在有些没有明确指出类型的地方,类型推论会帮助提供类型

  • 案例

    // 类型推论
    // 当没有给变量声明类型,却赋值了,那么 ts 会自动根据值,给这个变量提供对应的类型(类型声明)
    let number = 2;
    // number 被推论成了数字类型
    // 等同于
    // let number: number = 2;
    
    let xxxx = [0, 1, null];
    // xxxx 被推论成数字数组,并不是数字或者 null 数组
    // 因为 ts 底层会默认选择一个最佳的通用类型

# 函数

  • 案例

    // 函数
    /* function add(x, y) {
          return x + y;
          }
          const z = add(1, 2); */
    // 为函数定义类型
    // 1. 参数类型 x: number, y: number
    // 2. 返回值类型 add(x: number, y: number): number(这里的number是返回值类型)
    // 3. 整个函数的类型
    
    // 定义了参数类型和返回值类型,一般这样写
    function add(x: number, y: number): number {
      return x + y;
    }
    const z: number = add(1, 2);
    
    // 返回值无类型,也就是 void 类型
    // void 可省略
    let showInfo = (info: string): void => {
      console.log(info);
    };
    
    // ? 表示可选参数(可传可不传)
    function buildName(firstName: string, lastName?: string) {
      return lastName ? firstName + " " + lastName : firstName;
    }
    const fullName = buildName("李");
    console.log(fullName); // 李
    
    // 函数参数默认值
    function buildName1(firstName: string, lastName = "明") {
      return firstName + " " + lastName;
    }
    const fullName1 = buildName1("张");
    console.log(fullName1); // 张 明
    
    // 剩余参数
    const fun = (...rest: any[]) => {
      console.log(rest); //(6) [1, 2, 3, 4, true, "hello"]
    };
    fun(1, 2, 3, 4, true, "hello");

# 接口

对值所具有的结构进行类型检查

  • 案例

    // 对象的详细类型定义
    const obj: { username: string; password: string } = {
      username: "cxh",
      password: "123",
    };
    
    // 用接口定义对象的规则
    // 接口名称首字母一般大写
    interface UserObj {
      // 必须要有age属性,且类型必须是数字
      age: number;
      // 可选属性 sex,类型为字符串
      // 只读属性 readonly,不可修改
      readonly sex?: string;
      // 任意的属性名 任意的值
      [propName: string]: any;
    }
    
    // 这个函数接收的参数是对象,而且对象里面必须有一个 age 属性,属性值是数字
    // 函数的参数需要满足 UserObj
    // 是一个对象,里边有age属性,且属性类型为数字类型
    function printAge(userObj: UserObj) {
      console.log(userObj.age);
    }
    
    // myObj 对象也需要满足我们定义的接口
    let myObj: UserObj = { sex: "男", age: 10, hobby: ["篮球"] };
    printAge(myObj);
    
    interface Todo {
      id: string;
      text: string;
      isDone?: boolean;
    }
    
    const todos: Todo[] = [
      {
        id: "111",
        text: "222",
      },
    ];
    
    interface SquareConfig {
      color?: string;
      width?: number;
    }
    
    function createSquare(config: SquareConfig): { color: string; area: number } {
      // config是参数,SquareConfig是参数类型
      // { color: string; area: number }是函数设置的返回值,返回的是一个对象
      const width = config.width && 100;
      return {
        color: config.color && "orange",
        area: width * width,
      };
    }
    
    // 正常应该不检查 colour,但是因为 ts 有额外的类型检查,相似的属性名会进行额外的检查,
    // 解决方法是使用类型断言
    // let mySquare = createSquare({ colour: "orange", width: 100 });
    // 解决方法:利用类型断言绕过额外的检查,
    // 告诉SquareConfig我的colour不是你的color,你继续用你的color就行
    let mySquare = createSquare({ colour: "orange", width: 100 } as SquareConfig);
    // console.log(mySquare);//{color: undefined, area: 10000}

# 类

  • 简单案例

    class Cat {
      // 类的属性需要使用属性的新写法,对属性进行类型声明
      type = "猫科类";
      catAge: number = 1; // 相当于初始值
      catName: string; //初始值
    
      // new Greater()是实例化 的时候自动执行 constructor 函数
      constructor(catName: string, catAge: number) {
        this.catName = catName;
        this.catAge = catAge;
        // this.type = "猫科类"; // 也可以在上边写
      }
      say() {
        console.log("喵喵喵");
      }
    }
    const catOne = new Cat("大花", 2);
    console.log(catOne); //Cat {catName: "大花", catAge: 2, type: "猫科类"}
  • 继承案例

    class Animal {
      name: string;
      age: number;
      // 公有方法
      constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
      }
      // 不能加逗号
      move(distance: number = 0) {
        console.log(`${this.name} moved ${distance}m.`);
      }
    }
    const hh = new Animal("老虎", 5);
    // 这里的原型对象是 constructor 和 move
    console.log(hh); //Animal {name: "老虎", age: 5}
    hh.move(100); //老虎 moved 100m.
    
    // 创建一个 Animal 的子类 Cat
    // extends 实现的是
    // 1. super 关键字:将继承的类的 constructor 在子类的 constructor 内执行,
    // 并且将函数内部的 this 替换成子类的 this
    // 2. 将继承的类的原型对象给子类的原型的 __proto__
    
    // 当实例化对象访问一个属性的时候
    // 先找 constructor 然后找 类的实例化对象
    // 然后再看有没有继承,有继承的话 去类的实例化对象的 __proto__
    
    // 当找到最后一层 __proto__ 指的就是 Object 的构造函数的原型(鼻祖),
    // 再往上 __proto__ 就是 null
    
    // 实例对象的 __proto__ 指的是创建这个实例对象的构造函数(类)的原型对象
    // 原型对象的 __proto__ 指的是继承的构造函数(类)的原型对象
    class Cat extends Animal {
      type = "猫科类";
      constructor(name: string, age: number) {
        super(name, age);
      }
      say() {
        console.log("喵喵喵");
      }
    }
    const catOne = new Cat("小花", 2);
    console.log(catOne); // Cat {name: "小花", age: 2, type: "猫科类"}
    // console.log(catOne.__proto__);// 指向的Cat,constructor是Cat本身,有say方法
    // __proto__.__proto__指向的是 Animal,下边有move方法和constructor(是Animal本身)
    catOne.say(); // 喵喵喵
    catOne.move(10); // 小花 moved 10m.
    
    //
    // 类
    class Point {
      x: number;
      y: number;
    }
    
    // 用类的类型声明一个变量
    const pointA: Point = {
      x: 10,
      y: 20,
    };
    
    // 接口
    // 接口继承类
    interface Point3d extends Point {
      z: number;
    }
    
    let point3d: Point3d = { x: 1, y: 2, z: 3 };
    
    // 接口也可以继承接口,使用 extends 关键字
    interface Shape {
      color: string;
    }
    interface PerStroke {
      penWidth: number;
    }
    interface Square extends Shape, PerStroke {
      sideLength: number;
    }
    const square: Square = {
      color: "orange",
      penWidth: 100,
      sideLength: 4,
    };
    
    // 接口的联合类型
    // 既有对象又有函数
    interface Counter {
      // 函数类型
      (start: number): string;
      // 属性
      interval: number;
      // 方法
      reset(): void;
    }
    
    // Counter返回值类型,是接口
    function getCounter(): Counter {
      // 类型断言 把函数断言成了 接口 Counter
      let counter = <Counter>function (start: number) {};
      counter.interval = 123;
      counter.reset = function () {};
      return counter;
    }
    
    let xx = getCounter();
    xx(10);
    xx.reset();
    xx.interval = 5.0;

# 泛型

  • 案例 1

    // <T>:泛型 T 可以换成其他的名字,选T的意思是Type的意思
    // 一旦泛型规定了某个类型,那么后续的所有泛型都是这个类型
    // 一般在变量名之后定义某个泛型  `变量名<T>`:定义了一个泛型T(T以后就代表一个类型了)
    function identity<T>(arg: T): T {
      return arg;
    }
    // 要求 该函数参数和返回值同一个类型,不能用 any
    // 使用泛型解决
    
    // 泛型的使用
    // const res = identity<string>("hello world");
    // 泛型如果不写类型的话会进行类型推论
    // identity(myString),推论成myString类型
    const res = identity(1);
  • 案例 2

    // 多个泛型参数的函数:函数中有多个泛型的参数
    function getMsg<K, V>(value1: K, value: V): [K, V] {
      return [value1, value2];
    }
    
    const arr1 = getMsg<string,number>('jack',100.2345)
    console.log(arr1[0].split('')) // ['j','a','c','k']
    console.log(arr1[1].toFixed(1)) // "100.2"

# 泛型接口

在定义接口时,为接口中的属性或方法定义泛型类型
在使用接口时,再指定具体的泛型类型

  • 案例

    interface IbaseCRUD <T> {
      data: T[] // data: Array<T> 这种写法也可以
      add: (t: T) => void
      getById: (id: number) => T
    }
    
    class User {
      id?: number; //id主键自增,?代表该属性可有可无
      name: string; //姓名
      age: number; //年龄
    
      constructor (name, age) {
        this.name = name
        this.age = age
      }
    }
    
    // 类和泛型接口用 implements
    class UserCRUD implements IbaseCRUD <User> {
      data: User[] = [] // data:Array<User> = [] 这种写法也可以
    
      add(user: User): void {
        user = {...user, id: Date.now()}
        this.data.push(user)
        console.log('保存user', user.id)
      }
    
      getById(id: number): User {
        return this.data.find(item => item.id===id)
      }
    }
    
    
    const userCRUD:UserCRUD = new UserCRUD()
    userCRUD.add(new User('tom', 12))
    userCRUD.add(new User('tom2', 13))
    console.log(userCRUD.data) // [User,User]
    const {id} = userCRUD.add(new User('tom3', 14))
    const res =  userCRUD.getById(id)

# Vue 中使用 ts, 装饰器

装饰器:让类变的更简单,更容易操作
主要创建的是类组件,使用了装饰器语法,使用了两个官方推荐的
vue-class-component 以及 vue-property-decorator

配置代码片段:编辑器 ->f1-> 首选项:配置用户代码片段 ->vue

  • 配置代码片段案例

    {
      // Example:
      "vue script ts": {
        "prefix": "vts", // 按什么出代码片段
        "body": [
          "<script lang='ts'>",
          "import { Component, Vue } from 'vue-property-decorator'",
          "@Component$1",
          "export default class ${TM_FILENAME_BASE} extends Vue {$2}",
          "</script>"
        ],
        "description": "Log output to vue script lang=ts"
      }
    }
  • 装饰器语法的使用

    • Todo 案例

      • App.vue

        <template>
          <div id="app">
            <TodoWrap title="Vue Ts Todo" :count.sync="count" />
          </div>
        </template>
        
        <script lang="ts">
          import { Component, Vue } from "vue-property-decorator";
          import TodoWrap from "./components/TodoWrap.vue"; //要加后缀
          @Component({
            components: {
              TodoWrap,
            },
          })
          export default class App extends Vue {
            // 定义 data
            // count 相当于之前 data 内的 count
            count = 100;
          }
        </script>
      • TodoWrap.vue

        <template>
          <div class="todo-wrap">
            <h1>{{ title }}</h1>
            <p>{{ syncedCount }}</p>
            <button @click="changeCount">按钮</button>
          </div>
        </template>
        
        <script lang="ts">
          import { Component, Vue, Prop, PropSync } from "vue-property-decorator";
          @Component
          // TodoWrap 就是类
          export default class TodoWrap extends Vue {
            // Prop 用法:
            // 需要从 vue-property-decorator 导入 Prop 装饰器
            // Prop 装饰器的写法
            // @Prop()是装饰器
        
            // @Prop(Number) readonly propA: number | undefined
            // @Prop({ default: 'default value' }) readonly propB!: string
            // @Prop([String, Boolean]) readonly propC: string | boolean | undefined
        
            // @Prop({ default: "todo title" })
            // 它是之前prop的写法(写东西就是props:{},不写东西就是props:[]),后面的是类的写法
            // title!: string; 的意思是 非空断言(告诉编译器有值)  !:非空声明断言声明
            // @Prop(String)是接收过来的东西是String类型 ,title是类里变的一个值
            @Prop(String) title!: string;
        
            // @PropSync('name', { type: String }) syncedName!: string
            // @PropSync 装饰器
            // 下面代码相当于之前的
            /* props: {
                count: {
                  type: Number;
                };
              },
            computed:{
              syncedCount:{
                get(){
                    return this.count
                },
                set(value){
                    this.$emit('update:count',value)
                }
              }
            } */
            @PropSync("count", { type: Number }) syncedCount!: number;
        
            // 以前的 methods 里面的函数直接在类里面声明即可
            changeCount() {
              this.$emit("update:count", 200);
            }
          }
        </script>
    • 自定义事件

      • App.vue

        <template>
          <div id="app">
            <TodoWrap
              title="Vue Ts Todo"
              :count.sync="count"
              @change-count1="handleClick"
            />
            <!-- @change="handleClick" -->
          </div>
        </template>
        
        <script lang="ts">
          import { Component, Vue } from "vue-property-decorator";
          import TodoWrap from "./components/TodoWrap.vue"; //要加后缀
          @Component({
            components: {
              TodoWrap,
            },
          })
          export default class App extends Vue {
            count = 100;
            handleClick(value: number) {
              console.log(value);
              this.count = value;
            }
          }
        </script>
      • ToDoWrap.vue

        <template>
          <div class="todo-wrap">
            <div>
              <p>{{ syncedCount }}</p>
              <button @click="changeCount(500)">按钮</button>
              <button @click="changeCount1(300)">按钮</button>
            </div>
            <hr />
            <h1>{{ title }}</h1>
            <TodoHeader v-model="text" />
          </div>
        </template>
        
        <script lang="ts">
          import {
            Component,
            Vue,
            Prop,
            PropSync,
            Emit,
          } from "vue-property-decorator";
          import TodoHeader from "./TodoHeader.vue";
          @Component({
            components: {
              TodoHeader,
            },
          })
          export default class TodoWrap extends Vue {
            text = "123";
            @Prop(String) title!: string;
            @PropSync("count", { type: Number }) syncedCount!: number;
        
            // 使用 @Emit 接收父组件传递的自定义事件
            // 接收到的事件和我们定义的事件会自动合并
        
            // 重名的自定义事件接收
            @Emit() // 重名接收方式
            // @Emit("change") // 不重名的接收方式 @Emit("传过来的名字")
        
            // changeCount1 名字必须和父组件传递的自定义事件名称相同
            // 注意父组件传递的名称写法是烤串写法 xx-xx
            // 接收的时候可以使用小驼峰
            changeCount1(newCount: number) {
              console.log(111);
              // @Emit() 作用就是将自定义事件合并到了组件内的函数内
              // this.$emit("change-count1", 200);
            }
            // 装饰器就是和父组件对接的,函数就是我自己的,
            // 要紧跟着 @Emit() 和 它下面的函数是一组
        
            @Emit("update:count")
            // 之前的 methods 里面的函数直接在类里面声明即可
            changeCount(value: number) {}
          }
        </script>
    • v-model (重点)

      • TodoHeader.vue

        <template>
          <div class="todo-header">
            <input type="text" v-model="text" />
            <button @click="changeText('hhh')">修改父组件的 text</button>
            <button>提交</button>
          </div>
        </template>
        
        <script lang="ts">
          import {
            Component,
            Vue,
            Model,
            Emit,
            ModelSync,
          } from "vue-property-decorator";
          @Component({
            // updated() {
            //   console.log(this.text);
            // },
          })
          export default class TodoHeader extends Vue {
            // @Model('事件名',{prop的类型检验}) value!:string:用 value 接收 prop
            // 事件名的作用是修改传递过来的事件的名 默认是 input 事件可以修改成 change 事件
            // prop 校验类型 可以写成字符串或者布尔值
            @Model("change", { type: String }) value!: string;
        
            // 使用 @Emit() 接收父组件利用 v-model 传递的自定义事件
            // 因为使用 @Model 将事件名修改成了 change,接收的时候也用 change
            @Emit("change")
            changeText(value: string) {}
            // 因为 v-model 会向下传递一个 value 的 prop 和 一个自定义事件
            // @ModelSync 接收 value 和 change 事件,制作成计算属性 text,
            // 并且在计算属性的 set 内执行了 change 事件,自动修改了父组件的 data
            @ModelSync("value", "change", { type: String })
            readonly text!: string;
            // @ModelSync 把 prop 接受完之后制作成计算属性,而且把计算属性里面的东西都修改了
          }
        </script>
    • 监听,防抖,计算属性,Hooks

      <template>
        <div id="app">
          <input type="text" placeholder="请输入你的问题" v-model="question" />
          <p>问题的长度是:{{ questionNum }}</p>
          <p>答案:{{ answer }}</p>
        </div>
      </template>
      
      <script lang="ts">
        import { Component, Vue, Watch } from "vue-property-decorator";
        import TodoWrap from "./components/TodoWrap.vue";
        @Component({
          computed: {
            // answer() {
            //   // 根据 question 去向服务器发请求然后得到答案更新 answer
            //   return this.data;
            // },
            // 计算属性中一般不写异步操作
          },
        })
        export default class App extends Vue {
          question = "";
          answer = "";
          // 计算属性的 get
          get questionNum() {
            return this.question.length;
          }
          // 计算属性的 set
          set questionNum(value) {
            console.log(value);
          }
      
          // Hooks 就是生命周期(就是类里边的方法)
          created() {
            console.log("我是生命周期");
            console.log(this.question);
          }
      
          // @Watch 的使用
          // @Watch('监听的数据',{监听的配置可以设置 immediate 和 deep})
          // @Watch 紧跟着的函数就是数据的监听函数,数据发生改变就会触发
          // 一个数据可以有多个监听
          @Watch("question", { immediate: true })
          onQuestionChanged(newValue: string, oldValue: string) {
            // console.log("初始化时候监听" + newValue);
            this.getAnser(newValue);
            // newValue 是传递的参数
            // 防抖:滚动条触发次数太多,只触发一次
            // 节流
          }
      
          // 根据 question 发请求更新 answer
          getAnser(question: string) {
            // question: string 是接收参数
            setTimeout(() => {
              const questionLen = question.length;
              this.answer =
                questionLen === 0 ? "" : questionLen % 2 === 0 ? "是" : "否";
            }, 200);
          }
      
          /* @Watch("question")
          onQuestionChanged2(newValue: string, oldValue: string) {
            console.log("普通的监听" + newValue);
          } */
        }
      </script>

# Model 系列

  • App.vue

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

    <template>
      <div>
        <h3>@Model @ModelSync @VModel装饰器</h3>
        <!-- 都可以接收 v-model 的值 -->
        <!-- <p>{{ message }}</p>
        <button @click="changeMessage('world')">修改</button> -->
      </div>
    </template>
    
    <script lang="ts">
      import {
        Component,
        Vue,
        Model,
        Emit,
        ModelSync,
      } from "vue-property-decorator";
      @Component
      export default class ModelDemo extends Vue {
        // 将 v-model 传递的给到 message
        /* @Model("xxx", { type: String }) message!: string;
        // 能改事件名(xxx)
        // 用 @Emit() 去接收事件
    
        @Emit("xxx")
        changeMessage(str: string) {
          console.log(str);
        } */
    
        // xxx 表示的是这个组件接收到的 prop 名
        // aaa 表示的是这个组件接收到的 自定义事件名
        // message 表示的是这个组件的计算属性
        // 这个属性有 get 和 set
        // get 的返回值就是刚才接收到的 prop(xxx)  set 执行的就是刚才接收的自定义事件(aaa)
        @ModelSync("xxx", "aaa", { type: String }) message!: string;
    
        // @VModel 用的就是默认传递的 value 和 事件
        // @ModelSync 可以修改 自定义事件名,@VModel 用的是默认的,不可以修改事件名
      }
    </script>

# ts 中用 Vuex

vue add vuex

会自动帮你做一些内容 (创建一个 store->index.ts, 且里边写好内容)

vue cli 3+ 支持 add, 去看 package.json 中看有没有 vue cli

  • 案例

    • App.vue

      <template>
        <div class="app">
          <h3>测试 vuex</h3>
          <!-- <p>{{ myCount }}</p> -->
          <p>{{ count }}</p>
          <!-- <button @click="changeCount(300)">修改 state count</button> -->
          <button @click="setCount(300)">修改 state count</button>
      
          <ul>
            <li v-for="todo in list" :key="todo.id">{{ todo.text }}</li>
          </ul>
          <button @click="add">添加todo</button>
        </div>
      </template>
      
      <script lang="ts">
        import { Component, Vue } from "vue-property-decorator";
        import ModelDemo from "./components/ModelDemo.vue";
        import { State, Mutation, namespace } from "vuex-class";
        import { TodoItem } from "./interfaces";
      
        const todosModule = namespace("todos"); // 模块
      
        @Component({
          components: {
            ModelDemo,
          },
        })
        export default class App extends Vue {
          // @State("count") 去拿 store 中的 count
          // @State("count") myCount!: number;
          // @State((state) => state.count) count!: number;
          @State count!: number;
      
          @Mutation setCount!: Function;
          /* @Mutation("setCount")
        changeCount(value: number) {} */
          // 这个函数相当于给 index.ts 中的 setCount 传
      
          // @State((state) => state.todos.todos) list!: TodoItem[];
      
          // 导入模块
          @todosModule.State("todos") list!: TodoItem[];
          @todosModule.Mutation("addTodo") addTodo!: Function;
      
          add() {
            this.addTodo({ id: "1222", text: "艰苦艰苦", isDone: false });
          }
        }
      </script>
    • index.ts

      import Vue from "vue";
      import Vuex from "vuex";
      import todos from "./modules/todos";
      
      Vue.use(Vuex);
      // vue + ts+ vuex
      // vuex 的语法也要借助其他的包支持 ts 语法
      // vuex-class(没有模块用这个包)
      // vuex-module-decorators(全是模块写法用这个)
      
      export default new Vuex.Store({
        state: {
          count: 100,
        },
        modules: {
          todos,
        },
        mutations: {
          setCount(state, new_count: number) {
            state.count = new_count;
          },
        },
        actions: {},
      });
    • todos.ts
      模块

      // 模块
      import { TodoItem } from "../../interfaces/index";
      // 导入接口
      
      interface InitState {
        todos: TodoItem[];
      }
      
      export default {
        namespaced: "todos",
        // 模块必须加
        state: (): InitState => ({
          todos: [
            { id: "111", text: "嘿嘿嘿", isDone: false },
            { id: "112", text: "嘿嘿嘿11", isDone: false },
          ],
        }),
        mutations: {
          addTodo(state: InitState, todo: TodoItem) {
            state.todos.push(todo);
          },
        },
      };

文章作者: Mrr-cxh
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Mrr-cxh !
赏
 上一篇
Vue 1.0 Vue 1.0
Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
2021-04-23
下一篇 
Webpack Webpack
本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部构建一个 依赖图(dependency graph),此依赖图对应映射到项目所需的每个模块,并生成一个或多个 bundle。
2021-04-08
  目录