【油猴脚本】在 Iconfont 上直接复制 React component 代码

sxkk20082年前知识分享102

本文接上一篇《如何在项目中管理你的图标?》

Iconfont 和 SVG 优缺点对比

在上文中介绍了使用 iconfont 的缺点,以及使用 SVG 的优点,简单归纳为以下几点:

Icon 的缺点

  • 当网络不好的时候,会显示方块
  • 如只使用一个图标,字体冗余
  • 维护依赖 iconfont 平台
  • 在组件开发的时候命名冲突

使用 SVG 的优点

  • 完全离线化使用,不需要从 CDN 下载字体文件,图标不会因为网络问题呈现方块,也无需字体文件本地部署。
  • 在低端设备上 SVG 有更好的清晰度。
  • 支持多色图标。
  • SVG 可以支持动画

并给出了最终方案,放弃使用字体,使用 SVG 代替 iconfont。

又给出了实践步骤:

  • 老项目中的 iconfont, 可以通过 nodejs 脚本将下载的 iconfont.svg 转为多个 SVG 图标
  • 新加的图标,可以直接在 iconfont.cn 上下载 SVG
  • React 项目中,如果要直接使用 SVG,需要配置 webpack loader —— @svgr/webpack

下面是 webpack.config.js 中要加入的配置

module.exports = {
  module: {
    rules: [
      {
        test: /\.SVG$/i,
        type: 'asset',
        resourceQuery: /url/, // *.SVG?url
      },
      {
        test: /\.SVG$/i,
        issuer: /\.[jt]sx?$/,
        resourceQuery: { not: [/url/] }, // exclude react component if *.SVG?url
        use: ['@SVGr/webpack'],
      },
    ],
  },
}

上面这段配置看上去很简单,当我往项目中配置时,却又遇到了困难,有的时候打包配置是在一个单独的包中,比如使用 vite 脚手架创建的 react 项目, 想要在项目中支持直接使用 SVG, 就必须写一个自定义 plugin。

所以我写了一个油猴脚本,可以在 iconfont.cn 上直接复制 React component 代码,如此一来,我们就省去了配置 webpack 的烦恼。

使用

Tampermonkey 是一个 chrome 插件,允许开发者直接在上面发布脚本,相当于是一个简易的 chrome 插件,若要在 chrome 扩展商店中发布插件的话,需要花费 5 美元。

名字来源 svgr ,就是 iconfont + React component = IconfontR

iconfontr 效果

装完插件后会在原先的下载按钮边上多出一个复制按钮,点击复制按钮复制 react 代码,就可以在 react 项目中粘贴使用了。

实现原理

其实 svgr 可以提供了在 nodejs 中执行的版本 @svgr/core

安装

npm install --save-dev @svgr/core
# or use yarn
yarn add --dev @svgr/core

引入 @SVGr/core 这个包,我们就可以直接使用啦!

  • source: SVG 源码
  • options: SVGr 配置参数
  • state: 转变为 react component 的配置参数

使用

import { transform } from '@SVGr/core'

const SVGCode = `
  xmlns:xlink="http://www.w3.org/1999/xlink">
      style="stroke:#ff0000; fill: #0000ff"/>

`

const jsCode = await transform(SVGCode, { icon: true }, { componentName: 'MyComponent' })

所以我们可以写一个云函数,直接部署到 vercel 上,下面是 nodejs 云函数代码:

import { VercelRequest, VercelResponse } from '@vercel/node'
import { transform } from '@SVGr/core'

export default async (request: VercelRequest, response: VercelResponse) => {
  const { SVGCode } = request.query
  try {
    const jsCode = await transform(SVGCode, { icon: true }, { componentName: 'SVGComponent' })
    return {
      output: SVGCode,
    }
  } catch (error) {
    response.status(200).send(error.message)
  }
}

当不是成功后,我们就可以直接使用云函数的部署地址,直接通过 fetch 调用就可以啦,传入 SVG 源码,输入 react component 组件源码,当然你也可以使用国内的云开发平台,腾讯云或阿里云,主要是因为 vercel 是完全免费的。

直接使用 svgr playground 的接口

当我看到 svgr playground 的时候,我就想知道它的实现原理,打开控制台一看,我们连云函数都不用写了,它就是一个部署在 vercel 上的一个接口。

access-control-allow-origin: *并且允许跨域,所以我们可以直接调用了。

接下来我们只需要通过 Dom api 获得当前点击元素的 SVG 代码

dom 获取 SVG 元素

在每个图标的操作覆盖层加入一新图标,用于复制 react component

原先是块级布局,一列显示 3 行

为了减少页面空间, 将覆盖的背景层改成 grid 布局,正好 2 行 2 列。

  • grid-template-rows: repeat(2, minmax(0, 1fr)); 平均分 2 行;
  • grid-template-columns: repeat(2, minmax(0, 1fr));平均分 2 列,

脚本全部代码

