likes
comments
collection
share

被领导表扬过的蓝湖主题色插件,你确定不来看看吗?

作者站长头像
站长
· 阅读数 27

背景

公司最近招募了一批实习生,经过一个月的集中培训后,他们开始接手项目。第一个项目是对应用程序页面样式进行重构,因为之前的样式不统一且不够美观,希望实习生在修改样式的同时熟悉业务流程

在代码审查时,我发现大部分同事直接使用了色值,而没有采用统一的主题色名称。我询问了原因,得到的回答是“写着写着漏掉了”。回想起来,我自己也曾遇到过类似的情况。这让我思考,是否可以在蓝湖上提供一些提示

我与UI讨论过这个问题,但他们没有提出有效的解决方案。我曾经使用过一个翻译浏览器插件,当我选中不认识的英文单词时,它会自动提供中文提示。这让我想到,是否可以借鉴这个思路,开发一个类似的浏览器插件来解决我们的问题?

分析

我们平时使用蓝湖的习惯是,比如在进行按钮样式修改之前,先用鼠标点击UI图上的按钮。这时,侧边会弹出一个样式信息框(这是蓝湖自带的功能),里面显示了该按钮的相关样式,包括宽高、字体、边距和颜色等信息

被领导表扬过的蓝湖主题色插件,你确定不来看看吗?

设置主题色色值和名称

计划用插件中的popup弹框做,另外配合chrome.storageAPI 存储和读取数据

监听DOM变化

经过观察得到每一次点击UI上的样式都会触发 DOM 更新,可以使用 JavaScript 中的 MutationObserver 来监听 DOM 的变化

找到当前样式的颜色值

通过样式信息里面的颜色,拿到颜色值

提示主题色信息

获取到颜色值后,判断其是否符合主题色。如果符合,则提示相应的主题色信息

代码实现

popup弹框

需要提前设置好主题色色值和主题色名称,点击插件图标会弹出设置面板

被领导表扬过的蓝湖主题色插件,你确定不来看看吗?

// popup.html
<body>
    <h3>请设置主题色</h3>
    <div id="container"></div>
    <div class="btn-box">
        <button id="addBtn">添加</button>
        <button id="submitBtn">保存</button>
        <button id="clearBtn">清空</button>
    </div>
    <script type="text/javascript" src="./scripts/popup.js"></script>
</body>

// popup.js
let containerEl = document.getElementById('container');
let addBtn = document.getElementById('addBtn');
let clearBtn = document.getElementById('clearBtn');
let submitBtn = document.getElementById('submitBtn');

// 添加
addBtn.addEventListener('click', addElement)

// 清除
clearBtn.addEventListener('click', () => {
    chrome.storage.sync.remove('colorData');
    let inputDivArr = [...document.getElementsByClassName('input-box')];
    inputDivArr.forEach(inputDivEl => {
        let inputArr = inputDivEl.querySelectorAll('input')
        inputArr[0].value = ''
        inputArr[1].value = ''
    })
})

function addElement() {
    let newDiv = document.createElement('div')
    let newColorInput = document.createElement('input')
    let newNameInput = document.createElement('input')
    newDiv.setAttribute('class', 'input-box')
    newColorInput.setAttribute('placeholder', '请输入色值')
    newNameInput.setAttribute('placeholder', '请输入主题色名称')
    newDiv.appendChild(newColorInput)
    newDiv.appendChild(newNameInput)
    containerEl.appendChild(newDiv)
}

// 保存
submitBtn.addEventListener('click', () => {
    let inputDivArr = [...document.getElementsByClassName('input-box')];
    let data = inputDivArr.map(inputDivEl => {
        let inputArr = inputDivEl.querySelectorAll('input')
        return {
            name: inputArr[1].value,
            color: inputArr[0].value,
        }
    }).filter(item => item.color !== '' || item.name !== '');
    chrome.storage.sync.set({colorData: data}, function() {
        window.close();
    });
})

