Vue3重构案例(使用vue3的语法重构element的button组件)

news2024/11/26 10:01:42

这篇文章紧接的上一篇文章,上篇文章是对给element的button组件写了一个单元测试,这篇文章是使用vue3的语法进行重构,这里说一下单元测试和重构的联系,当你给组件写了单元测试之后,重构会减少你很多的debug时间,磨刀不误砍柴工,这里推荐大家先从上一篇文章看起:https://www.jianshu.com/p/01d2860607c1

vue3.0发布,大家是不是很兴奋呢!又可以拿头发换钱了,唉!命苦。

人如其名,本文的主题就是使用vue3的语法重构element的button组件

上才艺!

先来看一下element的button.vue本身是什么样子

<template>
  <button
    class="el-button"
    @click="handleClick"
    :disabled="buttonDisabled || loading"
    :autofocus="autofocus"
    :type="nativeType"
    :class="[
      type ? 'el-button--' + type : '',
      buttonSize ? 'el-button--' + buttonSize : '',
      {
        'is-disabled': buttonDisabled,
        'is-loading': loading,
        'is-plain': plain,
        'is-round': round,
        'is-circle': circle,
      },
    ]"
  >
    <i class="el-icon-loading" v-if="loading"></i>
    <i :class="icon" v-if="icon && !loading"></i>
    <span v-if="$slots.default"><slot></slot></span>
  </button>
</template>
<script>
export default {
  name: 'ElButton',

  inject: {
    elForm: {
      default: '',
    },
    elFormItem: {
      default: '',
    },
  },

  props: {
    type: {
      type: String,
      default: 'default',
    },
    size: String,
    icon: {
      type: String,
      default: '',
    },
    nativeType: {
      type: String,
      default: 'button',
    },
    loading: Boolean,
    disabled: Boolean,
    plain: Boolean,
    autofocus: Boolean,
    round: Boolean,
    circle: Boolean,
  },

  computed: {
    _elFormItemSize() {
      return (this.elFormItem || {}).elFormItemSize;
    },
    buttonSize() {
      return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
    },
    buttonDisabled() {
      return this.disabled || (this.elForm || {}).disabled;
    },
  },

  methods: {
    handleClick(evt) {
      this.$emit('clicked', evt);
    },
  },
};
</script>

重构思路:我们先一步步把每个方法、每个属性分解开,先挑软柿子捏,一步步的把他按照vue3的Composition API手法进行重构。

重构handleClick方法

重构前

<script>
export default{
   methods: {
    handleClick(evt) {
      this.$emit('clicked', evt);
    },
  },
}
</script>

重构后

<script>
export default{
  setup(props, {emit}) {
    const handleClick = (evt) => {
      emit('clicked', evt);
    };
    return {
      handleClick,
    };
  },
}
</script>
重构buttonDisabled属性

重构前

<script>
export default{
   computed: {
    buttonDisabled() {
      return this.disabled || (this.elForm || {}).disabled;
    },
  },
}
</script>

重构后

<script>
const usebuttonDisabled = (disabled) => {
  const elForm = inject('elForm', {});
  const buttonDisabled = computed(() => {
    return disabled.value || elForm.disabled;
  });
  return buttonDisabled;
};
export default{
  setup(props, {emit}) {
    const {disabled} = toRefs(props);
    const buttonDisabled = usebuttonDisabled(disabled);
    return {
      buttonDisabled,
    };
  },
}
</script>

这边说一下重构buttonDisabled这个属性的时候,遇到的一些坑。

1.解构props里面的值的时候,会使这个属性失去响应式,从而导致页面报错。
如果我在解构props的disabled属性的时候这样写

 const {disabled} = props;

那么就会报如下错误:


image.png

大概翻译下就是 :
从' setup() '根作用域中的' props '获取值将导致该值失去反应性。

所以需要我们用一个toRefs()这样一个api来解决这个问题

 const {disabled} = toRefs(props);

toRefs()这个方法可以使一个对象变成响应式对象

重构buttonSize属性

重构前

<script>
export default{
   computed: {
    buttonSize() {
      return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
    },
  },
}
</script>

重构后