;(function () {
  // 请求接口
  async function fetchSVGr(code) {
    return await fetch('https://api.react-SVGr.com/api/SVGr', {
      headers: {
        'content-type': 'application/json',
      },
      body: JSON.stringify({
        code: code,
        options: {
          icon: false,
          native: false,
          typescript: false,
          ref: false,
          memo: false,
          titleProp: false,
          expandProps: 'end',
          replaceAttrValues: {},
          SVGProps: {},
          SVGo: true,
          SVGoConfig: {
            plugins: [{ name: 'preset-default', params: { overrides: { removeTitle: false } } }],
          },
          prettier: true,
          prettierConfig: { semi: false },
        },
      }),
      method: 'POST',
      mode: 'cors',
      credentials: 'omit',
    }).then((res) => res.json())
  }

  // 往 head 中插入覆盖样式
  const style = `.page-manage-project .project-iconlist .block-icon-list li.cover .icon-cover-unfreeze, .page-manage-project .project-iconlist .block-icon-list li:hover .icon-cover-unfreeze,
.block-icon-list li:hover .icon-cover {
  display: grid!important;
}
.page-manage-project .project-iconlist .block-icon-list li .icon-cover {
  grid-template-rows: repeat(3, minmax(0, 1fr));
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.block-icon-list li .icon-cover {
  grid-template-rows: repeat(2, minmax(0, 1fr));
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.block-icon-list li .icon-cover .cover-item{
  width:auto;
}
.page-manage-project .project-iconlist .block-icon-list li .icon-cover .cover-code{
  height: auto;
  line-height: 40px;
}
.block-icon-list li .icon-cover .cover-item-line {
  height: auto;
  line-height: 52.5px;
}`

  const styleEl = document.createElement('style')
  styleEl.textContent = style
  document.head.appendChild(styleEl)

  function addCopybtn() {
    console.log([...document.querySelectorAll('.icon-cover')])
    ;[...document.querySelectorAll('.icon-cover')].forEach((item) => {
      const span = document.createElement('span')
      span.title = '复制 React component'
      span.className = 'cover-item iconfont cover-item-line icon-fuzhidaima'

      span.onclick = async () => {
        const SVG = `${
          item.parentNode.querySelector('SVG').innerHTML
        }`
        console.log('SVG', SVG)
        try {
          const res = await fetchSVGr(SVG)
          navigator.clipboard.writeText(res.output)
          console.log('React component 复制成功!')
        } catch (error) {
          console.log('请求服务出错')
        }
      }
      item.appendChild(span)
    })
  }
  // 监听路
  window.onpopstate = function (event) {
    addCopybtn()
  }

  // 调用 `history.pushState()` 或者 `history.replaceState()` 不会触发 `popstate` 事件,所以是点击时,对比 url 判断
  let href = window.location.href
  document.addEventListener('click', (e) => {
    setTimeout(() => {
      if (window.location.href !== href) {
        addCopybtn()
        href = window.location.href
      }
    }, 500)
  })

  //由于异步加载,需要延迟执行
  setTimeout(() => {
    addCopybtn()
  }, 1000)
})()

以上就是本文全部内容,希望这篇文章对大家有所帮助,也可以参考我往期的文章或者在评论区交流你的想法和心得,欢迎一起探索前端。

相关文章

https://retor.hr/

https://sedeblockchain.com/

https://dnaprojecten.nl/

web design trend 2023 example 1 https://nationalstudentshow.com/

https://anakaric.com/

https://yaremenko.design/

https://www.landa.as/es/

web design trend 2023 example https://selectedbase.com/

CSS First

在过去,我们通常依靠 JavaScript 来创造网站的视觉效果。但从那时起,CSS 已经发展到可以做很多复杂的事情,而这些事情是 JavaScript 无法做到的。三维变换、过滤器和新的 CSS 功能,如:选择器(has)、容器查询(@container)和层叠层(@layer),将使许多有趣的网页设计纯粹依靠 CSS 来实现。

因此,从今年开始,我们将看到网站减少对 JavaScript 的依赖来创造视觉效果。

https://redstapler.co/cool-css-text-light-effect-5-minutes-tutorial/

https://redstapler.co/3d-infinity-effect-css-tutorial/

https://codepen.io/seyedi/pen/zYoeLEv

3d transparent video https://redstapler.co/create-3d-effect-on-website-using-transparent-video-background/

2023 web 设计趋势

翻译一篇文章原文链接:https://redstapler.co/web-design-trends-2023/作者:TK在过去的一年里,我们在网页设计领域看到了很多令人兴奋的发展。而在这篇文章中,我...

人工智能机器人为你服务-革新未来的智能生活

人工智能机器人为你服务-革新未来的智能生活

  早在上世纪60年代,人们就开始梦想着人工智能机器人为我们服务的美好场景。如今,这一梦想正在变为现实,AI机器人已经开始逐渐融入我们的生活,为我们带来便利和舒适。  人工智...

AI绘画技术初探

AI绘画技术初探

  随着AI技术的快速发展,越来越多的领域开始利用这项技术进行创新和改进。其中,AI绘画技术已经逐渐成为热门话题。那么,AI绘画是如何运作的呢?本文将以此为中心,介绍AI绘画...

人脸识别:探寻其在人工智能领域地位和影响力

人脸识别:探寻其在人工智能领域地位和影响力

  人工智能的不断进步和创新已经取得了在各个领域非凡的成就,其中之一便是人脸识别技术。然而,人脸识别是否真正属于人工智能范畴一直备受关注和争议。以人脸识别是人工智能,探讨其在...

AI客服机器人哪个好?市场需求逐渐提升

AI客服机器人哪个好?市场需求逐渐提升

  近年来,AI客服机器人在以公开渠道为主的服务行业中逐渐得到了大众的认可和广泛的应用。然而,不同的AI客服机器人平台各有特点,产品质量和服务水平也不尽相同。本文将从市场需求...

人工智能与分布式计算:潜力巨大的合作伙伴

人工智能与分布式计算:潜力巨大的合作伙伴

  随着人工智能技术的迅速发展和应用的广泛普及,分布式计算成为了支撑人工智能发展的重要基础设施。人工智能的算法训练和推理过程需要大量的计算资源,而分布式计算能够通过将计算任务...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。