1 | 需求是一个vue组件封装 通过弹框填写相应属性(弹框做属性填写和选择 加属性预览) 点击确定后关闭弹框拿到返回的数据更新状态树 |
代码:vue部分
<template> <div class="fillDialog"> <div class="mask" @click="cancel"></div> <div class="fillDialogContent"> <div class="title"> 编辑填充 <img src="/images/close.png" class="img" @click="cancel"/> </div> <!-- 内容区 --> <div class="content"> <div class="content_left"> <ul class="ul"> <li class="li" @click="fill_.fillColor.value = 'none';fill_.fillGradientColor.value = 'color'"> <div class="lititle"> <img src="../../assets/selected.png" alt="" v-if="fill_.fillColor.value == 'none'"> <img src="../../assets/select.png" alt="" v-else> <span >无填充</span> </div> </li> <li class="li"> <div class="lititle" @click="fill_.filColor.value = ''"> <img src="../../assets/select.png" alt="" v-if=" fill_.fillColor.value == 'none'"> <img src="../../assets/selected.png" alt="" v-else> <span>填充</span> </div> <div v-if=" fill_.fillColor.value !== 'none'" class="liContent"> <div class="liItem"> <label for="">透明度</label> <select name="" id="" v-model="fill_.fillOpacity.value"> <option v-for="(item,index) in fill_.fillOpacity.range" :key="index" :value="item" >{{item}}</option> </select> </div> <div class="liItem"> <label for="">颜色选择</label> <select name="" id="" v-model="fill_.fillGradientColor.value"> <option value="#linearCol">纵向线性渐变</option> <option value="#linearRow">横向线性渐变</option> <option value="#radial">径向渐变</option> <option value="color">填充色</option> </select> <dl v-if="fill_.fillGradientColor.value !== 'color'"> <dd v-for="(v,i) in fill_.fillGradientColorGroup.value" :key="i" > <label for="">{{v.label+ '%'}}</label> <input type="color" v-model="v.value"> <button style="margin-left:20px;" @click="deleteColor(i)" :disabled="v.label == 0 || v.label == 100">删除</button> </dd> <dd > <button @click="messageStatus = !messageStatus" style="color:#0000ff;">点我</button>添加更多颜色 </dd> <dd v-if="messageStatus" style="border:1px solid #333;width:60%;padding:10px;"> <div> <label for="">位置</label> <input type="number" id="" style="width:50px" v-model="addData.label" min="0" max="100">% </div> <div> <label for="">颜色</label> <input type="color" name="" id="" v-model="addData.value"> </div> <button @click="addColor">添加</button> </dd> </dl> <div v-else> <label for="">填充色</label> <input type="color" name="" id="" v-model="fill_.fillColor.value"> </div> </div> </div> </li> </ul> </div> <!-- 预览区 --> <div class="content_right"> <svg style="position:absolute;margin:auto;left:0;right:0;left:0;bottom:0;top:0;" width="200" height="200" viewBox="0 0 200 200" > <linearGradient id="linearRow_dialog" x1="0%" y1="0%" x2="0%" y2="100%" > <stop v-for="(itm,idx) in fill_.fillGradientColorGroup.value" :key="idx" :offset="itm.label +'%'" :stop-color="itm.value" :stop-opacity="fill_.fillOpacity.value" /> </linearGradient> <linearGradient id="linearCol_dialog" x1="0%" y1="0%" x2="100%" y2="0%" > <stop v-for="(itm,idx) in fill_.fillGradientColorGroup.value" :key="idx" :offset="itm.label +'%'" :stop-color="itm.value" :stop-opacity="fill_.fillOpacity.value" /> </linearGradient> <radialGradient id="radial_dialog" fx="50%" fy="50%" cx="50%" cy="50%" r="50%"> <stop v-for="(itm,idx) in fill_.fillGradientColorGroup.value" :key="idx" :offset="itm.label +'%'" :stop-color="itm.value" :stop-opacity="fill_.fillOpacity.value" /> </radialGradient> <ellipse cx="100" cy="100" rx="100" ry="100" :style="`fill:${fill_.fillGradientColor.value =='color' ? fill_.fillColor.value : 'url('+fill_.fillGradientColor.value+'_dialog'+')'}`" stroke="#333333" stroke-width='1' /> </svg> </div> </div> <div class="btn-group"> <div class="btn-default btn" @click="cancel">取消</div> <div class="btn-primary btn" @click="confirm">确定</div> </div> </div> </div> </template> <script> export default { props:{ fill:{ type:Object, default:() => ({}) }, }, data () { let fill_ = JSON.parse(JSON.stringify(this.fill)) fill_.fillOpacity.range = [0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1] return { fill_:fill_, messageStatus:true, addData:{ label:"", value:"#000000" }, gradientStatus:true } }, mounted () { this.messageStatus = false } , methods: { addColor () { let status = true for (let index = 0; index < this.fill_.fillGradientColorGroup.value.length; index++) { if(this.fill_.fillGradientColorGroup.value[index].label == this.addData.label ) { status = false } } if (status && this.addData.label && this.addData.value && this.addData.label < 100 && this.addData.label > 0) { this.fill_.fillGradientColorGroup.value.push(JSON.parse(JSON.stringify(this.addData))) this.fill_.fillGradientColorGroup.value = this.fill_.fillGradientColorGroup.value.sort((a,b) => a.label - b.label) } else { if (!status) { alert("位置已存在") }else if (!this.addData.label) { alert("位置未填写") }else if (!this.addData.value) { alert("颜色未填写") }else if (this.addData.label >= 100) { alert("位置不能大于100") }else if (this.addData.label <= 0) { alert("位置不能小于0") } } }, deleteColor (index) { this.fill_.fillGradientColorGroup.value.splice(index,1) }, confirm () { this.resolve(this.fill_); this.remove(); }, cancel () { this.reject('cancel'); this.remove(); }, showFillDialog () { this.promise = new Promise((resolve, reject) => { this.resolve = resolve; this.reject = reject; }); return this.promise; }, remove () { setTimeout(() => this.destroy() ,0); }, destroy() { this.$destroy(); document.body.removeChild(this.$el); } } }; </script> <style lang="less" scoped> @height:160px; @padding-top:60px; .fillDialog { position: fixed; top:0; left:0; bottom:0; right:0; z-index:999999; margin:auto; .mask { width:100%; height:100%; background-color:rgba(0, 0, 0, 0.5) } .fillDialogContent { background-color:rgba(255, 255, 255, 1); overflow: hidden; border-radius:10px; display:flex; flex-direction: column; width:40%; height:60%; position:absolute; top:0; left:0; bottom:0; right:0; margin:auto; .title { text-align:center; width:100%; height:50px; line-height: 50px; font-size:16px; background-color:#6550b1; color:#fff; position: relative; .img{ position:absolute; top:18px;right:18px; cursor:pointer; } } .content { flex:1; padding:10px; width:100%; height:@height; font-size:14px; line-height:30px; display:flex; justify-content: space-around; box-sizing:border-box; .content_left{ box-sizing:border-box; width:70%; height:100%; .ul{ height:100%; overflow-y:auto; .li{ min-height:30px; line-height:30px; .lititle{ display:flex; img{ margin-top:5px; width:20px; height:20px; } span{ flex:1; } } .liContent{ min-height:50px; box-sizing: border-box; padding-left:30px; .liItem{ >label{ width:80px; display:inline-block; text-align:justify; text-align-last: justify; margin-right:20px; } } } } } } .content_right{ box-sizing:border-box; width:30%; height:100%; border:1px solid #333; text-align:center; overflow: hidden; position:relative; } } .btn-group { width:100%; height:50px; line-height:50px; border-top:1px solid #f1f1f1; position: relative; .btn{ position: absolute; top:10px; height:30px; width:50px; line-height:30px; display:inline-block; padding:0 10px; font-size:14px; border-radius:3px; background:rgba(0, 0, 0, 0.3); text-align: center; cursor: pointer; } .btn-default { right:110px; } .btn-primary { right:20px; } .btn:hover{ background-color:salmon; } .btn:active{ background-color:sienna; } } } } </style>
代码 : js 部分
import fillDialogComponent from './index.vue'; const MessageBox = {}; MessageBox.install = function (Vue) { const fillDialog = Vue.extend(fillDialogComponent); let currentFillDialogIstance = null; Vue.prototype.showFillDialog = function(fill) { if (!currentFillDialogIstance) { currentFillDialogIstance = new fillDialog({ propsData:{fill} } ); let msgBoxEl = currentFillDialogIstance.$mount().$el; document.body.appendChild(msgBoxEl); } else { Object.assign(currentFillDialogIstance, {fill}) } return currentFillDialogIstance.showFillDialog() .then(val => { currentFillDialogIstance = null; return Promise.resolve(val); }) .catch(err => { currentFillDialogIstance = null; return Promise.reject(err); }); } }; export default MessageBox;
代码 : main.js 部分
import FillDialog from "@/dialog/filDialog.js"
Vue.use(FillDialog)
然后就可以vm.showFillDialog()调用
其中遇到一个坑找了两三个小时才找到 (也不算是坑 主要是对SVG不太熟悉,记录一下)
svg标签内 linearGradient、radialGradient在通过id绑定ellipse fill的url地址时 会被全局编辑(就是id选择器在全局中只能有一个,当出现多个有linearGradient、radialGradient的svg标签(或者组件在多个地方调用)的时候一个定要注意选择器的重复命名问题,
如果出现重复命名问题后果就是修改数据后视图不会实时更新等后果,很难锁定错误,我本人找两三小时,其实是一个小问题,还是修炼不够啊,继续努力)
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· dotnet 源代码生成器分析器入门
· ASP.NET Core 模型验证消息的本地化新姿势
· 对象命名为何需要避免'-er'和'-or'后缀
· SQL Server如何跟踪自动统计信息更新?
· AI与.NET技术实操系列:使用Catalyst进行自然语言处理
· dotnet 源代码生成器分析器入门
· 官方的 MCP C# SDK:csharp-sdk
· 一款 .NET 开源、功能强大的远程连接管理工具,支持 RDP、VNC、SSH 等多种主流协议!
· 一步一步教你部署ktransformers,大内存单显卡用上Deepseek-R1
· 一次Java后端服务间歇性响应慢的问题排查记录