<script>
const useButtonSize = (size) => {
  const elFormItem = inject('elFormItem', {});
  const _elFormItemSize = computed(() => {
    return elFormItem.elFormItemSize;
  });
  const buttonSize = computed(() => {
    return (
      size.value ||
      _elFormItemSize.value ||
      (getCurrentInstance().ctx || {})._elFormItemSize
    );
  });
  return buttonSize;
};

setup(props, {emit}) {
   const {size} = toRefs(props);
   const buttonSize = useButtonSize(size)
   return {
     buttonSize
   };
},
</script>

注意:
computed返回的是一个ref对象,所以在使用的时候要用.value

遇到的坑:
当props中,如果某个属性没被给默认值也就是没有分配内存空间,就转换不成ref对象

如果我的props的值是这样,因为解构会使props值失去响应式,所以我想用toRefs(),转化成响应式对象,

<script>
  props:{
    size:String
}

setup(props){
  const {size} = toRefs(props);
  console.log('-----------------',size)
}
</script>

当我们输出size一看,发现是undefined,what?

image.png

当我们给size设置一个默认值""

<script>
  props:{
    size:{
      type:String,
      default:''
  }
}

setup(props){
  const {size} = toRefs(props);
  console.log('-----------------',size)
}
</script>

输出size的时候,就是一个ref对象


image.png

如此,全部重构完毕;
贴一份重构完成的代码:

<template>
  <button
    class="el-button"
    @click="handleClick"
    :disabled="buttonDisabled || loading"
    :autofocus="autofocus"
    :type="nativeType"
    :class="[
      type ? 'el-button--' + type : '',
      buttonSize ? 'el-button--' + buttonSize : '',
      {
        'is-disabled': buttonDisabled,
        'is-loading': loading,
        'is-plain': plain,
        'is-round': round,
        'is-circle': circle,
      },
    ]"
  >
    <i class="el-icon-loading" v-if="loading"></i>
    <i :class="icon" v-if="icon && !loading"></i>
    <span v-if="$slots.default"><slot></slot></span>
  </button>
</template>
<script>
import {computed, getCurrentInstance, inject, toRefs, unref} from 'vue';
const usebuttonSize = (size) => {
  const elFormItem = inject('elFormItem', {});

  const _elFormItemSize = computed(() => {
    return unref(elFormItem.elFormItemSize);
  });
  const buttonSize = computed(() => {
    return (
      size.value ||
      _elFormItemSize.value ||
      getCurrentInstance().ctx._elFormItemSize
    );
  });
  return buttonSize;
};
const userButtonDisabled = (disabled) => {
  const elForm = inject('elForm', {});

  const buttonDisabled = computed(() => {
    return disabled.value || elForm.disabled;
  });
  return buttonDisabled;
};
export default {
  name: 'ElButton',

  inject: {
    elForm: {
      default: '',
    },
    elFormItem: {
      default: '',
    },
  },

  props: {
    type: {
      type: String,
      default: 'default',
    },
    size: {
      type: String,
      default: '',
    },
    icon: {
      type: String,
      default: '',
    },
    nativeType: {
      type: String,
      default: 'button',
    },
    loading: Boolean,
    disabled: Boolean,
    plain: Boolean,
    autofocus: Boolean,
    round: Boolean,
    circle: Boolean,
  },

  computed: {
    _elFormItemSize() {
      return (this.elFormItem || {}).elFormItemSize;
    },
    // buttonSize() {
    //   return this.size || this._elFormItemSize || (this.$ELEMENT || {}).size;
    // },
    // buttonDisabled() {
    //   return this.disabled || (this.elForm || {}).disabled;
    // },
  },

  methods: {
    // handleClick(evt) {
    //   this.$emit('clicked', evt);
    // },
  },
  setup(props, {emit}) {
    const handleClick = (evt) => {
      emit('clicked', evt);
    };
    const {disabled, size} = toRefs(props);
    // 重构butonDisabled属性
    const buttonDisabled = userButtonDisabled(disabled);

    // 重构buttonSize属性

    const buttonSize = usebuttonSize(size);
    return {
      handleClick,
      buttonDisabled,
      buttonSize,
    };
  },
};
</script>




