vue實(shí)現(xiàn)自定義顏色選擇器
vue自定義顏色選擇器
效果圖:
step0: 默認(rèn)寫法 調(diào)用系統(tǒng)自帶的顏色選擇器
<input type="color">
step1:C:\Users\wangrusheng\PycharmProjects\untitled18\src\views\Home.vue
<template> <div class="container"> <!-- 顏色選擇器組件 --> <ColorPicker v-model="selectedColor" /> <!-- 新增的動(dòng)態(tài)背景按鈕 --> <div> <button class="dynamic-button" :style="{ backgroundColor: selectedColor }" > 我的背景色會(huì)變化! </button> <input type="color"> <p>當(dāng)前選中顏色: {{ selectedColor }}</p> </div> </div> </template> <script> import ColorPicker from './ColorPicker.vue' export default { components: { ColorPicker }, data() { return { selectedColor: '#ff0000' // 默認(rèn)顏色 } } } </script>
step2:C:\Users\wangrusheng\PycharmProjects\untitled18\src\views\ColorPicker.vue
<template> <div class="color-picker"> <!-- 飽和度/明度選擇區(qū)域 --> <div class="saturation" :style="{ backgroundColor: `hsl(${hsv.h}, 100%, 50%)` }" @mousedown="startDrag" > <div class="selector" :style="{ left: `${hsv.s * 100}%`, top: `${(1 - hsv.v) * 100}%`, backgroundColor: currentColor }" ></div> </div> <!-- 色相滑塊 --> <div class="hue-slider" @mousedown="startHueDrag"> <div class="hue-pointer" :style="{ left: `${(hsv.h / 360) * 100}%` }" ></div> </div> <!-- 顏色顯示和輸入 --> <div class="color-preview" :style="{ backgroundColor: currentColor }"></div> <input v-model="hexColor" class="hex-input" placeholder="#FFFFFF" @input="handleHexInput" > </div> </template> <script> export default { props: { modelValue: String }, emits: ['update:modelValue'], data() { return { hsv: { h: 0, s: 1, v: 1 }, hexColor: '#ff0000', isDragging: false, isHueDragging: false } }, computed: { currentColor() { return this.hsvToHex(this.hsv) } }, methods: { startDrag(e) { this.isDragging = true this.handleDrag(e) window.addEventListener('mousemove', this.handleDrag) window.addEventListener('mouseup', this.stopDrag) }, startHueDrag(e) { this.isHueDragging = true this.handleHueDrag(e) window.addEventListener('mousemove', this.handleHueDrag) window.addEventListener('mouseup', this.stopHueDrag) }, handleDrag(e) { if (!this.isDragging) return const rect = e.target.getBoundingClientRect() const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width)) const y = Math.max(0, Math.min(1, (e.clientY - rect.top) / rect.height)) this.hsv.s = x this.hsv.v = 1 - y this.updateHex() }, handleHueDrag(e) { if (!this.isHueDragging) return const rect = e.target.getBoundingClientRect() const x = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width)) this.hsv.h = x * 360 this.updateHex() }, stopDrag() { this.isDragging = false window.removeEventListener('mousemove', this.handleDrag) window.removeEventListener('mouseup', this.stopDrag) }, stopHueDrag() { this.isHueDragging = false window.removeEventListener('mousemove', this.handleHueDrag) window.removeEventListener('mouseup', this.stopHueDrag) }, updateHex() { this.hexColor = this.hsvToHex(this.hsv) this.$emit('update:modelValue', this.hexColor) }, handleHexInput() { if (/^#([0-9A-F]{3}){1,2}$/i.test(this.hexColor)) { this.hsv = this.hexToHsv(this.hexColor) } }, // 顏色轉(zhuǎn)換函數(shù) hsvToHex(hsv) { const h = hsv.h / 360 let r, g, b const i = Math.floor(h * 6) const f = h * 6 - i const p = hsv.v * (1 - hsv.s) const q = hsv.v * (1 - f * hsv.s) const t = hsv.v * (1 - (1 - f) * hsv.s) switch (i % 6) { case 0: r = hsv.v, g = t, b = p; break case 1: r = q, g = hsv.v, b = p; break case 2: r = p, g = hsv.v, b = t; break case 3: r = p, g = q, b = hsv.v; break case 4: r = t, g = p, b = hsv.v; break case 5: r = hsv.v, g = p, b = q; break } return `#${[r, g, b] .map(x => Math.round(x * 255) .toString(16) .padStart(2, '0')) .join('')}` }, hexToHsv(hex) { // 轉(zhuǎn)換邏輯(此處省略具體實(shí)現(xiàn)) // 返回類似 {h: 0, s: 1, v: 1} 的HSV對(duì)象 } } } </script> <style> .color-picker { width: 300px; padding: 20px; background: #fff; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } .saturation { position: relative; width: 100%; height: 200px; border-radius: 4px; background: linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent); } .selector { position: absolute; width: 16px; height: 16px; border: 2px solid white; border-radius: 50%; transform: translate(-8px, -8px); box-shadow: 0 1px 3px rgba(0,0,0,0.3); } .hue-slider { position: relative; height: 12px; margin: 15px 0; background: linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); border-radius: 6px; } .hue-pointer { position: absolute; width: 16px; height: 16px; background: white; border-radius: 50%; transform: translate(-8px, -2px); box-shadow: 0 1px 3px rgba(0,0,0,0.3); } .color-preview { width: 40px; height: 40px; border-radius: 4px; border: 1px solid #ddd; } .hex-input { margin-left: 10px; padding: 8px; width: 100px; border: 1px solid #ddd; border-radius: 4px; } </style>
到此這篇關(guān)于vue實(shí)現(xiàn)自定義顏色選擇器的文章就介紹到這了,更多相關(guān)vue顏色選擇器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue-cli3項(xiàng)目打包后自動(dòng)化部署到服務(wù)器的方法
這篇文章主要介紹了vue-cli3項(xiàng)目打包后自動(dòng)化部署到服務(wù)器的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09Vue頁(yè)面內(nèi)公共的多類型附件圖片上傳區(qū)域并適用折疊面板(示例代碼)
本文中實(shí)現(xiàn)的附件上傳區(qū)域支持超多類型附件分類型上傳,并且可根據(jù)特定條件具體展示某些類型的附件上傳,本文給大家分享Vue頁(yè)面內(nèi)公共的多類型附件圖片上傳區(qū)域并適用折疊面板的示例代碼,需要的朋友參考下吧2021-12-12Vue2(三)實(shí)現(xiàn)子菜單展開收縮,帶動(dòng)畫效果實(shí)現(xiàn)方法
這篇文章主要介紹了vue實(shí)現(xiàn)收縮展開效果的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04vue項(xiàng)目中使用lib-flexible解決移動(dòng)端適配的問(wèn)題解決
這篇文章主要介紹了vue項(xiàng)目中使用lib-flexible解決移動(dòng)端適配的問(wèn)題解決,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08vue路由結(jié)構(gòu)可設(shè)一層方便動(dòng)態(tài)添加路由操作
這篇文章主要介紹了vue路由結(jié)構(gòu)可設(shè)一層方便動(dòng)態(tài)添加路由操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08