Vue mergeProps用法详细讲解

很多人不知道megreProps的用法,今天我们就来讲解下mergeProps的用法以及原理

用法

大家觉得下面哪种用法是正确的呢?

这样

style: mergeProps({
    width: this.itemWidth
}, xProps.style)

或者这样

style: mergeProps({
    style: {
        width: this.itemWidth
    },
    ...(xProps?.style ?? {})
})

还是这样

style: mergeProps(
    {
      style: { width: this.itemWidth },
    },
    xProps,
).style

你使用的话会使用上面哪一种呢?

不知道

因为写的是jsx语法,所以查看了vue3的jsx语法,发现里面并没有关于这个解释,只说到了默认开启

于是去vue3官网查找,找到

megreProps:Merge multiple props objects with special handling for certain props.

意思就说合并多个道具对象,对某些道具进行特殊处理

所以前面两种写法是错误的

接着看了下mergeProps源码的写法

// ...args将多个对象收集成数组
export function mergeProps(...args: (Data & VNodeProps)[]) {
  // 最终合并的结果
  const ret: Data = {}
  // 遍历用户传入的多个对象
  for (let i = 0; i < args.length; i++) {
    // 取到传入的对象值
    const toMerge = args[i]
    for (const key in toMerge) {
       // 对class进行序列化合并处理
      if (key === 'class') {
        if (ret.class !== toMerge.class) {
          ret.class = normalizeClass([ret.class, toMerge.class])
        }
      // 对style进行序列化合并处理
      } else if (key === 'style') {
        ret.style = normalizeStyle([ret.style, toMerge.style])
      // 对其他的绑定的属性进行合并
      } else if (isOn(key)) {
        const existing = ret[key]
        const incoming = toMerge[key]
        if (
          incoming &&
          existing !== incoming &&
          !(isArray(existing) && existing.includes(incoming))
        ) {
          ret[key] = existing
            ? [].concat(existing as any, incoming as any)
            : incoming
        }
      // 如果是普通元素上的用户自定义属性,则直接赋值
      } else if (key !== '') {
        ret[key] = toMerge[key]
      }
    }
  }
  return ret
}

所以你传入的对象里面是需要有style、class等key的

接下来看看normalizeClass这个方法,这个方法就是将用户写的多种格式(比如数组,对象,字符串)的class进行序列化成字符串给到最终渲染的元素

export function normalizeClass(value: unknown): string {
  let res = ''
  // 如果是字符串,直接返回
  if (isString(value)) {
    res = value
  // 如果是数组
  } else if (isArray(value)) {
    for (let i = 0; i < value.length; i++) {
      // 递归调用进行处理
      const normalized = normalizeClass(value[i])
      if (normalized) {
        res += normalized + ' '
      }
    }
  // 如果是对象, 如{ active: isActive, 'text-danger': hasError },需要把key拼接
  } else if (isObject(value)) {
    for (const name in value) {
      if (value[name]) {
        res += name + ' '
      }
    }
  }
  return res.trim()
}

再看看normalizeStyle这个函数

export type NormalizedStyle = Record<string, string | number>
export function normalizeStyle(
  value: unknown
): NormalizedStyle | string | undefined {
  // 如果是数组的情况
  if (isArray(value)) {
    const res: NormalizedStyle = {}
    for (let i = 0; i < value.length; i++) {
      const item = value[i]
      const normalized = isString(item)
        ? parseStringStyle(item)
        : (normalizeStyle(item) as NormalizedStyle)
      if (normalized) {
        // 将序列化后的style保存到ret上
        for (const key in normalized) {
          res[key] = normalized[key]
        }
      }
    }
    return res
  } else if (isString(value)) {
    return value
  } else if (isObject(value)) {
    return value
  }
}

parseStringStyle函数就是将字符串对;进行分割,然后设置对应的key,value

元素上的style只能使用string,所以在最终挂在到dom元素上需要进行stringifyStyle

export function stringifyStyle(
  styles: NormalizedStyle | string | undefined
): string {
  let ret = ''
  if (!styles || isString(styles)) {
    return ret
  }
  for (const key in styles) {
    const value = styles[key]
    const normalizedKey = key.startsWith(`--`) ? key : hyphenate(key)
    if (
      isString(value) ||
      (typeof value === 'number' && isNoUnitNumericStyleProp(normalizedKey))
    ) {
      // only render valid values
      ret += `${normalizedKey}:${value};`
    }
  }
  return ret
}

所以通过简单的对vue3的mergeProps的代码进行简单分析就能知道其原理了,使用上也会更加的熟练

