vue3_制作一个在线修改svg颜色功能

简介: vue3_制作一个在线修改svg颜色功能

效果

可点击色块切换svg的颜色,可记录前七种选择的颜色和当前选择的色号
image.png

image.png

灵感来源

来源阿里图标库的在线修改svg颜色功能
image.png

思路

利用img标签产生一个shadow阴影,再使用transform把原图移走,达到替换svg颜色的效果

 if (state.colorValue) {
          document.getElementById("design-svg-id").style.transform = `translate(-500px)`;
          document.getElementById(
            "design-svg-id"
          ).style.filter = `drop-shadow(500px 0 0 ${state.colorValue})`;
        }

实现

/* eslint-disable vue/valid-v-model */
<template>
  <div class="design">
    <div class="design-img">
      <img src="../../assets/logo.svg" id="design-svg-id" />
    </div>
    <div class="design-color-extract" :ref="extractRef" id="extract-id"></div>
    <div class="design-color-select-box">
      <div class="design-color-select-box-record" :ref="selecttRef" id="select-id"></div>
      <div class="design-color-select-box-focus">
        <div class="design-color-select-box-focus-color-value">{{ colorValue }}</div>
        <div class="design-color-select-box-focus-box" id="select-color-box-id"></div>
      </div>
      <!-- <div class="design-color-select-box-svg-size">
        <a-input-number
          id="inputNumber"
          v-model:value="sizeValue"
          :min="1"
          :max="10"
          class="design-color-select-box-svg-size-input"
        />
      </div> -->
    </div>
    <div class="design-color-quick-extract"></div>
  </div>
</template>

<script>
import { ref, onMounted, reactive, toRefs, watch } from "vue";
export default {
  name: "DesignSvg",
  props: {},
  setup() {
    const state = reactive({
      sizeValue: ref(0),
      colorValue: ref("#"),
      colorArray: [
        "d81e06",
        "f4ea2a",
        "1afa29",
        "1296db",
        "13227a",
        "d4237a",
        "ffffff",
        "e6e6e6",
        "dbdbdb",
        "cdcdcd",
        "bfbfbf",
        "8a8a8a",
        "707070",
        "515151",
        "2c2c2c",
      ],
      colorSelected: [
        "e6e6e6",
        "dbdbdb",
        "cdcdcd",
        "bfbfbf",
        "8a8a8a",
        "707070",
        "515151",
        "2c2c2c",
      ],
      colorDomSelect: [],
      colorDomRecord: [],
    });
    const extractRef = ref(null);
    const selecttRef = ref(null);
    onMounted(() => {
      // 选择颜色
      initBoxColor();
      // 历史选择颜色
      initBoxSelected();
      // 选择的数组
      console.log("domSelect", state.colorDomSelect);
      console.log("domRecord", state.colorDomRecord);
      initClick();
    });
    // 获取颜色
    function initBoxColor() {
      state.colorArray.map((item) => {
        let singleBoxColor = document.createElement("div");
        singleBoxColor.className = "box";
        singleBoxColor.style.background = "#" + item;
        state.colorDomSelect.push(singleBoxColor);
        document.getElementById("extract-id").appendChild(singleBoxColor);
      });
    }
    // 容器记录选中的颜色
    function initBoxSelected() {
      state.colorSelected.map((item) => {
        let singleBoxColor = document.createElement("div");
        singleBoxColor.className = "box";
        singleBoxColor.style.background = "#" + item;
        state.colorDomRecord.push(singleBoxColor);
        document.getElementById("select-id").appendChild(singleBoxColor);
      });
    }
    // 添加事件 修改color
    function initClick() {
      state.colorDomSelect.map((item, index) => {
        item.addEventListener("click", function () {
          // color
          state.colorValue = "#" + state.colorArray[index];
          document.getElementById(
            "select-color-box-id"
          ).style.background = `${state.colorValue}`;
          // record
          if (state.colorSelected.includes(state.colorArray[index])) {
            console.log("have");
          } else {
            // 加入数组第一个
            let length = state.colorSelected.length;
            for (let loc = length - 1; loc > -1; --loc) {
              if (loc === 0) {
                // 第一个元素
                state.colorSelected[loc] = state.colorArray[index];
              } else {
                // 后移一位
                state.colorSelected[loc] = state.colorSelected[loc - 1];
              }
              // 替换颜色
              state.colorDomRecord[loc].style.background = "#" + state.colorSelected[loc];
            }
            // console.log("state.colorDomRecord", state.colorDomRecord);
          }
        });
      });
    }
    // 监听颜色变化
    watch(
      () => state.colorValue,
      () => {
        if (state.colorValue) {
          document.getElementById("design-svg-id").style.transform = `translate(-500px)`;
          document.getElementById(
            "design-svg-id"
          ).style.filter = `drop-shadow(500px 0 0 ${state.colorValue})`;
        }
      }
    );
    // 监听svg大小变化
    watch(
      () => state.sizeValue,
      () => {
        console.log("size", document.getElementById("design-svg-id").style.transform);
        if (state.sizeValue > 0) {
          let num = state.sizeValue * 0.1 + 1;
          document.getElementById("design-svg-id").style.transform = `scale(${num})`;
        } else {
          state.sizeValue = 1;
        }
      }
    );
    return { ...toRefs(state), extractRef, selecttRef };
  },
};
</script>

