前言
已经用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测试数据mit("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测试数据mit("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://HdhCmsTestfoobar测试数据/my-app/user/add
const url1 = "https://HdhCmsTestfoobar测试数据/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://HdhCmsTestfoobar测试数据/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://HdhCmsTestfoobar测试数据/my-app/user/add
const url1 = "https://HdhCmsTestfoobar测试数据/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测试数据mit("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://HdhCmsTestfoobar测试数据/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测试数据mit("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语法的详细内容...