前言
初衷: 前几天我在公司其它Vue项目中,发现了是用Decorator装饰器模式开发的,看起来整体代码还不错,于是就做了一下笔记分享给大家,不喜勿喷。
适合人群: 初级前端开发,大佬绕道。
本项目是使用js
和Decorator
装饰器搭建,如果大家项目用的是ts
,那么使用装饰器方法跟本文介绍的不同,请自行参考ts
使用装饰器。需要注意,使用这种模式,变量会存在污染,所以不能出现重名变量
什么是Decorator
Decorator
装饰器是一种类class
相关的语法,所以Decorator
装饰器只能用在class
类里面,在普通的语法或表达式上不能使用。个人理解:装饰器可以给我们提供一层拦截的作用,先执行装饰器里面的东西,后执行我们的操作。具体请看阮一峰老师的《装饰器》
安装
组件
npm install --save vue-class-component
npm install --save vue-property-decorator
配置
在项目的根目录babel.config.js
进行配置如下
module.exports = {
presets: [
'@vue/app'
],
plugins: [
['@babel/plugin-proposal-decorators', { legacy: true }],
['@babel/plugin-proposal-class-properties', { loose: true }],
]
}
在项目的根目录jsconfig.json
进行配置如下
{
"compilerOptions": {
"experimentalDecorators": true
}
}
使用方法
我这里就介绍一下在Vue中常用的几个方法,具体详细的可以看这里Vue-property-decorator
生命周期、methods、data
这些写法都跟原来一样,直接写就行,看如下案例对比
原写法
<script>
export default {
data() {
return {
msg: "hello 蛙人"
}
},
created() {
},
methods: {
test() {
}
}
}
</script>
装饰器写法
<script>
import { Vue } from 'vue-property-decorator'
class App extends Vue {
msg = "hello 蛙人"
created() {
}
test() {
}
}
export default App
</script>
Emit
原写法
<script>
export default {
methods: {
send() {
this.$emit("custom", 123)
}
}
}
</script>
装饰器写法
<script>
import { Vue, Emit } from 'vue-property-decorator'
class Hello extends Vue {
created() {
this.send()
}
@Emit("custom")
send() {
return 123
}
}
export default Hello
</script>
Provide
原写法
<script>
export default {
provide() {
return {
msg: this.msg
}
}
}
</script>
装饰器写法
<script>
class App extends Vue {
@Provide() msg = this.msg
msg = "hello 蛙人"
}
export default App
</script>
Inject
原写法
export default {
inject: {
msg: {
default: () => "",
required: true
}
}
}
</script>
装饰器写法
import { Vue, Component,Inject } from 'vue-property-decorator'
@Component
class Hello extends Vue {
@Inject({ required: true, default: () => "" }) msg
}
export default Hello
Prop
原写法
<script>
export default {
props: {
msg: {
type: () => String,
required: true
}
}
}
</script>
装饰器写法
<script>
import { Vue, Prop } from 'vue-property-decorator'
class Hello extends Vue {
@Prop({ required: true, type: String }) msg
}
export default Hello
</script>
PropSync
原写法
// 父组件
<HelloWorld :msg.sync="msg" v-show="msg"/>
// 子组件
<script>
export default {
props: {
msg: {
require: true
}
},
created() {
setTimeout(() => {
this.test()
}, 5000)
},
methods: {
test() {
this.$emit("update:msg", false)
}
}
}
</script>
装饰器写法
@PropSync
第一个参数则是,this.$emit("update:msg")
里面的msg
, 语句后面则跟着变量
<script>
import { Vue, Component, PropSync } from 'vue-property-decorator'
@Component
class Hello extends Vue {
@PropSync("msg", { required: true }) variable
created() {
setTimeout(() => {
this.variable = false
}, 5000)
}
}
export default Hello
</script>
Watch
原写法
export default {
data() {
return {
str: 123
}
},
created() {
setTimeout(() => {
this.str = 12
}, 5000)
},
watch: {
str: function(newVal, oldVal) {
console.log(newVal, oldVal)
}
}
}
</script>
装饰器写法
import { Vue, Component, Watch } from 'vue-property-decorator'
@Component
class Hello extends Vue {
str = 123
created() {
setTimeout(() => {
this.str = 12
}, 2000)
}
@Watch("str", {deep: true})
test(newVal, oldVal) {
console.log(newVal, oldVal)
}
}
export default Hello
Computed
原写法
<script>
export default {
computed: {
test: {
get() {
return this.msg
},
set(val) {
return this.msg = val
}
}
}
}
</script>
装饰器写法
<script>
import { Vue, Component } from 'vue-property-decorator'
@Component
class App extends Vue {
get test() {
return this.msg
}
set test(val) {
return this.msg = val
}
}
export default App
Model
有时候我们想给组件写一个v-model
方法就可以这样,如下
原写法
// 父组件
<HelloWorld :msg="msg" v-model="msg"/>
// 子组件
<input type="text" @input="test" :value="msg">
<script>
export default {
props: {
msg: {
require: true
}
},
model: {
prop: "msg",
event: "input"
},
methods: {
test(e) {
this.$emit("input", e.target.value)
}
}
}
</script>
装饰器写法
// 父组件
<HelloWorld :msg="msg" v-model="msg"/>
// 子组件
<input type="text" @input="test" :value="msg">
<script>
import { Vue, Component, Model, Emit } from 'vue-property-decorator'
@Component
class Hello extends Vue {
@Model("input", {default: () => ""}) msg
test(e) {
this.send(e)
}
@Emit("input")
send(e) {
return e.target.value
}
}
export default Hello
</script>
Ref
原写法
<HelloWorld :msg="msg" ref="val"/>
<script>
export default {
name: 'App',
components: {
HelloWorld
},
data() {
return {
msg: "hello 蛙人"
}
},
mounted() {
console.log(this.$refs.val)
},
}
</script>
装饰器写法
<HelloWorld :msg="msg" ref="val"/>
<script>
import { Vue, Component, Ref } from 'vue-property-decorator'
@Component({
components: {
HelloWorld
}
})
class App extends Vue {
@Ref("val") val
msg = "hello 蛙人"
mounted() {
console.log(this.val)
}
}
export default App
</script>
Component
该方法是从组件库中导入,如果使用使用生命周期方法,记得引入此装饰器,否则不生效。该装饰器接收一个对象里面也可以写原生Vue
方法。
<script>
import { Vue, Component } from 'vue-property-decorator'
@Component({
components: {
},
watch: {
str: function(val) {
console.log(val)
}
}
})
export class App extends Vue {}
</script>
扩展
当然了可以根据自己的需求扩展封装Decorator
装饰器,装饰器接收三个参数
- 目标对象
- 目标key
- 描述对象
这里不明白描述对象属性可以看我这篇文章《深入理解JavaScript对象》
<script>
function Decorator(data) {
return (vue, key, describe) => {
// vue 当前执行环境对象
// key 当前装饰器函数对象 test
// describe 描述对象里面value是函数
let fn = describe.value
describe.value = function () {
let status = window.confirm(data)
if (status) return fn()
}
}
}
import { Vue, Component } from 'vue-property-decorator'
@Component
class App extends Vue {
@Decorator("请点击确定")
test() {
window.confirm("你是否完成了")
}
}
export default App
</script>
上面example中,可扩展自己的Decorator
装饰器,装饰器就相当于起一层拦截作用,先执行装饰器里面的操作,在执行我们函数本身的逻辑操作。我这里只做一个案例哈,具体看你们的需求。
感谢
谢谢各位在百忙之中点开这篇文章,希望对你们能有所帮助,如有问题欢迎各位大佬指正。
我是蛙人,如果觉得写得可以的话,请点个赞吧。
感兴趣的小伙伴可以加入 前端娱乐圈交流群 欢迎大家一起来交流讨论
往期好文
《聊聊什么是CommonJs和Es Module及它们的区别》
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。