到此这篇关于Vue mergeProps用法详细讲解的文章就介绍到这了,更多相关Vue mergeProps内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Vue3源码分析组件挂载初始化props与slots

    目录 前情提要 初始化组件 (1).setupComponent (2).initProps (3).initSlots 额外内容 总结 前情提要 上文我们分析了挂载组件主要调用了三个函数: createComponentInstance(创建组件实例).setupComponent(初始化组件).setupRenderEffect(更新副作用).并且上一节中我们已经详细讲解了组件实例上的所有属性,还包括emit.provide等的实现.本文我们将继续介绍组件挂载流程中的初始化组件. 本文主要内

  • Vue 子组件更新props中的属性值问题

    目录 Vue子组件更新props的属性值 .sync属性 v-model应用 Vue子组件中修改Props的几种情况 针对以上几种情况再逐一进行分析 结果展示 结论 Vue子组件更新props的属性值 在子组件中更新props中的属性值,并且更新到父组件,有两种实现方式:.sync 和 自定义v-model .sync属性 父组件在给子组件传值时,属性名后需要加修饰符.sync,格式 :子组件props属性名.sync 父组件 <template> <div id="app&q

  • vue组件中props与data的结合使用方式

    目录 组件中props与data的结合使用 子组件中data从props中动态更新数据 组件中props与data的结合使用 如前所述(vue组件属性(props)及私有数据data),vue组件中,props是组件公有属性,对外:data是组件的私有数据,对内.正因为props对外,由外部赋值,因此在组件内部,是只读的,即组件内部不适宜去改变这些元素的值.当然,改也可以改,但运行时刻会有告警. 正如我们写一个函数,对于传入的参数,我们一般是只读对待的,极少会去修改它的值一样.当然,这只是一种编

  • Vue路由vue-router详细讲解指南

    中文文档:https://router.vuejs.org/zh/ Vue Router 是Vue.js官方的路由管理器.它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌.路由实际上就是可以理解为指向,就是我在页面上点击一个按钮需要跳转到对应的页面,这就是路由跳转: 首先我们来学习三个单词(route,routes,router): route:首先它是个单数,译为路由,即我们可以理解为单个路由或者某一个路由: routes:它是个复数,表示多个的集合才能为复数:即我们可以理解为

  • vue v-model的详细讲解(推荐!)

    目录 v-model的基本使用 v-model的原理 v-model绑定textarea v-model绑定checkbox v-model绑定radio v-model绑定select v-model的值绑定 v-model修饰符 - number v-model修饰符 - trim 附:父子组件v-model绑定的参数进行通信 总结 v-model的基本使用 表单提交是开发中非常常见的功能,也是和用户交互的重要手段: 比如用户在登录.注册时需要提交账号密码: 比如用户在检索.创建.更新信息时

  • 可能是全网vue v-model最详细讲解教程

    目录 v-model是什么 为什么使用v-model? 什么场景下会使用v-model? v-model的原理 那v-model是双向绑定吗? 那 v-model 是单向数据流吗? 什么是单项数据流? v-model 的做法是怎样的? v-model的绑定 我们来看一下绑定textarea v-model绑定checkbox v-model绑定radio v-model绑定select v-model的值绑定 v-model修饰符 - lazy lazy修饰符是什么作用呢? v-model修饰符

  • C++ boost thread库用法详细讲解

    目录 一.说明 二.boost::thread的几个函数 三.构造 一.说明 boost::thread的六种使用方法总结,本文初步介绍线程的函数.构造.执行的详细解释. 二.boost::thread的几个函数 函数 功能 join() 让主进程等待子线程执行完毕后再继续执行 get_id() 获得线程的 id 号 detach() 标线程就成为了守护线程,驻留后台运行 bool joinable() 是否已经启动,为 join() thread::join()是个简单暴力的方法,主线程等待子

  • 关于vue中计算属性computed的详细讲解

    目录 1.定义 2.用法 3.computed的响应式依赖(缓存) 4.应用场景 附:计算属性的 getter 与 setter 总结 1.定义 computed是vue的计算属性,是根据依赖关系进行缓存的计算,只有在它的相关依赖发生改变时才会进行更新 2.用法 一般情况下,computed默认使用的是getter属性 3.computed的响应式依赖(缓存) 1. computed的每一个计算属性都会被缓存起来,只要计算属性所依赖的属性发生变化,计算属性就会重新执行,视图也会更新.下面代码中,

  • vue进行图片的预加载watch用法实例讲解

    watch应用场景 我想信图片预加载大家肯定都有接触过,当图片量大的时候,为了保证页面图片都加载出来的时候,我们才把主页面给显示出来,再进行一些ajax请求,或者逻辑操作 那此时你用computed对这种监听一个数据然后进行一系列逻辑操作和ajax请求,那watch再适合不过了,如果用computed的话那你连实现都实现不了,只有用watch监听 <template> <div v-show=show> <img src="https://img.alicdn.co

  • C语言详细讲解二分查找用法

    目录 [力扣题号]704.二分查找 力扣题目链接 示例 1: 输入: nums = [-1,0,3,5,9,12], target = 9     输出: 4       解释: 9 出现在 nums 中并且下标为 4 示例 2: 输入: nums = [-1,0,3,5,9,12], target = 2     输出: -1        解释: 2 不存在 nums 中因此返回 -1 提示: 你可以假设 nums中的所有元素是不重复的. n将在[1, 10000]之间. nums的每个元素

  • C++详细讲解常用math函数的用法

    目录 1.fabs(double x) 2.floor(double x)ceil(double x) 3.pow(double x,double n) 4.sqrt(double x) 5.log(double x) 6.sin(double x)cos(double x) tan(double x) 7.round(double x) 包含头文件 #include<cmath> 1.fabs(double x) 对double型变量取绝对值 #include<iostream>

  • Java超详细讲解接口的实现与用法

    目录 1.接口的定义 2.接口的实现 3.接口的引用 4.接口的继承 5.利用接口实现多重继承 1.接口的定义 接口是一种特殊的抽象类,是Java提供的一个重要的功能,与抽象类不同的是: 接口的所有数据成员都是静态的且必须初始化. 接口中的所有方法必须都是抽象方法,不能有一般的方法. [public] interface 接口名称 [extends  父接口名列表]{    [public] [static] [final]数据类型 成员变量名 = 常量;    ...    [public][

  • C语言详细讲解指针数组的用法

    目录 1. 指针数组定义方法 2. 指针的指针(二级指针) 3. 字符串和指针 4. 数组指针 定义方法 数组指针的用法 1. 指针数组定义方法 格式: 类型说明符 *数组名[ 元素个数 ] int *p[10]; // 定义了一个整型指针数组p,有10个元素,都是int *类型的变量 指针数组的分类: 同指针类型的分类,见上一篇 大多数情况下,指针数组都用来保存多个字符串. #include <stdio.h> int main() { char *name[5] = {"Hell

随机推荐