VUE3 Hooks的面向对象实现方式

本文会以三种形式实现一个组件,该组件实现以下功能:

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>

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值