喜欢的朋友记得点赞、收藏、关注哦!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1897789.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jdk22+maven环境配置教程+idea的maven环境配置(Windows系统)

前言 jdk是Java开发必要的编程环境&#xff0c;idea是常用的Java开发工具&#xff0c;这里着重解释一下maven。 maven就是我们经常看见的pom.xml文件&#xff0c;maven有以下三点功能&#xff1a; 1.项目构建&#xff08;可以帮助我们更快速的打包、构建项目&#xff09; 2.依…

数据操作10-15题(30 天 Pandas 挑战)

数据操作 1. 相关知识点1.12 分组与连表1.13 排名 2. 题目2.10 第N高的薪水2.11 第二高的薪水2.12 部门工资最高的员工2.13 分数排名2.14 删除重复的电子邮箱2.15 每个产品在不同商店的价格 1. 相关知识点 1.12 分组与连表 分组max_salaryemployee.groupby(departmentId)[sal…

【leetcode】双指针算法题

文章目录 1.算法思想2.移动零3.复写零方法一方法二 4.快乐数5.盛水最多的容器方法一&#xff08;暴力求解&#xff09;方法二&#xff08;左右指针&#xff09; 6.有效三角形的个数方法一&#xff08;暴力求解&#xff09;方法二&#xff08;左右指针&#xff09; 7.两数之和8.…

k8s学习--基于k8s的ELK日志收集的详细过程

文章目录 FilebeatFilebeat主要特点Filebeat使用场景 ELK简介Elasticsearch简介Elasticsearch主要特点Elasticsearch使用场景 Logstash简介Logstash主要特点Logstash使用场景 Kibana简介Kibana主要特点Kibana使用场景 简单理解 环境一、ELK集群部署1.软件安装2.软件配置及启动(…

【python】PyQt5控件尺寸大小位置,内容边距等API调用方法实战解析

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Java毕业设计 基于SSM vue新生报到系统小程序 微信小程序

Java毕业设计 基于SSM vue新生报到系统小程序 微信小程序 SSM 新生报到系统小程序 功能介绍 学生 登录 注册 忘记密码 首页 学校公告 录取信息 录取详情 师资力量 教师详情 收藏 评论 用户信息修改 宿舍安排 签到信息 在线缴费 教室分配 我的收藏管理 我要发贴 我的发贴 管理…

STM32外扩SRAM及用法

一.概述 一般单片机有片内的RAM&#xff0c;但都不多&#xff0c;比如&#xff1a;STM32F407ZGT6 自带了 192K 字节的 RAM&#xff0c;对一般应用来说&#xff0c;已经足够了&#xff0c;不过在一些对内存要求高的场合&#xff0c;比如做华丽效果的 GUI&#xff0c;处理大量数据…

ionic7 使用Capacitor打包 apk 之后,设置网络权限

报错处理 在打包的时候遇到过几个问题&#xff0c;这里记录下来两个 Visual Studio Code运行ionic build出错显示ionic : 无法加载文件 ionic 项目通过 android studio 打开报错 capacitor.settings.gradle 文件不存在 ionic7 项目初始化以及打包 apk 这篇文章讲到了如果安装…

Java+前后端分离架构+ MySQL8.0.36产科信息管理系统 产科电子病历系统源码

Java前后端分离架构 MySQL8.0.36产科信息管理系统 产科电子病历系统源码 产科信息管理系统—住院管理 数字化产科住院管理是现代医院管理中的重要组成部分&#xff0c;它利用数字化技术优化住院流程&#xff0c;提升医疗服务质量和效率。以下是对数字化产科住院管理的详细阐述…

您的私人办公室!-----ONLYOFFICE8.1版本的桌面编辑器测评

随时随地创建并编辑文档&#xff0c;还可就其进行协作 ONLYOFFICE 文档是一款强大的在线编辑器&#xff0c;为您使用的平台提供文本文档、电子表格、演示文稿、表单和 PDF 编辑工具。 网页地址链接&#xff1a; https://www.onlyoffice.com/zh/office-suite.aspxhttps://www…

2个方法教你轻松移除pdf文件编辑限制

PDF是一种常见的办公文档格式&#xff0c;常用于文件共享和保护。然而&#xff0c;有时候我们需要编辑PDF文件中的内容&#xff0c;但受到了编辑限制。本文将介绍一些有效的方法&#xff0c;帮助您解除PDF的编辑限制&#xff0c;轻松进行编辑和修改。 一、通过密码取消PDF“限制…

运维锅总详解计算机缓存溢出

本文尝试从缓存溢出、如何平衡防止缓存溢出和OOM、conntrack缓存满载影响及优化措施、TCP/IP协议栈缓存满载影响及优化措施等方面对计算机缓存溢出进行详细分析&#xff0c;最后给出一些缓存满载的Prometheus告警规则。希望对您有所帮助&#xff01; 一、计算机缓存溢出简介 …

卫星轨道平面简单认识

目录 一、轨道平面 1.1 轨道根数 1.2 应用考虑 二、分类 2.1 根据运行高度 2.2 根据运行轨迹偏心率 2.3 根据倾角大小 三、卫星星座中的轨道平面 四、设计轨道平面的考虑因素 一、轨道平面 1.1 轨道根数 轨道平面是定义卫星或其他天体绕行另一天体运动的平面。这个平…

通过端口和进程pid查找启动文件/脚本

今天审计一个程序又让GPT给我上了一课&#xff0c;记一下笔记&#xff1a; 1、首先该程序开启了8080端口&#xff0c;使用如下命令得到pid为1817 netstat -tunlp|grep 80802、使用pid得到父进程 pstree -ps 1817输出结果如下&#xff1a; 3、看出程序是由systemd启动的&…

nginx安装演示(离线安装,直接安装在Linux中)

文章目录 1、创建文件夹 tool / nginx2、把安装文件放到 /opt/tool/nginx 目录下面3、yum install gcc4、yum install gcc-c5、tar -zxvf pcre-8.37.tar.gz6、./configure7、make8、make install9、tar -zxvf openssl-1.0.1t.tar.gz10、./config11、/config 1、创建文件夹 tool…

python绘制领域矩形

问题描述&#xff1a; 使用python书写代码实现以下功能&#xff1a;给定四个点的坐标&#xff0c;调用一个函数&#xff0c;可以使原来的四个点分别向四周上下左右移动15距离&#xff0c;分别记录下移动后的坐标&#xff0c;然后画出内侧矩形和外侧矩形 代码&#xff1a; im…

电脑为什么会提示丢失msvcp140.dll?怎么修复msvcp140.dll文件会靠谱点

电脑为什么会提示丢失msvcp140.dll&#xff1f;其实只要你的msvcp140.dll文件一损坏&#xff0c;然而你的电脑程序需要运用到这个msvcp140.dll文件的时候&#xff0c;就回提示你丢失了msvcp140.dll文件&#xff01;因为没有这个文件&#xff0c;你的很多程序都用不了的。今天我…

Purple Pi OH 更改SDK的编译选项

本文适用于在Purple Pi OH开发板更改SDK编译选项。触觉智能的Purple Pi OH鸿蒙开源主板&#xff0c;是华为Laval官方社区主荐的一款鸿蒙开发主板。 该主板主要针对学生党&#xff0c;极客&#xff0c;工程师&#xff0c;极大降低了开源鸿蒙开发者的入门门槛&#xff0c;具有以下…

数据为基 全面布局|美创再入《2024年中国网络安全市场全景图》

近日&#xff0c;网络安全行业研究机构数说安全正式发布《2024年中国网络安全市场全景图》&#xff08;以下简称全景图&#xff09;。 美创科技凭借以数据为中心的全面安全产品布局和领先能力&#xff0c;入榜数据库安全(数据库审计/数据库漏扫/数据库防火墙/数据库加密)、数据…

震撼发布!4M-21:苹果多模态AI巨擘,一键解锁21种模态

前沿科技速递&#x1f680; 来自洛桑联邦理工学院&#xff08;EPFL&#xff09;与苹果科研巨擘的强强联手&#xff0c;震撼发布全新跨时代成果——4M-21模型&#xff01;这一革命性单一模型&#xff0c;突破性地覆盖了数十种高度多样化的模态&#xff0c;通过大规模多模态数据集…