zoukankan      html  css  js  c++  java
  • vue如何使用TypeScript语法

    前言

    已经用TS写了半年了多了,然后总结下如何如何在vue项目中使用ts吧,好复习

    主要内容包含:组件,axios请求,vuex,父子组件传值,Mixins等。

    vue中常用功能点代码用js/ts写法分开书写,这样会好区别和理解

    一、新建项目

    vue create vue-ts-admin

    按步骤开始安装,安装过程中选择TypeScript,vuex,路由router; 使用npm run serve启动项目

    1. 在vue中书写ts的必备插件!

    vue-class-component 强化 Vue 组件,使用装饰器语法使 Vue 组件更好的跟TS结合使用。 vue-property-decorator在 vue-class-component 的基础上增加了更多与 Vue 相关的装饰器,使Vue组件更好的跟TS结合使用。

    npm i vue-class-component -s-d
    npm i  vue-property-decorator -s-d

    二、ts写vue单文件写法

    2.1单页面格式怎么写

    vue单页面的格式的写法不变,同样由template、script、style组成; 唯一区别:<script src="ts">

    <template>
      <div class="hello"></div>
    </template>
    <script src="ts"></script>
    <style scoped></style>

    2.1.1 vue项目中的mian.ts及app.vue

    main.ts写法

    import Vue from 'vue'
    import App from './App.vue'
    //vuex
    import store from './store'
    // 路由
    import router from './router'
    Vue.config.productionTip = false
    
    new Vue({
      store,
      router,
      render: h => h(App)
    }).$mount('#app')

    app.vue写法

    <template>
      <div id="app">
        <!-- 使用路由的方法,也可以不用路由,直接引子组件 -->
        <router-view></router-view>
      </div>
    </template>
    
    <script lang="ts">
    //注意点:1.下面的代码必须在每个页面都中引入
    import { Component, Vue } from 'vue-property-decorator';
    @Component
    //注意点:2.每个页面都有组件名称:App/自定义
    export default class App extends Vue {
    
    }
    </script>

     

    2.2 如何在Data双向绑定值

    • js写法
    <template>
      <div class="hello">
        <h1>{{msg}}</h1>
      </div>
    </template>
    <script>
    export default {
       data() {
        return {
          msg: "",
        };
      },
    }
    </script>
     
    • ts写法
    <template>
      <div class="hello">
        <h1>{{msg}}</h1>
      </div>
    </template>
    <script src="ts">
    import { Component, Vue, } from "vue-property-decorator";
    @Component
    export default class Home extends Vue {
      //注意点:3.public是公用的意思,可省略;没有data,return,直接放要绑定的值
      public msg!: number | string;
      // msg!: number | string;
    }
    </script>

    2.3 如何引入子组件及组件传值

    • js写法
    <template>
      <div class="hello">
        <MenuBar :setMsg="msg"/>
      </div>
    </template>
    <script>
    import MenuBar from "../components/MenuBar.vue";
    export default {
      props: {
        // 父组件的值
        fatherMsg: {
          type: String
        }
      },
      components: {
        MenuBar
      },
      data() {
        return {
          msg: "",
        };
      },
    }
    </script>
    • ts写法
    <template>
      <div class="hello">
        <MenuBar :setMsg="msg" />
      </div>
    </template>
    <script src="ts">
    import { Component, Vue, } from "vue-property-decorator";
    import MenuBar from "../components/MenuBar.vue";
    @Component({
      components: {
        MenuBar
      },
    })
    export default class Home extends Vue {
      // 父组件的传递过来的值
      @Prop() private fatherMsg!: string;
      //传递给子组件的值
      public msg!: number | string;
    }
    </script>

    2.4 生命周期的用法

    • js写法
    <template>
      <div class="hello">
        <h1>{{msg}}</h1>
      </div>
    </template>
    <script>
    var data = {name: "小明",age: 18};
    export default {
       data() {
        return {
          msg: "",
        };
      },
      created() {
        this.msg = data.name + data.age + "岁";
      },
    }
    </script>
    • ts写法
    <template>
      <div class="hello">
        <h1>{{msg}}</h1>
      </div>
    </template>
    <script  src="ts">
    import { Component, Vue, } from "vue-property-decorator";
    var data = {name: "小明",age: 18};
    @Component
    export default class Home extends Vue {
      public msg!: number | string;
      created(): void {
        console.log("created");
        this.msg = data.name + data.age + "岁";
      }
      beforeCreate(): void {
        console.log("beforecreate");
      }
      beforeMount(): void {
        console.log("beforemounted");
      }
      mounted(): void {
        console.log("mounted");
      }
    }
    </script>

    2.5 methods方法

    • js写法
    <template>
      <div class="hello">
        <h1>{{count}}</h1>
        <button class="btn" @click="addCount">add</button>
      </div>
    </template>
    <script>
    var data = {name: "小明",age: 18};
    export default {
       data() {
        return {
          count: 0,
        };
      },
      methods: {
        addCount() {
          return this.count++;
        }
      }
    }
    </script>
    • ts写法
    <template>
      <div class="hello">
        <h1>{{count}}</h1>
        <button class="btn" @click="addCount">add</button>
      </div>
    </template>
    <script  src="ts">
    import { Component, Vue, } from "vue-property-decorator";
    var data = {name: "小明",age: 18};
    @Component
    export default class Home extends Vue {
      public count: number = 0;
      //   方法也是直接写到外层
      addCount(): number {
        return this.count++;
      }
    }
    </script>
     

    2.6 计算属性(computed)和监听属性(watch)

    • js写法
    <template>
      <div class="hello">
      <h1>计算属性:{{countChange}},结果+2:{{watchMsg}}</h1>
        <button class="btn" @click="addCcountChange">计算属性:add</button>
        <h1>监听:{{count}},结果+1:{{watchMsg}}</h1>
        <button class="btn" @click="addCount">监听add</button>
      </div>
    </template>
    <script>
    var data = {name: "小明",age: 18};
    export default {
       data() {
        return {
          count: 0,
          watchMsg: ""
        };
      },
      watch: {
        count: {
          handler(newVal, oldVal) {
            if (newVal < 10) {
              this.watchMsg = "我是数字" + newVal;
            } else {
              this.watchMsg = "我会继续增长";
            }
          },
          immediate: true
        },
        watchMsg: {
          handler(newVal, oldVal) {
            console.log(newVal);
          },
          immediate: true
        }
      },
      computed: {
        countChange: {
          get() {
            return this.count;
          },
          set(val) {
            this.count = val + 1;
          }
        }
      },
      methods: {
       addCcountChange() {
          return this.countChange;
        },
        addCount() {
          return this.count++;
        }
      }
    }
    </script>
    • ts写法
    <template>
      <div class="hello">
        <h1>计算属性:{{countChange}},结果+2:{{watchMsg}}</h1>
        <button class="btn" @click="addCcountChange">计算属性:add</button>
        <h1>监听:{{count}},结果+1:{{watchMsg}}</h1>
        <button class="btn" @click="addCount">监听add</button>
      </div>
    </template>
    <script  src="ts">
    // 注意1.导入Watch
    import { Component, Vue,Watch } from "vue-property-decorator";
    var data = {name: "小明",age: 18};
    @Component
    export default class Home extends Vue {
      public count: number = 0;
      public watchMsg: string = "开始";
        //   计算属性
      get countChange(): number {
        return this.count;
      }
      set countChange(val) {
        this.count = val + 1;
      }
      // 注意2. 监听多个就导入多个Watch,命名自定义 clgMsg(newVal: string)
      @Watch("count")
      Count(newVal: number) {
        if (newVal < 10) {
          this.watchMsg = "我是数字" + newVal;
        } else {
          this.watchMsg = "我会继续增长";
        }
      }
      @Watch("watchMsg")
      clgMsg(newVal: string) {
        console.log(newVal);
      }
       //   方法
      addCcountChange(): number {
        return this.countChange++;
      }
      addCount(): number {
        return this.count++;
      }
    }
    </script>
     

    2.7 Mixins混入如何使用

    Mixins混入是公共方法同一调用;

    2.7.1 Mixins文件的写法

    • js写法
    export const TestMixins = {
        data(){
          return{
            form:{}
          }
        },
        methods:{
          handleSubmit(name): {
            return new Promise((resolve) => {
                resolve()
            })
          }
          handleReset(name){
            console.log(name)
            return name
          }
        }
    }
    • TS写法
    //必须引入
    import { Component, Vue, } from "vue-property-decorator";
    // 导出模块
    declare module 'vue/types/vue' {
        interface Vue {
            form: Object
            handleSubmit(name: any): Promise<any>
            handleReset(name: any): void
        }
    }
    @Component
    export default class TestMixins extends Vue {
        form: Object = {}
        handleSubmit(name: any): Promise<any> {
            return new Promise((resolve) => {
                resolve()
            })
        }
        handleReset(name: any): void {
            console.log(name)
            return name
        }
    }
     

    2.7.2 调用Mixins的vue文件写法

    • js写法
    <template>
      <div class="hello">
         <h1>{{handleReset("测试js-mixins")}}</h1>
      </div>
    </template>
    <script>
    import TestMixins from "../assets/mixin";
    export default {
       mixins: [TestMixins],
       data() {
        return {
          count: 0,
        };
       },
    }
    </script>
     
    • ts写法
    <template>
      <div class="hello">
          <h1>{{handleReset("测试TS-mixins222")}}</h1>
      </div>
    </template>
    <script  src="ts">
    import TestMixins from "../assets/mixin";
    import { Component, Vue, Mixins} from "vue-property-decorator";
    // 写在@Component内
    @Component({
      mixins: [TestMixins]
    })
    export default class Home extends Vue {
      public count: number = 0;
    }
    </script>
     

    2.8 路由vue-Router及路由守卫

    2.8.1 安装导入路由—— mian.ts

    import Vue from 'vue'
    import App from './App.vue'
    import store from './store'
    import router from './router'
    //1.导入组件
    import Component from 'vue-class-component'
    Vue.config.productionTip = false
    
    // 1.全局的路由守卫,js和ts的写法一致;
    // 2.组件内路由守卫,如果要在组件内部使用路由监听,路由钩子beforeRouteEnter,beforeRouteLeave,beforeRouteUpdate不生效。所以在此注册;
    Component.registerHooks([
      'beforeRouteEnter',//进入路由之前
      'beforeRouteLeave',//离开路由之前
      'beforeRouteUpdate'
    ])
    
    new Vue({
      store,
      router,
      render: h => h(App)
    }).$mount('#app')
     

    2.8.2 路由index文件写法—— router/index.ts

    import Vue from 'vue';
    import Router from 'vue-router';
    import stickyNotePage from '../page/stickyNotePage.vue';
    
    export default new Router({
        // history模式
        mode: 'history',
        base: process.env.BASE_URL,
        routes: [
            // 常规模块加载
            {
                path: '/',
                name: 'stickyNotePage',
                component: stickyNotePage,
            },
            // 路由懒加载写法
            {
                path: '/hello',
                name: 'hello',
                component: () => import(/* webpackChunkName: "hello" */'../page/HelloWorld.vue'),
            },
            {
                path: '/learn',
                name: 'learn',
                component: () => import(/* webpackChunkName: "learn" */'../page/learn.vue'),
            },
        ],
    })
    Vue.use(Router);

    2.8.3 在页面中如何使用路由守卫

    全局的路由守卫,js和ts的写法一致;
    // 全局守卫
    import router from './router'
    router.beforeEach((to, from, next) => {    
        console.log(to.path);
        next()    
    })
    // 全局后置钩子
    router.afterEach((to,from)=>{
      alert("after each");
    })
    组件内路由守卫
    • js写法
    <template>
      <div class="hello">
        <h1>{{count}}</h1>
        <button class="btn" @click="addCount">add</button>
      </div>
    </template>
    <script>
    var data = {name: "小明",age: 18};
    export default {
       data() {
        return {
          count: 0,
        };
      },
       // 进入路由触发
      beforeRouteEnter(to,from,next)=>{
        console.log("beforeRouteEnter111");
        next();
      }
      beforeRouteUpdate(to,from,next)=>{
        console.log("beforeRouteUpdate111");
        next();
      }
      // 离开路由触发
      beforeRouteLeave(to,from,next)=>{
        console.log("beforeRouteLeave111");
        next();
      }
    
    }
    </script>
    • ts写法
    <template>
      <div class="hello">
        <h1>{{count}}</h1>
      </div>
    </template>
    <script  src="ts">
    import { Component, Vue, } from "vue-property-decorator";
    @Component
    export default class Home extends Vue {
      public count: number = 0;
       // 进入路由触发
      beforeRouteEnter(to: any, from: any, next: () => void): void {
        console.log("beforeRouteEnter111");
        next();
      }
      beforeRouteUpdate(to: any, from: any, next: () => void): void {
        console.log("beforeRouteUpdate111");
        next();
      }
      // 离开路由触发
      beforeRouteLeave(to: any, from: any, next: () => void): void {
        console.log("beforeRouteLeave111");
        next();
      }
    }
    </script>

    2.9 vuex

    2.9.1 vuex/scr/store/index.ts写法

    js、ts写法除了类型判断其他区别不大;

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        isShowEdit: false,
        onlySticky: null,
      },
      mutations: {
        SHOW_EDIT(state: any, editMemo: any) {
          console.log(editMemo)
          state.onlySticky = editMemo;
          state.isShowEdit = true;
        }
      },
      actions: {
      },
      modules: {
      }
    })
     

    2.9.2 vuex调用单页面的写法

    • js写法
    <template>
      <div class="hello">
        <button @click="showEdit('vuex')">测试vuex</button>
      </div>
    </template>
    <script>
    import { mapActions, mapState, mapGetters, mapMutations } from "vuex";
    export default {
       data() {
        return {
          stickyList:[],
        };
       },
       created() {
        this.stickyList = this.$store.state.onlySticky;
      },
        methods: {
        ...mapMutations(["SHOW_EDIT"]),
        showEdit(item) {
          this.$store.commit("SHOW_EDIT", item);
        },
      }
    }
    </script>
    • ts写法
    <template>
      <div class="hello">
         <button @click="showEdit('vuex')">测试vuex</button>
      </div>
    </template>
    <script  src="ts">
    import { Component, Vue,} from "vue-property-decorator";
    import ItemData from "../model/ItemData"; //导入类
    // 写在@Component内
    @Component
    export default class Home extends Vue {
      stickyList: [ItemData] = this.$store.state.onlySticky;
     // vuex,如果this.$store一直报错,则在单页面引入 import Vuex from 'vuex'
      showEdit(item) {
        this.$store.commit("SHOW_EDIT", item);
      }
    }
    </script>

    2.10 axios请求数据

    2.10.1 main.ts

    import axios from 'axios'
    Vue.prototype.$axios = axios;
     

    关于axios的封装,在之前的博客中已经讲述过了,就不在封装,ts语法除了类型其他区别不大,这里直接使用的是挂载axios和引入axios的方式,

    2.10.2 单页使用

    • js写法
    <template>
      <div class="hello">
        axios请求
      </div>
    </template>
    <script>
    export default {
       data() {
        return {
        };
       },
       created() {
        // 请求地址  https://www.foobar.com/my-app/user/add
        const url1 = "https://www.foobar.com/my-app/user/add";
        this.$axios.get(url1, { params: { type: "js" } }).then(res => {
          console.log(res);
        });
        // 使用vue代理
        const url2 = "/my-app/user/add";
        this.$axios.get(url2, { params: { type: "Ts" } }).then(res => {
          console.log(res);
        });
      },
    }
    </script>
    • ts写法
    <template>
      <div class="hello">
        axios请求
      </div>
    </template>
    <script  src="ts">
    import { Component, Vue,} from "vue-property-decorator";
    import axios from "axios";
    // 写在@Component内
    @Component
    export default class Home extends Vue {
       created(): void {
        const url1 = "https://www.foobar.com/my-app/user/add";
        axios.get(url1, { params: { type: "js" } }).then((res: any) => {
          console.log(res);
        });
        // 使用vue代理
        const url2 = "/my-app/user/add";
        axios.get(url2, { params: { type: "Ts" } }).then((res: any) => {
          console.log(res);
        });
      }
    }
    </script>

    附:js常规书写vue--demo源码

    <template>
      <div class="hello">
        <MenuBar />
        <router-link :to="{path:'hello'}">测试路由守卫-->去helloword</router-link>
        <h1>{{handleReset("测试mixins222")}}</h1>
        <h1>{{msg}}</h1>
        <h1>{{fatherMsg}}</h1>
        <h1>计算属性:{{countChange}},结果:{{watchMsg}}</h1>
        <button class="btn" @click="addCcountChange">计算属性:add</button>
        <h1>监听:{{count}},结果:{{watchMsg}}</h1>
        <button class="btn" @click="addCount">监听add</button>
        <button @click="showEdit('vuex')">测试vuex</button>
      </div>
    </template>
    <script>
    import MenuBar from "../components/MenuBar.vue";
    import TestMixins from "../assets/mixin";
    import { mapActions, mapState, mapGetters, mapMutations } from "vuex";
    
    var data = {
      name: "小明",
      age: 18
    };
    export default {
      props: {
        fatherMsg: {
          type: String
        }
      },
      mixins: [TestMixins],
      components: {
        MenuBar
      },
      data() {
        return {
          msg: "",
          count: 0,
          watchMsg: "",
          stickyList: []
        };
      },
      created() {
        this.msg = data.name + data.age + "岁";
        this.stickyList = this.$store.state.onlySticky;
      },
      mounted() {
        // 页面内部使用路由守卫
        this.$router.beforeEach((to, from, next) => {
          console.log("我要去" + from.name);
          next();
        });
        // axios请求
        // 请求地址  https://www.foobar.com/my-app/user/add
        const url1 = "https://www.foobar.com/my-app/user/add";
        this.$axios.get(url1, { params: { type: "js" } }).then(res => {
          console.log(res);
        });
        // 使用代理
        const url2 = "/my-app/user/add";
        this.$axios.get(url2, { params: { type: "Ts" } }).then(res => {
          console.log(res);
        });
      },
      watch: {
        countChange: {
          handler(newVal, oldVal) {
            if (newVal < 5) {
              this.watchMsg = "我是数字" + newVal;
            } else {
              this.watchMsg = "我会继续增长";
            }
          },
          immediate: true
        },
        watchMsg: {
          handler(newVal, oldVal) {
            console.log(newVal);
          },
          immediate: true
        }
      },
      computed: {
        countChange: {
          get() {
            return this.count;
          },
          set(val) {
            this.count = val + 2;
          }
        }
      },
      methods: {
        ...mapMutations(["SHOW_EDIT"]),
        showEdit(item) {
          this.$store.commit("SHOW_EDIT", item);
        },
        addCcountChange() {
          return this.countChange++;
        },
        addCount() {
          return this.count++;
        }
      }
    };
    </script>
    View Code

    demo-上述代码用Ts书写vue

    <template>
      <div class="hello">
        <MenuBar />
        <router-link :to="{path:'learn'}">测试路由守卫-->去learn</router-link>
        <h1>{{handleReset("测试mixins111")}}</h1>
        <h1>{{msg}}</h1>
        <h1>{{fatherMsg}}</h1>
        <h1>计算属性:{{countChange}},结果+2:{{watchMsg}}</h1>
        <button class="btn" @click="addCcountChange">计算属性:add</button>
        <h1>监听:{{count}},结果+1:{{watchMsg}}</h1>
        <button class="btn" @click="addCount">监听add</button>
        <button @click="showEdit('vuex')">测试vuex</button>
      </div>
    </template>
    
      <!-- 使用ts书写js -->
    <script lang="ts">
    import router from "../router";
    import { Component, Prop, Vue, Watch, Mixins } from "vue-property-decorator";
    import MenuBar from "../components/MenuBar.vue";
    import TestMixins from "../assets/mixin";
    import ItemData from "../model/ItemData"; //导入类
    import axios from "axios";
    var data = {
      name: "小明",
      age: 18
    };
    // 组件
    @Component({
      components: {
        MenuBar
      },
      mixins: [TestMixins]
    })
    export default class Home extends Vue {
      @Prop() private fatherMsg!: string;
      //   挂载值
      public msg!: number | string;
      public count: number = 0;
      public watchMsg: string = "开始";
      stickyList: [ItemData] = this.$store.state.onlySticky;
      //   声明周期
      created(): void {
        console.log("created");
        this.msg = data.name + data.age + "岁";
    
        const url1 = "https://www.foobar.com/my-app/user/add";
        axios.get(url1, { params: { type: "js" } }).then((res: any) => {
          console.log(res);
        });
        // 使用vue代理
        const url2 = "/my-app/user/add";
        axios.get(url2, { params: { type: "Ts" } }).then((res: any) => {
          console.log(res);
        });
      }
      beforeCreate() {
        console.log("beforecreate");
      }
    
      beforeMount() {
        console.log("beforemounted");
      }
      mounted() {
        console.log("mounted");
        // 页面内部使用路由守卫
        // router.beforeEach((to, from, next) => {
        //   console.log("我来自" + from.name);
        //   next();
        // });
      }
      // 进入路由触发
      beforeRouteEnter(to: any, from: any, next: () => void): void {
        console.log("beforeRouteEnter111");
        console.log(to.path);
        next();
      }
    
      beforeRouteUpdate(to: any, from: any, next: () => void): void {
        console.log("beforeRouteUpdate111");
        next();
      }
      // 离开路由触发
      beforeRouteLeave(to: any, from: any, next: () => void): void {
        console.log("beforeRouteLeave111");
        next();
      }
      //   计算属性
      get countChange(): number {
        return this.count;
      }
      set countChange(val) {
        this.count = val + 1;
      }
      //   监听
      @Watch("count")
      Count(newVal: number) {
        if (newVal < 10) {
          this.watchMsg = "我是数字" + newVal;
        } else {
          this.watchMsg = "我会继续增长";
        }
      }
      @Watch("watchMsg")
      clgMsg(newVal: string) {
        console.log(newVal);
      }
      //   方法
      addCcountChange(): number {
        return this.countChange++;
      }
      addCount(): number {
        return this.count++;
      }
      // vuex
      showEdit(item) {
        this.$store.commit("SHOW_EDIT", item);
      }
    }
    </script>
    
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped lang="less">
    h3 {
      margin: 40px 0 0;
    }
    ul {
      list-style-type: none;
      padding: 0;
    }
    li {
      display: inline-block;
      margin: 0 10px;
    }
    a {
      color: #42b983;
    }
    </style>
    View Code

    总结

    还是以vue2.0的版本为主的,后面在看看vue3 的写法 ,其实也差不多吧,用法 继续折腾吧 少年

  • 相关阅读:
    前端常见跨域解决方案
    前端必须要懂的浏览器缓存机制
    判断一个变量是数组还是对象
    javascript中Array常用方法
    Javascript数据类型
    Email接收验证码,以实现登录/注册/修改密码
    web安全之机器学习入门——3.2 决策树与随机森林
    web安全之机器学习入门——3.1 KNN/k近邻
    web安全之机器学习入门——2.机器学习概述
    cmd下的一些小技巧
  • 原文地址:https://www.cnblogs.com/yf-html/p/13723268.html
Copyright © 2011-2022 走看看