最近花時間弄了一個動態配置小程序頁面的功能css
主要分配置端和渲染端(參考螢火商城後臺配置小程序)vue
1.先設計出頁面有哪些展現類組件git
2.設計組件樣式小程序
3.抽取可以動態變化的配置參數bash
4.開發頁面組件把每一個動能組件分類編寫樣式獨立文件 方便後期維護(目前我這裏是寫在一塊兒的)async
5.小程序端 相應的寫出對應的組件參數配置模式防止組件不能渲染ide
icon 使用的是阿里矢量圖工具
https://www.iconfont.cn/
複製代碼
1.整理組件列表post
2.配置點擊組件默認數據flex
<template>
<div class="my-menu">
<div class="menu-title">
<span>組件庫</span>
</div>
<div class="navs">
<div class="navs-group">
<template v-for="g in navs">
<div class="title" :key="g.type">
{{g.title}}
</div>
<div class="navs-components am-cf" :key="g.title">
<div class="special" @click="addcomponent(item)" v-for="item in g.item" :key="item.type">
<p class="item-icon">
<i class="iconfont" :class="[item.icon]" style="font-size: 1.8rem;"></i>
</p>
<p>
{{item.name}}
</p>
</div>
</div>
</template>
</div>
</div>
<div class="action">
<el-button type="primary" @click="save">保存頁面</el-button>
</div>
</div>
</template>
<script>
export default {
name: '',
data() {
return {
navs: [
{
title: '媒體組件',
type: 'mt',
item: [
{
type: 'banner',
icon: 'icontupianlunbo',
name: '圖片輪播',
},
{
type: 'imageSingle',
icon: 'icontupian',
name: '單組圖片',
},
{
type: 'video',
icon: 'iconshipin',
name: '視頻組',
},
{
type: 'article',
icon: 'iconwenzhang',
name: '文章組',
},
{
type: 'special',
icon: 'icontoutiao',
name: '頭條快報',
},
],
},
{
title: '業務組件',
type: 'yw',
item: [
{
type: 'search',
icon: 'iconsearch',
name: '搜索框',
},
{
type: 'notice',
icon: 'icondvt-notice',
name: '公告組',
},
{
type: 'navBar',
icon: 'icondaohangzu',
name: '導航組',
},
],
},
{
title: '工具組件',
type: 'gj',
item: [
{
type: 'service',
icon: 'iconzaixiankefu',
name: '在線客服',
},
{
type: 'officialAccount',
icon: 'iconguanzhugongzhonghao',
name: '關注公衆號',
},
{
type: 'richText',
icon: 'iconfuwenben',
name: '富文本',
},
{
type: 'blank',
icon: 'iconkongbai',
name: '輔助空白',
},
{
type: 'guide',
icon: 'iconfengexian',
name: '輔助線',
},
],
},
],
defaultimgurl: '',
defaultimgurl1: '',
defaultserviceurl: '',
defaultnoticeurl: '',
}
},
components: {},
created() {},
methods: {
async save() {
this.$emit('save')
},
addcomponent(val) {
let item = {}
if (val.type == 'banner') {
item = {
name: val.name,
type: 'banner',
style: {
height: 200,
backgroundTpye: 'all',
background: '',
},
params: {
interval: 2800,
},
data: [
{
linkUrl: '',
imgUrl: this.defaultimgurl,
},
{
linkUrl: '',
imgUrl: this.defaultimgurl,
},
],
}
}
if (val.type == 'imageSingle') {
item = {
name: val.name,
type: 'imageSingle',
style: {
paddingTop: 0,
paddingLeft: 0,
background: '#ffffff',
height: 200,
},
data: [
{
linkUrl: '',
imgUrl: this.defaultimgurl,
},
{
linkUrl: '',
imgUrl: this.defaultimgurl,
},
],
}
}
if (val.type == 'video') {
item = {
name: val.name,
type: 'video',
style: {
paddingTop: 0,
height: 200,
},
params: {
videoUrl: '',
poster: this.defaultimgurl,
autoplay: '0',
},
}
}
if (val.type == 'navBar') {
item = {
name: val.name,
type: val.type,
style: {
background: '',
rowsNum: 4,
marginLeft: 0,
paddingTop: 0,
},
params: {
title: '標題內容',
visible: 1,
color: '#666666',
textAlign: 'center',
},
data: [
{
imgUrl: this.defaultimgurl,
linkUrl: '',
text: '按鈕文字1',
color: '#666666',
},
{
imgUrl: this.defaultimgurl,
linkUrl: '',
text: '按鈕文字2',
color: '#666666',
},
{
imgUrl: this.defaultimgurl,
linkUrl: '',
text: '按鈕文字3',
color: '#666666',
},
{
imgUrl: this.defaultimgurl,
linkUrl: '',
text: '按鈕文字4',
color: '#666666',
},
],
}
}
if (val.type == 'article') {
item = {
name: '文章組',
type: 'article',
params: {
source: 'auto',
auto: {
category: 0,
showNum: 6,
},
},
style: [],
defaultData: [
{
article_title: '此處顯示文章標題',
article_cont: '這是文章的內容',
show_type: 10,
image: this.defaultimgurl,
date: '2020-05-10 12:00',
},
{
article_title: '此處顯示文章標題',
show_type: 10,
article_cont: '這是文章的內容',
image: this.defaultimgurl,
date: '2020-05-10 12:00',
},
],
data: [],
}
}
if (val.type == 'special') {
item = {
name: '頭條快報',
type: 'special',
params: {
source: 'auto',
auto: {
category: 0,
showNum: 6,
},
},
style: {
display: '1',
image: this.defaultimgurl1,
},
defaultData: [
{
article_title: '頭條內容。。。',
},
{
article_title: '頭條內容。。。',
},
],
data: [],
}
}
if (val.type == 'blank') {
item = {
name: '輔助空白',
type: 'blank',
style: {
height: 20,
background: '#ffffff',
},
}
}
if (val.type == 'guide') {
item = {
name: '輔助線',
type: 'guide',
style: {
background: '#ffffff',
lineStyle: 'solid',
lineHeight: 1,
lineColor: '#000000',
paddingTop: 10,
},
}
}
if (val.type == 'service') {
item = {
name: '在線客服',
type: 'service',
params: {
type: 'chat',
image: this.defaultserviceurl,
phone_num: '',
},
style: {
right: 1,
bottom: 10,
opacity: 100,
},
}
}
if (val.type == 'notice') {
item = {
name: '公告組',
type: 'notice',
params: {
text: '這裏是第一條自定義公告的標題',
icon: this.defaultnoticeurl,
},
style: {
paddingTop: '4',
background: '#ffffff',
textColor: '#000000',
},
}
}
if (val.type == 'search') {
item = {
name: '搜索框',
type: 'search',
params: {
placeholder: '請輸入關鍵字進行搜索',
},
style: {
textAlign: 'left',
searchStyle: 'square',
},
}
}
if (val.type == 'richText') {
item = {
name: '富文本',
type: 'richText',
params: {
content: '<p>這裏是文本的內容</p>',
},
style: {
paddingTop: '0',
paddingLeft: '0',
background: '#ffffff',
},
}
}
this.$emit('add', item)
},
},
}
</script>
<style lang="scss" scoped>
.my-menu {
width: 285px;
height: auto;
background: #fdfdfd;
border: 1px solid #ddd;
padding: 15px 10px;
transition: all 0.3s;
user-select: none;
.menu-title {
position: relative;
padding: 0 22px;
height: 30px;
border-bottom: 1px solid #eef1f5;
line-height: 30px;
&:before {
content: '';
position: absolute;
width: 4px;
height: 13px;
background: #00aeff;
top: 8px;
left: 9px;
}
}
.navs {
padding: 10px 5px;
border-bottom: 1px dotted #ddd;
position: relative;
display: flex;
.navs-group {
.title {
// font-size: 1.24rem;
color: #999;
margin: 10px 0;
}
.navs-components {
.special {
width: 74px;
float: left;
padding: 3px 0;
margin: 5px;
border: 1px solid #dddddd;
text-align: center;
font-size: 12px;
cursor: pointer;
transition: All 0.3s ease-in-out;
background: #f4f4f4;
p {
color: #424242;
}
}
}
}
}
.action {
margin-top: 15px;
text-align: right;
position: relative;
}
}
.am-cf:after {
clear: both;
}
.am-cf:after,
.am-cf:before {
content: ' ';
display: table;
}
</style>
複製代碼
1.根據默認參數渲染組件
<template>
<div class="my-phone">
<div class="phone-top optional" :style="{backgroundColor: pages.page.style.titleBackgroundColor}" @click="changitem(pages.page,-1)" :class="{'selected':selectitem.type=='page'}">
<h4 :style="{color: pages.page.style.titleTextColor}">{{pages.page.params.title}}</h4>
</div>
<div class="phone-main">
<div class="dragArea" :style="{background:pages.page.style.pageBackgroundColor}">
<draggable v-model="pages.items" @start="dragstart" @end="dragend">
<template v-for="(item,index) in pages.items">
<div v-if="item.type!='service'" :key="index" @click="changitem(item,index)" class="drag optional" :class="{selected:selectindex==index}">
<div v-if="item.type=='banner'" class="my-banner" :style="{paddingBottom:item.style.paddingTop+'px',backgroundColor:item.style.background}">
<img v-for="(img,imgindex) in item.data" :key="'banner'+imgindex" :src="img.imgUrl" :style="{padding:item.style.paddingTop+'px '+item.style.paddingLeft+'px 0px',}">
</div>
<div v-if="item.type=='imageSingle'" class="my-imageSingle" :style="{paddingBottom:item.style.paddingTop+'px',background:item.style.background}">
<div class="item-image" v-for="(img,imgindex) in item.data" :key="'imageSingle'+imgindex" :style="{padding:item.style.paddingTop+'px '+item.style.paddingLeft+'px 0px',}">
<img :src="img.imgUrl">
</div>
</div>
<div v-if="item.type=='video'" class="my-video" :style="{padding:item.style.paddingTop+'px 0px',}">
<video :src="item.params.videoUrl" :poster="item.params.poster" controls="controls" :style="{height:item.style.height+'px'}"></video>
</div>
<div v-if="item.type=='navBar'" class="my-navBar" :style="{background:item.style.background,margin:'0px '+item.style.marginLeft+'px'}" style="border-radius: 3px;">
<p class="item-text am-text-truncate" v-if="item.params.visible" :style="{color:item.params.color,textAlign:item.params.textAlign}">
{{item.params.title}}
</p>
<ul :class="['am-avg-sm-'+item.style.rowsNum]">
<li v-for="(item,index) in item.data" :key="'navBar'+index" class="my-navBar-li">
<div class="item-image">
<img :src="item.imgUrl">
</div>
<p class="item-text am-text-truncate" :style="{color:item.color}">
{{item.text}}
</p>
</li>
</ul>
</div>
<div v-if="item.type=='article'" class="my-article">
<div class="article-item" v-for="(item,index) in item.defaultData" :key="index">
<div class="article-item__image">
<img :src="item.image">
</div>
<div class="article-item__right">
<div class="article-item__title twolist-hidden">
{{item.article_title}}
</div>
<div class="article-item__coont">
{{item.article_cont}}
</div>
<div class="article-item__footer">
{{item.date}}
</div>
</div>
</div>
</div>
<div v-if="item.type=='special'" class="my-special">
</div>
<div v-if="item.type=='search'" class="my-search">
</div>
<div v-if="item.type=='notice'" class="my-notice" :style="{padding:item.style.paddingTop+'px 10px',background:item.style.background}">
<div class="notice__icon">
<img :src="item.params.icon">
</div>
<div class="notice__text">
<span :style="{color:item.style.textColor}">{{item.params.text}}</span>
</div>
</div>
<div v-if="item.type=='guide'" class="my-guide" :style="{padding:item.style.paddingTop+'px 0px',background:item.style.background}">
<p class="line" :style="{borderTop:item.style.lineHeight+'px '+item.style.lineStyle+' '+item.style.lineColor}"></p>
</div>
<div v-if="item.type=='blank'" class="my-blank" :style="{height:item.style.height+'px',background:item.style.background}">
</div>
<div class="btn-edit-del" v-if="item.type!='service'">
<div class="btn-edit-del" @click.stop="delitem(item,index)">
刪除
</div>
</div>
</div>
<div v-if="item.type=='service'" @click="changitem(item,index)" class="my-service drag optional " :class="{selected:selectindex==index}" :style="{right:item.style.right+'%',bottom:item.style.bottom+'%',opacity:item.style.opacity/100}" :key="index">
<div class="service-icon">
<img :src="item.params.image">
</div>
<div class="btn-edit-del">
<div class="btn-edit-del" @click.stop="delitem(item,index)">
刪除
</div>
</div>
</div>
</template>
</draggable>
</div>
</div>
</div>
</template>
<script>
import draggable from 'vuedraggable'
export default {
name: '',
model: {
prop: 'pages',
},
props: {
pages: {
type: [Array, Object],
default() {
return {
page: {
type: 'page',
name: '頁面設置',
params: {
title: '',
share_title: '',
},
style: {
titleTextColor: '',
titleBackgroundColor: '',
pageBackgroundColor: '',
},
},
items: [],
}
},
},
},
data() {
return {
selected: '',
selectindex: -1,
selectitem: {
type: '',
},
}
},
components: {
draggable,
},
created() {},
methods: {
//選中模塊
changitem(val, index) {
this.selectitem = val
this.selectindex = index
this.chang()
},
dragstart(evt) {
this.selectindex = evt.oldIndex
this.chang()
},
dragend(evt) {
this.selectindex = evt.newIndex
this.chang()
},
delitem(item, index) {
this.$confirm('確認刪除嗎?', '提示', {
confirmButtonText: '肯定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
this.pages.items.splice(index, 1)
this.selected = ''
this.$emit('modulechang', { type: '' })
})
.catch(() => {})
},
chang() {
this.$emit('modulechang', this.selectitem)
},
},
}
</script>
<style lang="scss" scoped>
.my-phone {
width: 377px;
border-radius: 3px;
box-shadow: 0 3px 10px #dcdcdc;
border: 1px solid #ddd;
.phone-top {
width: 100%;
height: 66px;
text-align: center;
background: url('../../assets/phone-top-black.png') center center / contain
no-repeat;
h4 {
margin: 0;
font-size: 1.4rem;
font-weight: normal;
white-space: nowrap;
line-height: 88px;
}
}
.optional {
position: relative;
&:before {
content: ' ';
}
}
.optional:hover:before {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 2px dashed #00a0e9;
cursor: move;
}
.optional.selected:before {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 2px dashed #00a0e9;
cursor: move;
}
.phone-main {
position: relative;
border-top: 0;
user-select: none;
line-height: normal;
.my-service {
position: absolute;
z-index: 999;
.service-icon {
padding: 5px;
img {
display: block;
width: 45px;
height: 45px;
}
}
}
.dragArea {
overflow-y: auto;
height: 580px;
.drag {
&:hover {
.btn-edit-del {
display: block;
}
}
.btn-edit-del {
height: 16px;
position: absolute;
right: 2px;
bottom: 2px;
display: none;
z-index: 90;
> div {
width: 32px;
height: 16px;
line-height: 16px;
display: inline-block;
text-align: center;
font-size: 10px;
color: #fff;
background: rgba(0, 0, 0, 0.4);
margin-left: 2px;
cursor: pointer;
position: relative;
z-index: 11;
}
}
.my-banner {
display: block;
margin: 0;
padding: 0;
height: auto;
overflow: hidden;
img {
width: 100%;
display: none;
}
img:first-child {
display: block;
}
}
.my-imageSingle {
display: block;
margin: 0;
padding: 0;
height: auto;
overflow: hidden;
img {
width: 100%;
display: block;
}
}
.my-video {
video {
display: block;
width: 100%;
height: 100%;
}
}
.my-article {
background: #f7f7f7;
.article-item {
display: flex;
margin-bottom: 10px;
padding: 15px;
background: #fff;
.article-item__right {
padding-left: 10px;
.article-item__title {
min-height: 30px;
text-overflow: ellipsis;
overflow: hidden;
}
.article-item__coont {
min-height: 30px;
text-overflow: ellipsis;
overflow: hidden;
}
.item__footer {
margin-top: 5px;
}
}
.article-item__image img {
display: block;
width: 120px;
}
}
}
.my-notice {
padding: 4px 10px;
line-height: 26px;
display: flex;
.notice__icon {
font-size: 0;
img {
width: 16px;
height: 16px;
vertical-align: middle;
border: 0;
}
}
.notice__text {
padding-left: 5px;
flex: 1;
word-wrap: normal;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
}
.my-guide {
.line {
height: 0;
width: 100%;
margin: 0;
}
}
.my-blank {
}
}
.selected {
.btn-edit-del {
display: block;
}
}
.my-navBar {
.my-navBar-li {
margin: 10px 0;
.item-text {
text-align: center;
}
.item-image {
text-align: center;
margin-bottom: 4px;
img {
height: 44px;
width: 44px;
}
}
}
ul,
li {
list-style: none;
padding: 0;
margin: 0;
}
}
}
}
}
.am-ellipsis,
.am-text-truncate {
word-wrap: normal;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.am-avg-sm-3 > li:nth-of-type(3n + 1) {
clear: both;
}
.am-avg-sm-3 > li:nth-of-type(n) {
clear: none;
}
.am-avg-sm-3 > li {
width: 33.33333333%;
}
.am-avg-sm-4 > li:nth-of-type(4n + 1) {
clear: both;
}
.am-avg-sm-4 > li:nth-of-type(n) {
clear: none;
}
.am-avg-sm-4 > li {
width: 25%;
}
.am-avg-sm-5 > li:nth-of-type(5n + 1) {
clear: both;
}
.am-avg-sm-5 > li:nth-of-type(n) {
clear: none;
}
.am-avg-sm-5 > li {
width: 20%;
}
[class*='am-avg-'] > li {
display: block;
height: auto;
float: left;
}
[class*='am-avg-']:after,
[class*='am-avg-']:before {
content: ' ';
display: table;
}
[class*='am-avg-']:after {
clear: both;
}
[class*='am-avg-']:after,
[class*='am-avg-']:before {
content: ' ';
display: table;
}
[class*='am-avg-'] {
display: block;
padding: 0;
margin: 0;
list-style: none;
}
</style>
複製代碼
1.配置組件參數
<template>
<div class="my-editor form-horizontal" v-show="data.type">
<!-- 頁面設置 -->
<template v-if="data.type=='page'">
<div class="editor-title">
頁面設置
</div>
<el-form label-width="100px" size="mini">
<el-form-item label="頁面標題">
<el-input v-model="data.params.title"></el-input>
<span class="help-block">小程序端頂部顯示的標題</span>
</el-form-item>
<el-form-item label="分享標題">
<el-input v-model="data.params.share_title"></el-input>
<span class="help-block">小程序端轉發時顯示的標題</span>
</el-form-item>
<el-form-item label="標題欄文字">
<el-radio-group v-model="data.style.titleTextColor">
<el-radio label="black">黑色</el-radio>
<el-radio label="white">白色</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="標題欄背景">
<el-color-picker v-model="data.style.titleBackgroundColor"></el-color-picker>
</el-form-item>
<el-form-item label="頁面背景">
<el-color-picker v-model="data.style.pageBackgroundColor"></el-color-picker>
</el-form-item>
</el-form>
</template>
<!-- 圖片輪播 -->
<template v-if="data.type=='banner'">
<div class="editor-title">
圖片輪播
</div>
<el-form label-width="100px" size="mini">
<el-form-item label="切換時間">
<el-input-number v-model="data.params.interval" controls-position="right" :min="1000" style="width:100%"></el-input-number>
<span class="help-block">輪播圖自動切換的間隔時間,單位:毫秒</span>
</el-form-item>
<el-form-item label="上下邊距">
<el-slider v-model="data.style.paddingTop" :min="0" :max="50"></el-slider>{{data.style.paddingTop}}px(像素)
</el-form-item>
<el-form-item label="左右邊距">
<el-slider v-model="data.style.paddingLeft" :min="0" :max="50"></el-slider>{{data.style.paddingLeft}}px(像素)
</el-form-item>
<!-- <el-form-item label="背景顏色模式">
<el-radio-group v-model="data.style.backgroundTpye">
<el-radio label="all">所有填充</el-radio>
<el-radio label="top">上下</el-radio>
</el-radio-group>
</el-form-item> -->
<el-form-item label="背景顏色">
<el-color-picker v-model="data.style.background"></el-color-picker>
</el-form-item>
<div class="form-items">
<div class="form-item" v-for="(img,imgindex) in data.data" :key="'banner'+imgindex">
<i class="el-icon-close item-delete" @click.stop="delimgitem(data.data,imgindex)"></i>
<div class="item-inner">
<el-form-item label="圖片">
<div class="data-image" @click.stop="showfile(imgindex,data.type)">
<img :src="img.imgUrl">
</div>
<span class="help-block">建議尺寸750x360</span>
</el-form-item>
<el-form-item label="連接地址">
<el-input v-model="img.linkUrl"></el-input>
</el-form-item>
</div>
</div>
</div>
<div class="form-item-add" @click.stop="addimgitem(data.data)">
添加一個
</div>
</el-form>
</template>
<!-- 單組圖片 -->
<template v-if="data.type=='imageSingle'">
<div class="editor-title">
單組圖片
</div>
<el-form label-width="100px" size="mini">
<el-form-item label="上下邊距">
<el-slider v-model="data.style.paddingTop" :min="0" :max="50"></el-slider>{{data.style.paddingTop}}px(像素)
</el-form-item>
<el-form-item label="左右邊距">
<el-slider v-model="data.style.paddingLeft" :min="0" :max="50"></el-slider>{{data.style.paddingLeft}}px(像素)
</el-form-item>
<el-form-item label="背景顏色">
<el-color-picker v-model="data.style.background"></el-color-picker>
</el-form-item>
<div class="form-items">
<div class="form-item" v-for="(img,imgindex) in data.data" :key="'banner'+imgindex">
<i class="el-icon-close item-delete" @click.stop="delimgitem(data.data,imgindex)"></i>
<div class="item-inner">
<el-form-item label="圖片">
<div class="data-image" @click.stop="showfile(imgindex,data.type)">
<img :src="img.imgUrl">
</div>
</el-form-item>
<el-form-item label="連接地址">
<el-input v-model="img.linkUrl"></el-input>
</el-form-item>
</div>
</div>
</div>
<div class="form-item-add" @click.stop="addimgitem(data.data)">
添加一個
</div>
</el-form>
</template>
<!-- 視頻組件 -->
<template v-if="data.type=='video'">
<div class="editor-title">
視頻組
</div>
<el-form label-width="100px" size="mini">
<el-form-item label="上下邊距">
<el-slider v-model="data.style.paddingTop" :min="0" :max="50"></el-slider>{{data.style.paddingTop}}px(像素)
</el-form-item>
<el-form-item label="視頻高度">
<el-slider v-model="data.style.height" :min="0" :max="500"></el-slider>{{data.style.height}}px(像素)
</el-form-item>
<el-form-item label="視頻封面">
<div class="data-image" @click.stop="showfile(-1,data.type)">
<img :src="data.params.poster">
</div>
</el-form-item>
<el-form-item label="視頻地址">
<el-input v-model="data.params.videoUrl"></el-input>
</el-form-item>
<el-form-item label="自動播放">
<el-radio-group v-model="data.params.autoplay">
<el-radio label="0">否</el-radio>
<el-radio label="1">是</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
</template>
<!-- 導航組 -->
<template v-if="data.type=='navBar'">
<div class="editor-title">
導航組
</div>
<el-form label-width="100px" size="mini">
<el-form-item label="是否顯示標題">
<el-radio-group v-model="data.params.visible">
<el-radio :label="1">顯示</el-radio>
<el-radio :label="0">隱藏</el-radio>
</el-radio-group>
</el-form-item>
<template v-if="data.params.visible">
<el-form-item label="標題文字">
<el-input v-model="data.params.title"></el-input>
</el-form-item>
<el-form-item label="文字對齊">
<el-radio-group v-model="data.params.textAlign">
<el-radio label="left">顯居左</el-radio>
<el-radio label="center">居中</el-radio>
<el-radio label="right">居右</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="標題文字驗證">
<el-color-picker v-model="data.params.color"></el-color-picker>
</el-form-item>
</template>
<el-form-item label="左右邊距">
<el-slider v-model="data.style.marginLeft" :min="0" :max="50"></el-slider>{{data.style.paddingLeft}}px(像素)
</el-form-item>
<el-form-item label="背景顏色">
<el-color-picker v-model="data.style.background"></el-color-picker>
</el-form-item>
<el-form-item label="每行數量">
<el-radio-group v-model="data.style.rowsNum">
<el-radio :label="3">3</el-radio>
<el-radio :label="4">4</el-radio>
<el-radio :label="5">5</el-radio>
</el-radio-group>
</el-form-item>
<div class="form-items">
<draggable v-model="data.data">
<div class="form-item" v-for="(img,imgindex) in data.data" :key="'banner'+imgindex">
<i class="el-icon-close item-delete" @click.stop="delimgitem(data.data,imgindex)"></i>
<div class="item-inner">
<el-form-item label="圖片">
<div class="data-image" @click.stop="showfile(imgindex,data.type)">
<img :src="img.imgUrl">
</div>
<span class="help-block">建議尺寸100x100</span>
</el-form-item>
<el-form-item label="文字內容">
<el-input v-model="img.text"></el-input>
</el-form-item>
<el-form-item label="文字顏色">
<el-color-picker v-model="img.color"></el-color-picker>
</el-form-item>
<el-form-item label="業務分類">
<SelectTree :props="bprops" :options="business" :data.sync="img.classify" :clearable="true" :accordion="true" height="200" style="width:100%"></SelectTree>
</el-form-item>
<el-form-item label="連接地址">
<el-input v-model="img.linkUrl"></el-input>
</el-form-item>
</div>
</div>
</draggable>
</div>
<div class="form-item-add" @click.stop="addimgitem(data.data)">
添加一個
</div>
</el-form>
</template>
<!-- 文章組 -->
<template v-if="data.type=='article'">
<div class="editor-title">
文章組
</div>
<el-form label-width="100px" size="mini">
<el-form-item label="文章分類">
<SelectTree :props="props" :options="trredata" :data.sync="data.params.auto.category" :clearable="true" :accordion="true" height="200" style="width:100%"></SelectTree>
</el-form-item>
<el-form-item label="顯示數量">
<el-input-number v-model="data.params.auto.showNum" placeholder="請輸入顯示數量" :min="1" controls-position="right" style="width:100%"></el-input-number>
</el-form-item>
</el-form>
</template>
<!-- 公告組 -->
<template v-if="data.type=='notice'">
<div class="editor-title">
公告組
</div>
<el-form label-width="100px" size="mini">
<el-form-item label="上下邊距">
<el-slider v-model="data.style.paddingTop" :min="0" :max="50"></el-slider>{{data.style.paddingTop}}px(像素)
</el-form-item>
<el-form-item label="背景顏色">
<el-color-picker v-model="data.style.background"></el-color-picker>
</el-form-item>
<el-form-item label="文字顏色">
<el-color-picker v-model="data.style.textColor"></el-color-picker>
</el-form-item>
<el-form-item label="公告圖標">
<div class="data-image" @click.stop="showfile(-1,data.type)">
<img :src="data.params.icon" style="height: 30px;">
<span class="help-block">建議尺寸32x32</span>
</div>
</el-form-item>
<el-form-item label="公告內容">
<el-input v-model="data.params.text"></el-input>
</el-form-item>
</el-form>
</template>
<!-- 輔助空白 -->
<template v-if="data.type=='blank'">
<div class="editor-title">
輔助空白
</div>
<el-form label-width="100px" size="mini">
<el-form-item label="組件高度">
<el-slider v-model="data.style.height" :min="0" :max="50"></el-slider>{{data.style.height}}px(像素)
</el-form-item>
<el-form-item label="背景顏色">
<el-color-picker v-model="data.style.background"></el-color-picker>
</el-form-item>
</el-form>
</template>
<!-- 輔助線 -->
<template v-if="data.type=='guide'">
<div class="editor-title">
輔助線
</div>
<el-form label-width="100px" size="mini">
<el-form-item label="背景顏色">
<el-color-picker v-model="data.style.background"></el-color-picker>
</el-form-item>
<el-form-item label="線條樣式">
<el-radio-group v-model="data.style.lineStyle">
<el-radio label="solid">實線</el-radio>
<el-radio label="dashed">虛線</el-radio>
<el-radio label="dotted">點狀</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="線條顏色">
<el-color-picker v-model="data.style.lineColor"></el-color-picker>
</el-form-item>
<el-form-item label="線條高度">
<el-slider v-model="data.style.lineHeight" :min="0" :max="20"></el-slider>{{data.style.lineHeight}}px(像素)
</el-form-item>
<el-form-item label="上下邊距">
<el-slider v-model="data.style.paddingTop" :min="0" :max="50"></el-slider>{{data.style.paddingTop}}px(像素)
</el-form-item>
</el-form>
</template>
<!-- 在線客服 -->
<template v-if="data.type=='service'">
<div class="editor-title">
在線客服
</div>
<el-form label-width="100px" size="mini">
<el-form-item label="底邊距">
<el-slider v-model="data.style.bottom" :min="0" :max="100"></el-slider>{{data.style.height}}%
</el-form-item>
<el-form-item label="右邊距">
<el-slider v-model="data.style.right" :min="0" :max="100"></el-slider>{{data.style.height}}%
</el-form-item>
<el-form-item label="不透明度">
<el-slider v-model="data.style.opacity" :min="0" :max="100"></el-slider>{{data.style.opacity}}%
</el-form-item>
<el-form-item label="線條樣式">
<el-radio-group v-model="data.params.type">
<el-radio label="chat">在線聊天</el-radio>
<el-radio label="phone">撥打電話</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="電話號碼" v-if="data.params.type=='phone'">
<el-input v-model="data.params.phone_num" placeholder="請輸入電話號碼" :maxlength='11' type="tel"></el-input>
</el-form-item>
<el-form-item label="客服圖標">
<div class="data-image" @click.stop="showfile(-1,data.type)">
<img :src="data.params.image" style="height: 30px;">
<span class="help-block">建議尺寸90x90</span>
</div>
</el-form-item>
</el-form>
</template>
<FileLibrary :visible.sync="FileLibraryvisible" @ok="Fileok"></FileLibrary>
</div>
</template>
<script>
import FileLibrary from '../FileLibrary'
import SelectTree from '../treeSelect'
import draggable from 'vuedraggable'
export default {
name: '',
model: {
prop: 'data',
},
props: {
data: {
type: [Object, Array],
default() {
return {
type: '',
}
},
},
},
data() {
return {
dataindex: -1,
FileLibraryvisible: false,
ntype: '',
trredata: [
{
id: 0,
label: '所有分類',
children: [],
},
],
props: {
// 配置項(必選)
value: 'id',
label: 'label',
children: 'children',
// disabled:true
},
bprops: {
// 配置項(必選)
value: 'id',
label: 'name',
children: 'children',
},
business: [],
}
},
components: {
FileLibrary,
SelectTree,
draggable,
},
created() {
},
methods: {
addimgitem(data) {
data.push({
linkUrl: '',
imgUrl: '',
})
},
delimgitem(data, index) {
data.splice(index, 1)
},
showfile(index, type) {
this.FileLibraryvisible = true
this.dataindex = index
this.ntype = type
},
Fileok(val) {
if (val.length != 0) {
switch (this.ntype) {
case 'banner':
case 'imageSingle':
case 'navBar':
this.data.data[this.dataindex].imgUrl = val[0]
break
case 'video':
this.data.params.poster = val[0]
break
case 'notice':
this.data.params.icon = val[0]
break
case 'service':
this.data.params.image = val[0]
break
}
}
},
},
}
</script>
<style lang="scss" scoped>
.my-editor {
width: 400px;
height: auto;
min-height: 100px;
padding: 15px 10px;
border: 1px solid #ddd;
.data-image {
display: inline-block;
width: auto;
min-width: 40px;
max-width: 220px;
text-align: center;
cursor: pointer;
}
.editor-title {
position: relative;
padding: 0 22px;
height: 34px;
border-bottom: 1px solid #eef1f5;
margin-bottom: 20px;
line-height: 34px;
&:before {
content: '';
position: absolute;
width: 4px;
height: 13px;
background: #00aeff;
top: 10px;
left: 9px;
}
}
.tpl-form-line-form {
font-size: 1.3rem !important;
color: #656565;
}
.help-block {
color: #838fa1;
font-size: 12px;
}
.form-items {
height: auto;
padding: 5px 6px;
.form-item {
background: #f7fafc;
margin-bottom: 0.6rem;
position: relative;
border-radius: 3px;
cursor: move;
.item-delete {
position: absolute;
top: -6px;
right: -6px;
height: 16px;
width: 16px;
line-height: 16px;
background: rgba(153, 153, 153, 0.7);
color: #fff;
border-radius: 50%;
text-align: center;
cursor: pointer;
font-size: 12px;
transition: background-color 0.3s ease-out, border-color 0.3s ease-out;
}
.item-inner {
padding: 10px;
background: #f7fafc;
span {
display: block;
width: 100%;
}
}
}
}
.form-item-add {
width: 100%;
background: #fdfdfd;
color: #6b6b6b;
border: 1px solid #efefef;
outline: none;
padding: 10px 16px;
border-radius: 2px;
font-size: 12px;
line-height: 1;
text-align: center;
vertical-align: middle;
cursor: pointer;
user-select: none;
transition: All 0.2s ease-in-out;
}
.data-image {
display: inline-block;
width: auto;
min-width: 40px;
max-width: 220px;
text-align: center;
cursor: pointer;
img {
display: block;
max-width: 100%;
height: 50px;
}
}
}
</style>
複製代碼
<template>
<el-row :gutter="20">
<el-col :span="8">
<LeftPage @save="save" @add="addcomponent"></LeftPage>
</el-col>
<el-col :span="8">
<MainPage :pages="pages" @modulechang="modulechang"></MainPage>
</el-col>
<el-col :span="8">
<RightPage :data="selectitem"></RightPage>
</el-col>
</el-row>
</template>
<script>
import LeftPage from './left'
import MainPage from './main'
import RightPage from './right'
export default {
name: '',
props: {
data: {
type: [Object],
default() {
return {}
},
},
},
data() {
return {
pages: this.data,
selected: '',
selectindex: -1,
selectitem: {
type: '',
},
}
},
components: {
LeftPage,
MainPage,
RightPage,
},
created() {},
watch: {
'data.page.type'() {
this.pages = this.data
},
},
methods: {
modulechang(val) {
this.selectitem = val
},
addcomponent(item) {
this.pages.items.push(item)
},
save() {
this.$emit('save', this.pages)
},
},
}
</script>
<style lang="scss" scoped>
</style>
複製代碼
下期會分享動態配置表單配置