# 掘金博客:https://juejin.im/user/579570d679bc44006638c738/posts
# vue-typescript-admin-element-ui
基于Vue+typescript版的后台管理系统模板。
## 项目预览
![](https://user-gold-cdn.xitu.io/2020/1/13/16f9c4f830e52ebf?w=480&h=296&f=gif&s=2863431)
![](https://user-gold-cdn.xitu.io/2020/1/13/16f9c38738097c03?w=2154&h=1350&f=png&s=1595150)
![](https://user-gold-cdn.xitu.io/2020/1/13/16f9c3932101039a?w=2160&h=1350&f=png&s=2216780)
![](https://user-gold-cdn.xitu.io/2020/1/13/16f9c3981b0c483d?w=2430&h=1400&f=png&s=213171)
分享不易,喜欢的话一定别忘了点<font color=red size=12>💖</font>
只关注不点<font color=red size=12>💖</font>的都是`耍流氓`
只收藏也不点<font color=red size=12>💖</font>的也一样是`耍流氓`。
## 简介
ts香不香这里我就不做过多吹捧了,基础[api官方文档](https://typescript.bootcss.com/)有比较清晰的介绍,本篇博客主要分享Vue+typescript+element-ui,后台管理系统实战篇。
简单来说,ts属于强类型语言,它的优势在于静态类型检查,概括来说主要包括以下几点:
- 静态类型检查
- IDE 智能提示
- 代码重构
- 可读性
## 一、技术栈
- Typescript
- vue-cli 3.x+
- Yarn
- Sass
- Element-ui
- Vuex
- ...
## 二、项目说明
```
yarn install //依赖安装
yarn run serve //项目启动
yarn run build:prod //打包
```
## 三、ts用法介绍
本次项目基础框架为Vue,跟正常的Vue项目还是或多或少有不少差距的。众所周知,js是一门弱类型的语言,尤其是在变量赋值时,永远都是给变量直接赋值各种类型值来初始化,线上一些隐藏的bug就冷不防会暴露出来。把这种错误扼杀在项目开发编译阶段而非上线阶段,所有就有了typescript超集的出现。
那Vue中是怎么引用typescript项目的呢,项目开始之前,先大致介绍一番ts在Vue项目中的基础用法
> [vue-property-decorator](https://github.com/kaorun343/vue-property-decorator)
`vue-property-decorator`在`vue-class-component`的基础上增加了更多与`Vue`相关的装饰器,使`Vue`组件更好的跟TS结合使用。这两者都是离不开装饰器的,(decorator)装饰器已在ES提案中。`Decorator`是装饰器模式的实践。装饰器模式呢,它是继承关系的一个替代方案。动态地给对象添加额外的职责。在不改变接口的前提下,增强类的性能。
`vue-property-decorator`是这个Vue项目文件中完全依赖的库,它是Vue官方推荐的并且依赖于[vue-class-component](https://github.com/vuejs/vue-class-component),先介绍下它在项目中的常见用法。
- @Component
- @Emit
- @Provice @Inject
- @Prop
- @Watch
- @Model
- @Minxins
### @Component 类装饰器
首先,Vue页面中的script部分要加一个lang=ts,这样安装好typescript正能引用
```
<script lang="ts">
import {Vue, Component} from 'vue-property-decorator';
import BaseHeader from '@/components/BaseHeader';
//公共头部组件
@Component({
components: {
BaseHeader
}
})
export default class extends Vue {
private stateA:boolean = true
private stateB:string = ''
private stateC:number = 0
private stateD:any = {}
stateE:any[] = []
}
</script>
```
等同于
```
<script>
import Vue from 'vue';
import BaseHeader from '@/components/BaseHeader'; //公共头部组件
export default {
components: {
BaseHeader
},
data(){
return {
stateA: true,
stateB: '',
stateC: 0,
stateD: {},
stateE: []
}
}
}
</script>
```
`vue-property-decorator`在项目中的应用最主要是起一个装饰器的作用,差异化的话看对比就非常直观了
data变量的定义比较多元化,这里区别有加private,不加就是public,当变量标记为private时,它就不能在声明它的类的外部访问。
`@Component`装饰器属性名必须得写上
-------
### @Prop
父子组件之间的属性传值
```
export default class extends Vue {
@Prop({ default: 0 }) private propA!: number
@Prop({ default: () => [10, 20, 30, 50] }) private propB!: number[]
@Prop({ default: 'total, sizes, prev, pager, next, jumper' }) private propC!: string
@Prop({ default: true }) private propD!: boolean,
@prop([String, Boolean]) propE: string | boolean;
}
```
等同于
```
export default {
props: {
propA: {
type: Number
},
propB: {
type: Array,
default: [10, 20, 30, 50]
},
propC: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
propD: {
type: String,
default: 'total, sizes, prev, pager, next, jumper'
},
propE: {
type: [String, Boolean]
}
}
}
```
这里有两个常用修饰符`!``?`,`!`和可选参数`?`是相对的, `!`表示强制解析(也就是告诉typescript编译器,我这里一定有值),你写`?`的时候再调用,`typescript`会提示可能为`undefined`
--------
### @Emit
```
Component
export default class YourComponent extends Vue {
count = 0
@Emit('reset')
resetCount() {
this.count = 0
}
@Emit()
returnValue() {
return 10
}
@Emit()
onInputChange(e) {
return e.target.value
}
}
```
等同于
```
export default {
data() {
return {
count: 0
}
},
methods: {
resetCount() {
this.count = 0
this.$emit('reset')
},
returnValue() {
this.$emit('return-value', 10)
},
onInputChange(e) {
this.$emit('on-input-change', e.target.value, e)
}
}
}
```
`@Emit装饰器`的函数会在运行之后触发等同于其函数名`(驼峰式会转为横杠式写法)`的事件, 并将其函数传递给`$emit`
@Emit触发事件有两种写法
- @Emit()不传参数,那么它触发的事件名就是它所修饰的函数名.
- @Emit(name: string),里面传递一个字符串,该字符串为要触发的事件名
-----------
### @Watch 观察属性装饰器
@Watch装饰器主要用于替代`Vue`属性中的`watch`属性,监听依赖的变量值变化而做一系列的操作
```
@Component
export default class YourComponent extends Vue {
@Watch('child')
onChildChanged(val: string, oldVal: string) {}
@Watch('person', { immediate: true, deep: true })
onPersonChanged(val: Person, oldVal: Person) {}
}
```
等同于
```
export default {
watch: {
child(val, oldVal) {},
person: {
handler(val, oldVal) {},
immediate: true,
deep: true
}
}
}
```
watch 是一个对象,对象就有键,有值。
- 第一个handler:其值是一个回调函数。即监听到变化时应该执行的函数。
- 第二个是deep:其值是true或false;确认是否深入监听。deep的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器(受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除)
- 第三个是immediate:其值是true或false;immediate:true代表如果在 wacth 里声明了之后,就会立即先去执行里面的handler方法,如果为 false就跟我们以前的效果一样,不会在绑定的时候就执行
`@Watch`使用非常简单,接受第一个参数为要监听的属性名, 第二个属性为可选对象。@Watch所装饰的函数即监听到属性变化之后应该执行的函数。
`@Watch`装饰的函数的函数名并非如上`onStateChanged`严格命名,它是多元化的,你可以随心所欲的命名,当然,能按照规范化的命名会使你的代码阅读性更好。
------------
### @Minxins
```
// myMixin.ts
@Component
export default class MyMixin extends Vue {
mixinValue:string = 'Hello World!!!'
}
```
```
// 引用mixins