好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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 >
    <!-- 使用路由的方法,也可以不用路由,直接引子组件 -->
    <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 的写法 ,其实也差不多吧,用法 继续折腾吧 少年

查看更多关于vue如何使用TypeScript语法的详细内容...

  阅读:62次