如何动态控制第三方组件包的某个元素样式

158 阅读2分钟

需求背景

对项目中引入的第三包的发送按钮进行动态配置,控制发送按钮的展示与隐藏。
已知:

  • 发送按钮默认展示
  • 能获取发送按钮的 class 类名(方便说明,假设该类名为.chat-design-input-operation)。

思考过程

方案一

  1. 获取该元素
  2. 给该元素添加或删除样式
function handleSendBtn (btnShow: boolean) {
  const btn = document.querySelector('.chat-design-input-operation')
  if (btnShow) {
    btn.classList.remove('.chat-design-input-operation-hiddern')
  } else {
    btn.classList.add('.chat-design-input-operation-hiddern')
  }
}

缺点:只适用第三方包元素常驻情况,若该元素需要特定条件才渲染,且我们无法获取第三包特定渲染条件,该方法不适用

方案二

  1. 按需载入css文件
function handleSendBtn (btnShow: boolean) {
  if (btnShow) {
    // do-nothing
  } else {
    import('./hidden.css')
  }
}

.chat-design-input-operation {
    display: none
}

缺点:css文件一旦引入,无法移除,不能实现切换按钮的展示与隐藏。只适用于元素样式改变一次的情况。

方案三(最终方案)

虽然方案二最终未使用,但给了我思考问题的方向。动态导入 css 文件,其实就是在页面中插入了 style 标签,那我何尝不自己特定的 style 片段进行样式的控制呢,说干就干:

  1. 新建一个 style 标签,设置唯一标识(方便后面移除)
  2. style 标签设置按钮隐藏样式
  3. 根据条件插入/移除 style 标签
function handleSendBtn (btnShow: boolean) {
  const styleId = 'IM-sendBtn-config';
  if (btnShow) {
    const styleElement = document.querySelector(`[data-style-id="${styleId}"]`)
    styleElement && document.head.removeChild(styleElement)
  } else if (sendType === 'button') {
    const styleElement = document.createElement('style')
    styleElement.setAttribute('data-style-id', styleId)
    styleElement.innerHTML = `
      .chat-design-input-operation {
        display: none;
      }
    `
    document.head.appendChild(styleElement)
  }
}

最终效果

发送按钮展示

image.png image.png

发送按钮隐藏

image.png

image.png

思考

本需求虽然在实现方案上比较简单,但一不小心很容易掉坑里,比如使用 MutationObserver 监听 DOM 变化继续沿用方案一,但使用 MutationObserver 监听 DOM 这一方式并不准确,不一定能获取到你想要的目标元素。所以,做需求很重要的一点就是:发现思路不对,及时掉头,避免自己踩坑,给别人挖坑。