提交 3662b71a authored 作者: matian's avatar matian

Merge remote-tracking branch 'origin/master'

<template>
<div class="edit-style-box">
<div class="title">{{ title }}</div>
<div class="f-type">
<div class="tit">{{ subTitle }}</div>
<div :class="returnData.show === false ? 'active btn' : 'btn'" @click="handleDom">
点击{{ returnData.show || returnData.show === undefined ? '创建' : '删除' }}{{ subTitle }}
</div>
<el-input :maxlength="valueMaxLength" v-if="returnData.show === false" style="margin-top: 15px" v-model="returnData.textValue" placeholder="请输入"></el-input>
</div>
<div class="tool-select">
<div v-for="(item, index) in toolList" :key="index">
<div class="tool-item" v-if="item.name === 'fontSize'">
<div class="tit">字体大小</div>
<el-select v-model="item.value" filterable placeholder="请选择">
<el-option v-for="opt in item.option" :key="opt.value" :label="opt.label" :value="opt.value"> </el-option>
</el-select>
</div>
<div class="tool-item" v-if="item.name === 'fontColor'">
<div class="tit">字体颜色</div>
<el-color-picker v-model="item.value"></el-color-picker>
</div>
<div class="tool-item" v-if="item.name === 'fontLineH'">
<div class="tit">字间距</div>
<el-select v-model="item.value" filterable placeholder="请选择">
<el-option v-for="opt in item.option" :key="opt.value" :label="opt.label" :value="opt.value"> </el-option>
</el-select>
</div>
<div class="tool-item" v-if="item.name === 'fontFamily'">
<div class="tit">字体</div>
<el-select v-model="item.value" filterable placeholder="请选择">
<el-option v-for="opt in item.option" :key="opt.value" :label="opt.label" :value="opt.value"> </el-option>
</el-select>
</div>
<div class="tool-item" v-if="item.name === 'borderRadius'">
<div class="tit">圆角</div>
<el-select v-model="item.value" filterable placeholder="请选择">
<el-option v-for="opt in item.option" :key="opt.value" :label="opt.label" :value="opt.value"> </el-option>
</el-select>
</div>
<div class="tool-item" v-if="item.name === 'bgColor'">
<div class="tit">背景颜色</div>
<el-color-picker v-model="item.value"></el-color-picker>
</div>
<div class="tool-item" v-if="item.name === 'fontPosition'">
<div class="tit">位置</div>
<el-select v-model="item.value" filterable placeholder="请选择">
<el-option v-for="opt in item.option" :key="opt.value" :label="opt.label" :value="opt.value"> </el-option>
</el-select>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
// 工具框大标题
title: { type: String },
// 工具框小标题
subTitle: { type: String },
// 共有多少个工具
tool: { type: Array },
// 一组数据的话工具框的下标
toolIndex: { type: Number, default: 0 },
// 输入框最多输入的长度
valueMaxLength: { type: Number, default: 10 }
},
data() {
return {
// 设置样式
toolList: [],
// 最后返回的数据
returnData: {}
}
},
created() {
this.setToolData()
},
methods: {
// 拖拽的dom 通过此方法显示隐藏
handleDom() {
this.returnData.show = this.returnData.show === undefined ? false : !this.returnData.show
const data = Object.assign({ originalData: this.toolList }, this.returnData)
data.toolIndex = this.toolIndex
this.$emit('data', data)
this.$forceUpdate()
},
// 通过父组件传来的tool重组数据渲染
setToolData() {
const data = [
{
name: 'fontSize',
styleName: 'font-size',
value: '12px',
option: this.setOption(12, 30, 2, 'px')
},
{
name: 'fontColor',
styleName: 'color',
value: '#000000'
},
{
name: 'fontLineH',
styleName: 'line-height',
value: '12px',
option: this.setOption(12, 50, 1, 'px')
},
{
name: 'fontFamily',
styleName: 'font-family',
value: 'fangsong',
option: [{ value: 'fangsong', label: 'fangsong' }]
},
{
name: 'borderRadius',
styleName: 'border-radius',
value: '15px',
option: this.setOption(1, 15, 1, 'px')
},
{
name: 'bgColor',
styleName: 'background',
value: '#000000'
},
{
name: 'fontPosition',
styleName: 'background-color',
value: 'center',
option: [
{ value: 'center', label: '居中' },
{ value: 'left', label: '居左' },
{ value: 'right', label: '居右' }
]
}
]
this.toolList = this.tool.reduce((a, b) => {
const item = data.find(i => i.name === b.name)
item && a.push(Object.assign(item, b))
return a
}, [])
},
// 重新组合对象变成父组件需要的
setStyleData() {
this.returnData.style = this.toolList
.reduce((a, b) => {
a.push(`${b.styleName}: ${b.value};`)
return a
}, [])
.join().replace(/,/g, '')
},
// 设置option值
setOption(min, max, count, symbol = '') {
const options = []
for (let i = min; i <= max; i += count) {
options.push({ value: `${i}${symbol}`, label: `${i}${symbol}` })
}
return options
}
},
computed: {
toolListWat() {
return this.toolList // 深拷贝需要监听的对象数据
},
returnDataWat() {
return this.returnData // 深拷贝需要监听的对象数据
}
},
watch: {
// 工具框改变的时候就告诉父组件
toolListWat: {
deep: true,
handler() {
this.setStyleData()
const data = Object.assign({ originalData: this.toolList }, this.returnData)
data.toolIndex = this.toolIndex
this.$emit('data', data)
}
},
returnDataWat: {
deep: true,
handler() {
this.setStyleData()
const data = Object.assign({ originalData: this.toolList }, this.returnData)
data.toolIndex = this.toolIndex
this.$emit('data', data)
}
}
}
}
</script>
<style lang="scss" scoped>
.edit-style-box {
width: 320px;
padding: 22px 23px 0;
background: rgba(248, 248, 248, 0.39);
border-radius: 16px;
margin-bottom: 60px;
position: relative;
&::before {
content: '';
width: 100%;
position: absolute;
bottom: -30px;
left: 0;
border-bottom: 1px solid #e3e3e3;
}
.title {
text-align: center;
font-size: 18px;
font-weight: bold;
line-height: 11px;
color: #333333;
}
.f-type {
padding-top: 21px;
.tit {
font-size: 14px;
line-height: 100%;
color: #333333;
}
.btn {
text-align: center;
line-height: 34px;
background: rgba(73, 187, 162, 1);
border-radius: 6px;
font-size: 14px;
color: #fff;
margin-top: 8px;
border: 1px solid rgba(73, 187, 162, 1);
cursor: pointer;
&.active {
background: rgba(237, 245, 243, 0.39);
border: 1px solid #80d6c4;
border-radius: 6px;
color: #49bba2;
}
}
}
.tool-select {
display: flex;
padding-top: 15px;
justify-content: space-between;
flex-wrap: wrap;
.tool-item {
// min-width: 127px;
width: 127px;
margin-bottom: 20px;
// margin-right: 20px;
.tit {
font-size: 14px;
line-height: 100%;
color: #333333;
margin-bottom: 8px;
}
}
::v-deep {
.el-input__inner {
text-align: center;
}
.el-color-picker__trigger {
width: 127px;
.el-color-picker__color {
border-radius: 0;
}
.el-color-picker__icon {
opacity: 0;
}
}
}
}
}
</style>
<template>
<div class="mail-three-box">
<div class="content-left">
<edit-style v-for="(item, index) in toolList" :key="index" v-bind="item" @data="setTitleData" :toolIndex="index"></edit-style>
<div class="upload-img">
<div class="btn">上传图片</div>
<UploadImage class="upload" style="width:50px" v-model="imgParams.url" @input="uploadImg"></UploadImage>
</div>
</div>
<div class="content-right">
<div class="card-dom" id="max">
<div id="title" v-show="titleParams.show == false" :style="titleParams.style" class="title">{{ titleParams.textValue || '请输入' }}</div>
<div id="describe" v-show="describeParams.show == false" :style="describeParams.style" class="describe">{{ describeParams.textValue || '请输入' }}</div>
<div id="btn" v-show="btnParams.show == false" :style="btnParams.style" class="btn">{{ btnParams.textValue || '请输入' }}</div>
<div v-if="imgParams.url" id="uploadImg" :style="`background:url(${imgParams.url});background-size:cover;`" class="img" />
</div>
<!-- <div @click="makePreview">点击生成预览</div> -->
</div>
</div>
</template>
<script>
import UploadImage from '@/components/upload/UploadImage.vue'
import drag from '@/utils/drag.js'
import EditStyle from '@/components/base/EditStyle.vue'
export default {
components: { EditStyle, UploadImage },
data() {
return {
imgParams: { url: '' },
titleParams: {},
describeParams: {},
btnParams: {},
textarea1: '',
toolList: [
{
title: '邮件标题',
subTitle: '标题栏',
tool: [
{ name: 'fontSize', value: '20px' },
{ name: 'fontColor', value: '#232325' },
{ name: 'fontLineH', value: '20px' },
{ name: 'fontFamily' }
]
},
{
title: '邮件内容',
subTitle: '内容栏',
tool: [
{ name: 'fontSize', value: '14px' },
{ name: 'fontColor', value: '#999999' },
{ name: 'fontLineH', value: '20px' },
{ name: 'fontFamily' }
],
valueMaxLength: 50
},
{
title: '按钮',
subTitle: '按钮',
tool: [
{ name: 'borderRadius', value: '15px' },
{ name: 'bgColor', value: '#49BBA2' },
{ name: 'fontSize', value: '12px' },
{ name: 'fontColor', value: '#fff' },
{ name: 'fontLineH', value: '20px' },
{ name: 'fontPosition' }
]
}
]
// tool: ['fontSize', 'fontColor', 'fontLineH', 'fontFamily', 'borderRadius', 'bgColor', 'fontPosition']
}
},
mounted() {
},
methods: {
makePreview() {
const params = {
titleParams: this.titleParams,
imgParams: this.imgParams,
describeParams: this.describeParams,
btnParams: this.btnParams
}
console.log(params)
},
uploadImg() {
this.$nextTick(() => {
console.log(111, 222)
drag(document.querySelector('#uploadImg'), document.querySelector('#max'), function(res) {
this.imgParams.position = res
})
})
},
setTitleData(data) {
switch (data.toolIndex) {
case 0:
this.titleParams = data
this.$nextTick(() => {
drag(document.querySelector('#title'), document.querySelector('#max'), res => {
this.titleParams.position = res
})
})
break
case 1:
this.describeParams = data
this.$nextTick(() => {
drag(document.querySelector('#describe'), document.querySelector('#max'), res => {
this.describeParams.position = res
})
})
break
case 2:
this.btnParams = data
this.$nextTick(() => {
drag(document.querySelector('#btn'), document.querySelector('#max'), res => {
this.btnParams.position = res
})
})
break
}
console.log(data)
}
}
}
</script>
<style lang="scss" scoped>
.mail-three-box {
display: flex;
.content-left {
border-left: 1px solid #dedede;
border-right: 1px solid #dedede;
padding: 30px 30px 0;
.upload-img{
position: relative;
.btn{
width: 321px;
height: 40px;
background: rgba(237, 245, 243, 0.39);
border: 1px solid #80D6C4;
border-radius: 8px;
font-size: 14px;
line-height: 40px;
color: #49BBA2;
cursor: pointer;
text-align: center;
}
.upload{
position: absolute;
top:0;
left:0;
opacity: 0.00001;
::v-deep{
.el-upload{
width: 320px;
height: 40px;
}
}
}
}
}
.content-right {
width: 588px;
padding-top: 95px;
box-sizing: border-box;
.card-dom {
width: 431px;
height: 238px;
margin: 0 auto;
background: rgba(255, 255, 255, 0.39);
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.12);
position: relative;
.title {
width: 140px;
position: absolute;
top: 50px;
left: 30px;
font-size: 20px;
font-weight: bold;
color: #232325;
cursor: pointer;
}
.describe {
width: 140px;
position: absolute;
top: 80px;
left: 30px;
font-size: 14px;
color: #999999;
cursor: pointer;
}
.btn {
position: absolute;
top: 170px;
left: 30px;
padding: 5px 20px;
font-size: 12px;
background: rgba(73, 187, 162, 1);
border-radius: 13px;
color: #fff;
cursor: pointer;
}
.img {
width: 220px;
height: 190px;
position: absolute;
top: 30px;
left: 200px;
}
}
}
}
</style>
......@@ -19,6 +19,7 @@
@getTime="getTime"
ref="mailStepTwo"
/>
<MailStepThree v-if="activeStep === 2"/>
<div class="main_content_btn">
<div class="step_prev step_btn" @click="handlePrev" v-if="activeStep > 0">上一步</div>
<div class="step_next step_btn" @click="handleNext" v-if="activeStep >= 0 && activeStep < 2">下一步</div>
......@@ -38,12 +39,14 @@ import ToolCard from '@/components/base/ToolCard.vue'
import MailStepOne from '../components/mail/MailStepOne.vue'
import Step from '@/components/base/Step.vue'
import MailStepTwo from '../components/mail/MailStepTwo.vue'
import MailStepThree from '../components/mail/MailStepThree.vue'
export default {
components: {
ToolCard,
MailStepOne,
Step,
MailStepTwo
MailStepTwo,
MailStepThree
},
data() {
return {
......
export default function dragFun(dragBox, binding, call) {
dragBox.onmousedown = eDown => {
// 算出鼠标相对元素的位置
const disX = eDown.clientX - dragBox.offsetLeft
const disY = eDown.clientY - dragBox.offsetTop
let getPosition = {}
let isMove = false
document.onmousemove = e => {
// 用鼠标的位置减去鼠标相对元素的位置,得到元素的位置
const left = e.clientX - disX
const top = e.clientY - disY
const right = binding.clientWidth - dragBox.clientWidth
const bottom = binding.clientHeight - dragBox.clientHeight
if (left < 0 || top < 0 || right < left || bottom < top) {
return
}
dragBox.style.left = left + 'px'
dragBox.style.top = top + 'px'
getPosition = {
top: top,
left: left
}
isMove = true
}
document.onmouseup = () => {
// 鼠标弹起来的时候不再移动
document.onmousemove = null
// 预防鼠标弹起来后还会循环(即预防鼠标放上去的时候还会移动)
document.onmouseup = null
if (isMove) {
isMove = false
call(getPosition)
}
}
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论