尊贵的掘金会员先生,我觉得您需要一个符合身份的头像框 !

1,693 阅读3分钟

您好,尊贵的会员先生,有什么能帮到您的吗?
哦,似乎有什么不对,让我看看,您没有自己的头像框
您可是最尊贵的会员,居然没有自己的头像框,这太不可思议了。
掘金怎么能让您受到这种屈辱,我发誓,我会用42码的大靴子狠狠地踢他屁股,并且让他吃下隔壁玛丽苏太太做的苹果派,这是他应得的惩罚。

--- 沃兹基 ● 硕德

言归正传,以上纯属玩笑,但是作为尊贵的掘金会员,没有自己的头像框来彰显自己的尊贵,确实让我很郁闷。

好在身为程序猿,尤其是前端高级CV工程师,没有便自己创造。

效果

动画2.gif

说明

  1. 因为是要更改第三方页面的内容,结合本人目前的技术栈,选用浏览器插件比较合适;
  2. 插件操作页面主要有四个部分,分别是选头像框区域、选择需要处理的头像、执行结果区域、按钮操作区域;
  3. 基本操作就是选中头像框,再选中需要处理的头像(页面上的全部头像、导航栏的头像,或者指定用户名称的头像),点击添加即可;
  4. 该插件内置了四款头像框可用,如果需要,可以在项目中popup/avatarBorderList.js文件中添加;
  5. 添加边框基本原理是为头像图片添加一个span元素,将头像图片放于span中,所以自定义的头像框中的字段说明如下:
{
  "name": "头像框名称",
  "value": {
    "element": "span样式",
    "before": "span::before样式",
    "after": "span::after样式",
    "other": "其他样式,如动画。。。。"
  }
}

项目地址

Github

基本实现

获取头像

既然是为头像添加边框,那么自然就需要获取到头像的DOM元素,本插件中,获取头像的方法有三种:

  1. 获取页面已有的全部头像,不包括未加载、未渲染的头像:
document.querySelectorAll('.avatar')
  1. 只获取导航栏的头像,这个也是比较简单:
document.querySelectorAll('.main-nav .avatar')
  1. 指定用户名称的头像:这种比较麻烦,一般头像img元素的alt属性上会带有用户名称: 微信截图_20220721092112.png
    但是,有时又会没有,显示undefine微信截图_20220721092217.png
    所以按照用户名称查找时,除了查找图片元素之外,还得查找含有用户名称的元素,两方面同时搜索:
    // 获取指定用户名称的头像框
    const allAvatarElement = document.querySelectorAll('.avatar')
    const userName = avatarCondition[2].value
    const list = []
    // 按照用户名称对 img 元素进行过滤
    for (let i = 0, len = allAvatarElement.length; i < len; i++) {
      const item = allAvatarElement[i]
      item.alt.includes(userName) && list.push(item)
    }
    // 部分 img.alt 属性获取不到用户名称,只能按照用户名称查找方式
    const userNameList = document.querySelectorAll('.username') // 获取页面上的全部用户名称
    for (let i = 0, len = userNameList.length; i < len; i++) {
      const item = userNameList[i]
      if (item.innerText.includes(userName)) {
        // 如果用户名称拥有指定字段,查找相应的 img 元素
        const target = item.parentNode.parentNode.parentNode.querySelector('.avatar')
        target && list.push(target)
      }
    }

添加头像框

添加头像框时,需要先把定义好的样式注入到页面中,这样头像框的类.my-avatar-border才能获取到样式:

// 获取选中的样式
const css = avatarBorderList.find(item => item.name === currentAvatarBorder)
// 将选中的样式拼接成最终样式
currentCssValue = css && css.value ? 
    `.${myAvatarBorderClassName}{${css.value.element};box-sizing: border-box;}
    .${myAvatarBorderClassName}::after{${css.value.after}}
    .${myAvatarBorderClassName}::before{${css.value.before}}
    ${css.value.other}` : ''
// 注入样式
chrome.scripting.insertCSS({ target: { tabId: tab.id }, css: currentCssValue  })

处理好样式之后,就是给指定头像添加边框元素。将头像img元素取出,包裹上一层span元素,其类名为my-avatar-border:

  // 创建包裹 img 的 span
  const avatarBorder = document.createElement('span')
  // 给 span 添加类名
  avatarBorder.classList.add('my-avatar-border')
  // 遍历选中的 img, 逐个添加 span
  for (let i = 0, len = avatarElementList.length; i < len; i++) {
    const targetAvatarElement = avatarElementList[i]
    // 克隆创建的 span
    const cloneElement = avatarBorder.cloneNode(true)
    // 将 span 设定为于 img 同样的宽高
    cloneElement.style = `display:inline-block;width: ${targetAvatarElement.clientWidth}px;height: ${targetAvatarElement.clientHeight}px;`
    // 将 img 放入 span中,再将 span 放入 img.parentNode中
    const parentNode = targetAvatarElement.parentNode
    cloneElement.appendChild(targetAvatarElement)
    parentNode.appendChild(cloneElement)
  }

移除头像框

首先需要移除之前注入页面的样式:

  // 删除注入的样式表
  chrome.scripting.removeCSS({ target: { tabId: tab.id }, css: currentCssValue  })

然后将所有 span.my-avatar-border删除:

  // 获取 span 元素
  const avatarBorderElementList = document.querySelectorAll(`.${myAvatarBorderClassName}`)
  for (let i = 0, len = avatarBorderElementList.length; i < len; i++) {
    // 将 span 删除,将 img 放回原处
    const target = avatarBorderElementList[i]
    const parentNode = target.parentNode
    const img = target.childNodes[0]
    parentNode.removeChild(target)
    parentNode.append(img)
  }

自定义头像框

本插件只有预设四种头像框,如果需要更多的头像框效果,可以在项目中popup/avatarBorderList.js文件中设置,文件内容如下:

export default [
  {
    "name": "头像框名称",
    "value": {
      "element": "span样式",
      "before": "span::before样式",
      "after": "span::after样式",
      "other": "其他样式,如动画。。。。"
    }
  },
  ...
]

其中other可以用来定义一些其他样式,比如动画或者其他元素样式,如:

     "other": `
        @keyframes rotateBorder {
          0% {
            transform: rotateZ(0);
          }
          100% {
            transform: rotateZ(720deg);
          }
        }
        .my-avatar-border img {
          z-index: 1;
        }
      `

预设的边框展示

动画2.gif

我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!