如何魔改不维护的开源库来满足自己的需求

背景

在开发开源库vue-design-editor过程中,需要一款设置画布背景色或其他元素颜色的颜色选择器, 在 github 中看大部分只支持 vue2, 不支持 vue3, 也不支持渐变色设置, 千辛万苦找到了一款优秀的开源颜色选择器库vue3-colorpicker, 本来心满意足的在项目中使用, 不过在开发过程中也发现了两大缺陷

缺陷一

不支持多点渐变

缺陷二

linear-gradient(0deg, rgba(241, 98, 126, 1) 0%, rgba(0, 0, 0, 1) 100%)

以上是返回的渐变数据,是一个只局限于 dom 元素的背景样式, 扩展性底, 如果想支持以下格式

js 复制代码
colorStops: [
  // 定义渐变颜色的数组
  { offset: 0, color: "red" },
  { offset: 0.2, color: "orange" },
  { offset: 0.4, color: "yellow" },
  { offset: 0.6, color: "green" },
  { offset: 0.8, color: "blue" },
  { offset: 1, color: "purple" },
];

需要正则匹配或使用gradient-parser解析, 复杂度上升

为了解决以上两个问题只能 pull 源代码进行魔改

为什么不fork

原仓库已不更新, 如果fork后在github上就搜索不到该仓库,为了更多人使用优化后的库,减少重复造轮子, 所以重新创建了单独仓库

仓库地址: github.com/haixin-fang...

多点渐变支持

数据结构优化

从渐变组件源代码可以看出, 只定义了开始和结束两个节点数据, 该数据结构不满足在原有基础上进行逻辑修改, 所以重构了渐变数据结构

原有结构

js 复制代码
const gradientState = reactive({
  startColor,
  endColor,
  startColorStop: 0,
  endColorStop: 100,
  angle: 0,
  type: "linear",
  gradientColor: props.gradientColor,
});

重写结构

js 复制代码
  const gradientState = reactive<any>({
    colors: [],
    angle: 0,
    type: "linear",
    gradientColor: props.gradientColor,
  });

使用数组结构来存储渐变的多点数据

新增节点

color-scales的作用是该在具有定义的最小值和最大值的两个颜色端点之间以线性渐变形式返回值的颜色。

就不用新增一个节点就初始化一个固定色值, 过渡自然

也需要通过点击事件的位置计算出在渐变区间内的固定位置,作为断点值

js 复制代码
const handlePotBar = (e: MouseEvent) => {
      if (refColorBar.value) {
        const barBounding = refColorBar.value.getBoundingClientRect();
        const barLeft = barBounding.left;
        const colorPotDist = e.pageX - barLeft;
        const value = cloneDeep(state.colors);
        // 渐变条stopColors;
        const rangColors = value
          .sort((a: any, b: any) => a.pst - b.pst)
          .map((item: any) => {
            return item.toHexString();
          });

        // 初始化色条Range,用来取渐变色值
        const colorScale = new ColorScale(0, barBounding.width, rangColors);
        const colorPotHex = colorScale.getColor(colorPotDist).toHexString();
        const colorPotPst = (100 * colorPotDist) / barBounding.width;
        const addPot = new Color(colorPotHex);
        addPot.pst = colorPotPst;
        state.colors.push(addPot);
        // 增加后默认选中
        state.selectIndex = state.colors.length - 1;
        emit("gradientChange", state.colors);
      }
};

节点滑动交互

每个节点支持通过鼠标拖动位置

绑定mousedown事件

html 复制代码
          <div
              class="vc-gradient__stop"
              v-for="(item, index) in colors"
              :key="index"
              :class="{
                'vc-gradient__stop--current': index == state.selectIndex,
              }"
              ref="startGradientRef"
              :style="{ left: `calc(${item.pst + '%'} - 8px)` }"
              @mousedown="sliderPotDown(index, $event)"
              @click="clickGColorPot(index)"
            >
              <span class="vc-gradient__stop--inner"></span>
          </div>

滑动交互

持久存储mousedown落下的位置, 通过监听mousemove事件实时获取鼠标移动的位置, 计算出和mousedown初始位置的距离实时改变节点数组的pst(节点位置)字段, vue通过数据双向绑定来修改节点dom的位置, 实现节点随鼠标滑动的交互

useEventListener 是vueuse提供的hooks, 轻松使用事件监听。在挂载时使用 addEventListener 注册,在卸载时自动使用 removeEventListener

js 复制代码
    const handleEleMouseMove = (e: MouseEvent) => {
      if (!isSelectBoxMouseDown) return;
      state.movePst.x = e.pageX - state.mouseStartPst.x;
      state.movePst.y = e.pageY - state.mouseStartPst.y;
      state.pageX = e.pageX;
      state.pageY = e.pageY;
      sliderMove();
    };
    const sliderMove = () => {
      if (refColorBar.value) {
        const barWidth = refColorBar.value.getBoundingClientRect().width;
        let distRatio =
          ((state.startMovePst * barWidth) / 100 + state.movePst.x) / barWidth;
        if (distRatio > 1) {
          distRatio = 1;
        } else if (distRatio < 0) {
          distRatio = 0;
        }
        state.colors[state.selectIndex].pst = Math.round(distRatio * 100);
        emit("gradientChange", state.colors);
      }
    };
    const handleEleMouseUp = () => {
      isSelectBoxMouseDown = false;
      sliderDone();
    };
    const sliderDone = () => {
      resetDraggle();
    };
    const resetDraggle = () => {
      isSelectBoxMouseDown = false;
      state.mouseStartPst = { x: 0, y: 0 };
      state.movePst.x = 0;
      state.movePst.y = 0;
    };
    const bindEventsDoc = () => {
      useEventListener(document.body, "mousemove", handleEleMouseMove);
      useEventListener(document.body, "mouseup", handleEleMouseUp);
    };

    const clickGColorPot = (index: Number) => {
      if (state.selectIndex === index) return;
      state.selectIndex = index;
    };
    const sliderStart = () => {
      state.startMovePst = state.colors[state.selectIndex].pst;
    };
    const sliderPotDown = (index: Number, $event: MouseEvent) => {
      bindEventsDoc();
      const e: MouseEvent = $event;
      clickGColorPot(index);
      isSelectBoxMouseDown = true;
      state.mouseStartPst.x = e.pageX;
      state.mouseStartPst.y = e.pageY;
      sliderStart();
    };

