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

目录
相关文章
|
2月前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
148 64
|
2月前
|
JavaScript 前端开发 API
Vue 3 中 v-model 与 Vue 2 中 v-model 的区别是什么?
总的来说,Vue 3 中的 `v-model` 在灵活性、与组合式 API 的结合、对自定义组件的支持等方面都有了明显的提升和改进,使其更适应现代前端开发的需求和趋势。但需要注意的是,在迁移过程中可能需要对一些代码进行调整和适配。
118 60
|
13天前
|
JavaScript API 数据处理
vue3使用pinia中的actions,需要调用接口的话
通过上述步骤,您可以在Vue 3中使用Pinia和actions来管理状态并调用API接口。Pinia的简洁设计使得状态管理和异步操作更加直观和易于维护。无论是安装配置、创建Store还是在组件中使用Store,都能轻松实现高效的状态管理和数据处理。
47 3
|
2月前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
41 8
|
2月前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
35 1
|
2月前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
45 1
|
2月前
|
JavaScript
在 Vue 3 中,如何使用 v-model 来处理自定义组件的双向数据绑定?
需要注意的是,在实际开发中,根据具体的业务需求和组件设计,可能需要对上述步骤进行适当的调整和优化,以确保双向数据绑定的正确性和稳定性。同时,深入理解 Vue 3 的响应式机制和组件通信原理,将有助于更好地运用 `v-model` 实现自定义组件的双向数据绑定。
|
2月前
|
JavaScript 索引
Vue 3.x 版本中双向数据绑定的底层实现有哪些变化
从Vue 2.x的`Object.defineProperty`到Vue 3.x的`Proxy`,实现了更高效的数据劫持与响应式处理。`Proxy`不仅能够代理整个对象,动态响应属性的增删,还优化了嵌套对象的处理和依赖追踪,减少了不必要的视图更新,提升了性能。同时,Vue 3.x对数组的响应式处理也更加灵活,简化了开发流程。
|
2月前
|
存储 JavaScript 前端开发
介绍一下Vue的核心功能
介绍一下Vue的核心功能
|
2月前
|
JavaScript 前端开发 API
从Vue 2到Vue 3的演进
从Vue 2到Vue 3的演进
48 0

热门文章

最新文章