需求是一个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标签(或者组件在多个地方调用)的时候一个定要注意选择器的重复命名问题,
如果出现重复命名问题后果就是修改数据后视图不会实时更新等后果,很难锁定错误,我本人找两三小时,其实是一个小问题,还是修炼不够啊,继续努力)
浙公网安备 33010602011771号