本文会以三种形式实现一个组件,该组件实现以下功能:
1.显示一个数字(可从prop给初始值)和一个添加按钮;
2.点击添加按钮数字增加;
3.当数字大于5时,数字颜色变红,并提交error事件。
第一种,逻辑直接写在组件内部
<template>
<div :class="{error:isError}">{{ count }}</div>
<button @click="addCount">add</button>
</template>
<script setup lang="ts">
import {defineEmits, defineProps, ref, watch} from "vue";
// -----props-----
interface PropModel {
initCount?: number
}
const prop = defineProps<PropModel>()
// -----emits----
interface EmitModel {
/**
* 上报异常
* @param e
* @param count 异常值
*/
(e: 'error', count: number): void
}
const emit = defineEmits<EmitModel>()
// 数量
const count = ref(prop.initCount?? 0)
// 监听prop变化
watch(() => prop.initCount, (value) => {
count.value = value ?? 0
})
// 异常阈值
const ERROR_COUNT = 5
// 是否异常 大于5就异常
const isError = ref(false)
// 监听是否异常
watch(count, (value) => {
if (value > ERROR_COUNT) {
isError.value=true
emit('error',value)
}
})
// 添加值
function addCount(){
count.value++
}
</script>
<style scoped>
.error{
color: red;
}
</style>
第二种,通过Hooks方式将业务抽离
同目录下创建 【NumPanelHooks.ts】文件
import {ref, watch} from "vue";
interface EmitModel {
/**
* 上报异常
* @param e
* @param count 异常值
*/
(e: 'error', count: number): void
}
export default function (prop: { initCount?: number }, emit: EmitModel) {
// 数量
const count = ref(prop.initCount ?? 0)
// 监听prop变化
watch(() => prop.initCount, (value) => {
count.value = value ?? 0
})
// 异常阈值
const ERROR_COUNT = 5
// 是否异常 大于5就异常
const isError = ref(false)
// 监听是否异常
watch(count, (value) => {
if (value > ERROR_COUNT) {
isError.value = true
emit('error', value)
}
})
// 添加值
function addCount() {
count.value++
}
return {
count,
isError,
addCount
}
}
组件页面
<template>
<div :class="{error:isError}">{{ count }}</div>
<button @click="addCount">add</button>
</template>
<script setup lang="ts">
import {defineEmits, defineProps} from "vue";
import useNumPanelHoos from './NumPanelHooks'
// -----props-----
interface PropModel {
initCount?: number
}
const prop = defineProps<PropModel>()
// -----emits----
interface EmitModel {
/**
* 上报异常
* @param e
* @param count 异常值
*/
(e: 'error', count: number): void
}
const emit = defineEmits<EmitModel>()
const {
count,
isError,
addCount
} = useNumPanelHoos(prop, emit)
</script>
<style scoped>
.error {
color: red;
}
</style>
此种方式,已经实现业务的抽离,组件内部也很清洁。
第三种,面向对象Hooks
创建【NumPanelObjHooks.ts】文件
import {ref, watch} from "vue";
interface EmitModel {
/**
* 上报异常
* @param e
* @param count 异常值
*/
(e: 'error', count: number): void
}
export default class NumPanelObjHooks {
prop = undefined
emit = undefined
// 数量
count = ref(0)
constructor(prop: { initCount?: number }, emit: EmitModel) {
this.prop = prop
this.emit = emit
this.count.value = this.prop?.initCount ?? 0
}
addWatch = () => {
// 监听prop变化
watch(() => this.prop.initCount, (value) => {
this.count.value = value ?? 0
})
// 监听是否异常
watch(this.count, (value) => {
if (value > this.ERROR_COUNT) {
this.isError.value = true
this.emit('error', value)
}
})
}
// 异常阈值
ERROR_COUNT = 5
// 是否异常 大于5就异常
isError = ref(false)
// 添加值
addCount = () => {
this.count.value++
}
}
组件页面
<template>
<div :class="{error:isError}">{{ count }}</div>
<button @click="addCount">add</button>
</template>
<script setup lang="ts">
import {defineEmits, defineProps} from "vue";
import NumPanelObjHooks from "./NumPanelObjHooks";
// -----props-----
interface PropModel {
initCount?: number
}
const prop = defineProps<PropModel>()
// -----emits----
interface EmitModel {
/**
* 上报异常
* @param e
* @param count 异常值
*/
(e: 'error', count: number): void
}
const emit = defineEmits<EmitModel>()
const {
count,
isError,
addCount,
addWatch
} = new NumPanelObjHooks(prop, emit)
addWatch()
</script>
<style scoped>
.error {
color: red;
}
</style>
第二种就能实现业务的抽离,为什么采取要使用第三种方式?
我们公司的公共组件与结构是在一个分支上,各项目都是从这个分支拉出的各项目的分支。各项目由于业务不同可能会有改动组件,这样再维护公共组件,就会造成冲突。把组件单独提出,作为各项目的私有组件,那么修改公共组件问题,私有组件又无法更新。于是想通过继承的方式来创建私有组件,这样公共的组件修改问题时,由于继承关系私有组件也会同时更新。
举个例子:现在把增加的方法变为自增为2
创建【MyNumPanelHooks.ts】
import NumPanelObjHooks from "../NumPanel/NumPanelObjHooks";
export default class MyNumPanelHooks extends NumPanelObjHooks{
addCount=()=>{
this.count.value+=2
}
}
创建【MyNumPanel.vue】
<template>
<div :class="{error:isError}">{{ count }}</div>
<button @click="addCount">add</button>
</template>
<script setup lang="ts">
import {defineEmits, defineProps} from "vue";
import MyNumPanelHooks from "./MyNumPanelHooks";
// -----props-----
interface PropModel {
initCount?: number
}
const prop = defineProps<PropModel>()
// -----emits----
interface EmitModel {
/**
* 上报异常
* @param e
* @param count 异常值
*/
(e: 'error', count: number): void
}
const emit = defineEmits<EmitModel>()
const {
count,
isError,
addCount,
addWatch
} = new MyNumPanelHooks(prop, emit)
addWatch()
</script>
<style scoped>
.error {
color: red;
}
</style>