<style>
.design {
  position: relative;
  width: 100%;
  height: 100%;
  background: rgba(241, 193, 164, 0.603));
  border-radius: 10px;
  padding: 20px;
  box-shadow: 0 1px 20px rgba(0, 0, 0, 0.1);
}
.design-img {
  position: relative;
  overflow: hidden;
  width: 100%;
  height: 300px;
}
.design-color-extract {
  position: relative;
  display: flex;
  height: 60px;
}
.design-color-select-box {
  position: relative;
  display: flex;
}
.design-color-select-box-record {
  position: relative;
  display: flex;
  width: 50%;
  height: 60px;
}
.design-color-quick-extract {
  position: relative;
  height: 60px;
}
.design-color-select-box-focus {
  position: relative;
  margin-left: 10px;
  width: 110px;
  height: 50px;
  border: 1px solid #444;
  display: flex;
  background: #fff;

  box-shadow: 0 1px 20px rgba(0, 0, 0, 0.2);
}
.design-color-select-box-focus-box {
  position: relative;
  top: 50%;
  transform: translateY(-50%);
  width: 40px;
  height: 25px;
  border: 1px solid #444;
  margin-left: 20px;
  width: 25px;
}
.design-color-select-box-focus-color-value {
  position: relative;
  width: 60px;
  margin-left: 2px;
  top: 50%;
  transform: translateY(-50%);
  height: 25px;
  border: 1px solid #444;
  text-align: left;
}
.design-color-select-box-svg-size {
  position: relative;
  margin-left: 10px;
  width: 100px;
  height: 50px;
  border: 1px solid #444;
  overflow: hidden;
  box-sizing: border-box;
}

.design-color-select-box-svg-size-input {
  position: relative;
  outline: none;
  text-align: center;
  width: 100%;
  height: 100%;
}
.box {
  position: relative;
  width: 40px;
  height: 40px;
  cursor: pointer;
}
</style>

我的代码仓库

传送门:https://codechina.csdn.net/qq_38870145/edit_svg
image.png

目录
相关文章
|
3月前
|
JavaScript 前端开发 安全
Vue 3
Vue 3以组合式API、Proxy响应式系统和全面TypeScript支持,重构前端开发范式。性能优化与生态协同并进,兼顾易用性与工程化,引领Web开发迈向高效、可维护的新纪元。(238字)
643 139
|
3月前
|
缓存 JavaScript 算法
Vue 3性能优化
Vue 3 通过 Proxy 和编译优化提升性能,但仍需遵循最佳实践。合理使用 v-if、key、computed,避免深度监听,利用懒加载与虚拟列表,结合打包优化,方可充分发挥其性能优势。(239字)
307 1
|
8月前
|
缓存 JavaScript PHP
斩获开发者口碑!SnowAdmin:基于 Vue3 的高颜值后台管理系统,3 步极速上手!
SnowAdmin 是一款基于 Vue3/TypeScript/Arco Design 的开源后台管理框架,以“清新优雅、开箱即用”为核心设计理念。提供角色权限精细化管理、多主题与暗黑模式切换、动态路由与页面缓存等功能,支持代码规范自动化校验及丰富组件库。通过模块化设计与前沿技术栈(Vite5/Pinia),显著提升开发效率,适合团队协作与长期维护。项目地址:[GitHub](https://github.com/WANG-Fan0912/SnowAdmin)。
1086 5
|
4月前
|
开发工具 iOS开发 MacOS
基于Vite7.1+Vue3+Pinia3+ArcoDesign网页版webos后台模板
最新版研发vite7+vue3.5+pinia3+arco-design仿macos/windows风格网页版OS系统Vite-Vue3-WebOS。
480 11
|
3月前
|
JavaScript 安全
vue3使用ts传参教程
Vue 3结合TypeScript实现组件传参,提升类型安全与开发效率。涵盖Props、Emits、v-model双向绑定及useAttrs透传属性,建议明确声明类型,保障代码质量。
356 0
|
5月前
|
缓存 前端开发 大数据
虚拟列表在Vue3中的具体应用场景有哪些?
虚拟列表在 Vue3 中通过仅渲染可视区域内容,显著提升大数据列表性能,适用于 ERP 表格、聊天界面、社交媒体、阅读器、日历及树形结构等场景,结合 `vue-virtual-scroller` 等工具可实现高效滚动与交互体验。
548 1
|
5月前
|
缓存 JavaScript UED
除了循环引用,Vue3还有哪些常见的性能优化技巧?
除了循环引用,Vue3还有哪些常见的性能优化技巧?
316 0
|
6月前
|
JavaScript
vue3循环引用自已实现
当渲染大量数据列表时,使用虚拟列表只渲染可视区域的内容,显著减少 DOM 节点数量。
149 0
|
8月前
|
JavaScript API 容器
Vue 3 中的 nextTick 使用详解与实战案例
Vue 3 中的 nextTick 使用详解与实战案例 在 Vue 3 的日常开发中,我们经常需要在数据变化后等待 DOM 更新完成再执行某些操作。此时,nextTick 就成了一个不可或缺的工具。本文将介绍 nextTick 的基本用法,并通过三个实战案例,展示它在表单验证、弹窗动画、自动聚焦等场景中的实际应用。
715 17
|
8月前
|
JavaScript 前端开发 API
Vue 2 与 Vue 3 的区别:深度对比与迁移指南
Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架,在过去的几年里,Vue 2 一直是前端开发中的重要工具。而 Vue 3 作为其升级版本,带来了许多显著的改进和新特性。在本文中,我们将深入比较 Vue 2 和 Vue 3 的主要区别,帮助开发者更好地理解这两个版本之间的变化,并提供迁移建议。 1. Vue 3 的新特性概述 Vue 3 引入了许多新特性,使得开发体验更加流畅、灵活。以下是 Vue 3 的一些关键改进: 1.1 Composition API Composition API 是 Vue 3 的核心新特性之一。它改变了 Vue 组件的代码结构,使得逻辑组
1932 0