发布npm

使用npm publish 发布到npm中, 这样在vue-design-editor项目中可以直接通过npm install方式进行安装

为什么包名是colorpickers, 因为我能想到的vue-color, vuecolorpicker等各种名称已被占用

文档更新

原有的文档是使用storybook开发的, 所以基于该文档,增加了两个配置和优化了事件回调, 原文档的事件回调数据未打印,造成事件回调数据不直观,影响体验

新增两个配置

  • 渐变底层数据, 提高该库的扩展性
  • 渐变模块线性或经向按钮可自定义展示
js 复制代码
    gradientData: {
      control: "text",
      description: "Get gradient details",
    },
    gradientType: {
      type: "string",
      description: "linear | radial | both",
      control: { type: "select" },
      options: ["radial", "linear", "both"],
      table: {
        defaultValue: {
          summary: "both",
        },
      },
    },
js 复制代码
import { action } from "@storybook/addon-actions";

{
  template:
      '<div class="demo">' +
      '<ColorPicker v-model:pureColor="pureColor" v-model:gradientColor="gradientColor" v-bind="args" @activeKeyChange="activeKeyChange" @gradientColorChange="gradientColorChange" @gradientDataChange="onChange" @pureColorChange="pureColorChange" />' +
      "</div>",
    methods: {
      onChange: action("gradientDataChange"),
      pureColorChange: action("pureColorChange"),
      gradientColorChange: action("gradientColorChange"),
      activeKeyChange: action("activeKeyChange"),
    }
}

haixin-fang.github.io/colorpicker...

workflow

使用github的工作流功能, 每一次更新代码并提交到github中都会自动更新文档

yaml 复制代码
name: GitHub Actions Build and Deploy
on:
  push:
    branches:
      - main
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v1
        with:
          persist-credentials: false
      - name: Install and Build
        run: |
          npm install --force
          npm run-script build-storybook
      - name: Deploy
        uses: JamesIves/[email protected]
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          BRANCH: gh-pages
          FOLDER: storybook-static
          CLEAN: true

新特性总结

  • 支持多点渐变
  • 渐变绑定的数据是linear-gradient字符串,不满足个性化需求,提供了渐变底层数据,可以使用gradientData数据双向绑定或者gradientDataChange方法获取
  • 支持线性或经向渐变按钮自定义展示,通过 gradientType: "linear | radial | both" 控制
  • 修复透明度输入框有小数问题
  • 文档支持事件打印,可直观看数据结构和事件方法
  • 可长期维护

安装与使用

vue-design-editor项目中使用以下命令进行安装

csharp 复制代码
yarn add colorpickers

OR

复制代码
npm install colorpickers

使用

vue 复制代码
<template>
  <!-- :gradientType="'linear'" -->
  <color-picker
    :pureColor="pureColor"
    :gradientColor="gradientColor"
    :isWidget="true"
    :useType="useType"
    @pureColorChange="onPureColor"
    @gradientDataChange="gradientColorChange"
  />
</template>
<script setup>
import { ColorPicker } from "colorpickers";
import "colorpickers/style.css";
import { defineProps, defineEmits } from "vue";
const emit = defineEmits(["select"]);
defineProps({
  useType: { type: String, default: "both" },
  pureColor: {
    type: String,
    default: "red",
  },
  gradientColor: {
    type: String,
    default: "",
  },
});
function onPureColor(color) {
  emit("select", {
    fill: color,
  });
}
function gradientColorChange(color) {
  emit("select", {
    gradient: color,
  });
}
</script>

最终效果

比搞定设计多了经向渐变背景色设置

简介

vue-design-editor 是仿搞定设计的一款开源图片编辑器, 支持多种格式的导入,包括png、jpg、gif、mp4, 也可以一键psd转模板(后续开发)

github地址 预览

上个开源库是 starfish-vue3-lowcode

github地址 预览

相关推荐
江城开朗的豌豆3 分钟前
Git分支管理:从'独狼开发'到'团队协作'的进化之路
前端·javascript·面试
GIS之家4 分钟前
vue+cesium示例:3D热力图(附源码下载)
前端·vue.js·3d·cesium·webgis·3d热力图
幽蓝计划5 分钟前
鸿蒙Next仓颉语言开发实战教程:下拉刷新和上拉加载更多
前端
红衣信6 分钟前
电影项目开发中的编程要点与用户体验优化
前端·javascript·github
LeeAt11 分钟前
npm:详细解释前端项目开发前奏!!
前端·node.js·html
山有木兮木有枝_13 分钟前
JavaScript对象深度解析:从创建到类型判断 (上)
前端
crary,记忆21 分钟前
MFE(微前端) Module Federation:Webpack.config.js文件中每个属性的含义解释
前端·学习·webpack
清风~徐~来23 分钟前
【Qt】控件 QWidget
前端·数据库·qt
前端小白从0开始24 分钟前
关于前端常用的部分公共方法(二)
前端·vue.js·正则表达式·typescript·html5·公共方法
真的很上进30 分钟前
2025最全TS手写题之partial/Omit/Pick/Exclude/Readonly/Required
java·前端·vue.js·python·算法·react·html5