// 回显
document.addEventListener('DOMContentLoaded', () => {
    chrome.storage.sync.get(['colorData'], (result) => {
        if(result.colorData && Array.isArray(result.colorData)) {
            result.colorData.forEach(item => {
                let newDiv = document.createElement('div')
                let newColorInput = document.createElement('input')
                let newNameInput = document.createElement('input')
                newDiv.setAttribute('class', 'input-box')
                newColorInput.setAttribute('placeholder', '请输入色值')
                newColorInput.setAttribute('value', item.color)
                newNameInput.setAttribute('placeholder', '请输入主题色名称')
                newNameInput.setAttribute('value', item.name)
                newDiv.appendChild(newColorInput)
                newDiv.appendChild(newNameInput)
                containerEl.appendChild(newDiv)
            });
            for(let i = 0; i < 5 - result.colorData.length; i++) {
                addElement()
            }
        } else {
            for(let i = 0; i < 5; i++) {
                addElement()
            }
        }
    });
})

插件主体

插件主体业务代码依赖于MutationObserverAPI 监测网页 DOM 的变化,并根据变化动态更新某些元素的内容和样式

const observer = new MutationObserver(function (mutationsList, observer) {
  // 在每次变化发生时要执行的操作
  var elements = document.getElementsByClassName(' mu-drawer open');
  if (elements.length > 0) {
    elements = document.getElementsByClassName('layer_color');
    if (elements.length > 0) {
      for (let key = 0; key < elements.length; key++) {
        let container = elements[key];
        let themeElements = container.getElementsByClassName('el-theme');
        let themeElement = themeElements.length > 0 ? themeElements[0] : null;
        if (!themeElement) {
          themeElement = document.createElement('div');
          themeElement.className = 'el-theme';
          themeElement.style.color = '#7A7AF9';
          themeElement.style.fontWeight = 'bold';
          let index = 0;
          if (container.getElementsByClassName('subtitle color_title').length > 0) {
            index = 1;
          }
          container.insertBefore(themeElement, container.children[index]);
        }
        let colorElements = container.getElementsByClassName("color_li");
        if (colorElements.length > 0) {
          let colors = [];
          for (let i = 0; i < colorElements.length; i++) {
            let ele = colorElements[i];
            colors.push(getColor(ele));
          }
          // 单颜色处理,目前没有处理混合颜色
          if (colors.length == 1) {
            let color = colors[0];
            chrome.storage.sync.get(['colorData'], (result) => {
                let dataItem = result.colorData.find(item => item.color.toUpperCase() == color.toUpperCase())
                if(typeof dataItem == 'object') {
                  themeElement.style.display = 'block';
                  themeElement.textContent = dataItem.name;
                } else {
                  themeElement.style.display = 'none';
                  themeElement.textContent = ''
                }
            });
          }
          else {
            themeElement.style.display = 'none';
            themeElement.textContent = ''
          }
        }
      }
    }
  }
});

const rgb = (r, g, b) => {
  return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`.toLocaleLowerCase();
}

const getColor = (element) => {
  let colors = element.getElementsByClassName('color');
  if (colors.length == 1) {
    let color = colors[0];
    let background = color.style.background;
    if (background) {
      background = background.replace(/\s/g, '');
      if (background.startsWith('rgb')) {
        let colorint = background.replace('rgb(', '').replace(')', '').split(',');
        return rgb(Number(colorint[0]), Number(colorint[1]), Number(colorint[2]));
      }
    }
  }
}

// 开始监测指定节点的变化
observer.observe(document.body, {
  childList: true, // 监测子节点的变化
  attributes: true, // 监测属性的变化
  subtree: true, // 包括所有后代节点
  attributeFilter: ['class', 'style'] // 过滤属性,只监测指定的属性变化
});

其思路是获取样式信息的弹出框 DOM 元素,然后从中提取颜色信息的 DOM 元素。接着,动态创建一个新的 DOM 元素用于展示主题色名称。如果存在已设置的主题色,则显示相应的主题色名称。目前不支持混合颜色

被领导表扬过的蓝湖主题色插件,你确定不来看看吗?

总结

大家感觉是不是挺有意思?整个实现过程并不复杂,有兴趣的同学可以一起交流交流

如果遇到类似的问题,欢迎使用这个插件,如果你喜欢它,欢迎star🚗🚗🚗

蓝湖主题色识别器(插件) (github.com)

转载自:https://juejin.cn/post/7394835461040504851
评论
请登录