使用vue+elementUI编写运营活动生成工具
2017-06-26 14:40
791 查看
前端切图的对象,很大一部分是公司营销活动类和纯展示类的页面,这一类页面通常有以下特点:
1.页面:切片(cuts的添加和删除)、功能区域(map、area或absolute操作对象)、模块(include的固定代码)、组件(components的调用和配置);
2:组件: 一份代码 + 一份数据,可复用组装。
3.有规则的数据监控和上线配置;
4.实时预览及快速发布上线。
以下为采用vue+elementUI制作运营活动工具的实践。
源码地址: JZ_Activity
活动上线流程:
1.新建活动页面,配置信息(页面标题,生成URL,分享图标及描述)
2.上传切好的各个切片(暂存于临时目录,活动生成后自动删除)
3.进入编辑页后选择组件(如:链接,功能性按钮,表单等等,可以根据需求自行开发),框选组件位置和尺寸
4.生成代码 =>
1)一键上传到服务器(需配置好对应上传目录及权限)
2)下载代码,编写无法用编辑器实现的特定需求后上传(活动代码压缩包);
组件开发流程:
1.新建vue组件.
2.进入活动编辑页
3.添加 - 选择组件 , 框选组件位置和尺寸
实现编辑页功能:
生成数据结构:
代码生成:
点击生成活动时:提交到本地nodejs server,实现以下步骤:
1.新建活动代码目录build;
2.匹配活动模板,拼接HTML字符串,生成至build目录
3.拷贝默认携带的js,images等资源至build目录
4.生成build压缩包或上线代码
5.清空暂存目录
源码地址: JZ_Activity
原文链接:http://www.tliangl.com/article67.aspx
1.页面:切片(cuts的添加和删除)、功能区域(map、area或absolute操作对象)、模块(include的固定代码)、组件(components的调用和配置);
2:组件: 一份代码 + 一份数据,可复用组装。
3.有规则的数据监控和上线配置;
4.实时预览及快速发布上线。
以下为采用vue+elementUI制作运营活动工具的实践。
源码地址: JZ_Activity
活动上线流程:
1.新建活动页面,配置信息(页面标题,生成URL,分享图标及描述)
2.上传切好的各个切片(暂存于临时目录,活动生成后自动删除)
3.进入编辑页后选择组件(如:链接,功能性按钮,表单等等,可以根据需求自行开发),框选组件位置和尺寸
4.生成代码 =>
1)一键上传到服务器(需配置好对应上传目录及权限)
2)下载代码,编写无法用编辑器实现的特定需求后上传(活动代码压缩包);
组件开发流程:
1.新建vue组件.
2.进入活动编辑页
3.添加 - 选择组件 , 框选组件位置和尺寸
实现编辑页功能:
import Vue from 'vue' export default { components: {}, data () { return { defaults:{ width:0,height:0,left:0,top:0, memorySize : true,//记住上一次尺寸 currentCutName:'' }, pageUrl:null,//生成地址 info:{},//活动信息 fileList : [],//切片列表 currentMoveArea : null,//补充未快速响应的移动事件 currentChangeArea : null,//补充未快速响应的移动事件 areaTypeList :[ { name:'组件库', type:2, data:[ { key : 'slider-zhucai' , icon : 'menu' , text : '主材轮播',width:300,height:200}, { key : 'slider-fangan' , icon : 'menu' , text : '整装方案轮播',width:300,height:200}, { key : 'slider-ybj' , icon : 'menu' , text : '样板间轮播',width:300,height:200} ] }, { name:'热区元素', type:3, data:[ { key : 'open-form' , icon : 'view' , text : '弹出表单',width:100,height:50}, { key : 'open-link' , icon : 'view' , text : '超链接',width:200, c680 height:50} ] }, { name:'表单录入', type:3, data:[ { key : 'input-name' , icon : 'edit' , text : '姓名',width:200,height:50}, { key : 'input-telephone' , icon : 'edit' , text : '电话',width:200,height:50}, { key : 'input-mianji' , icon : 'edit' , text : '面积',width:200,height:50}, { key : 'input-text' , icon : 'edit' , text : '文本',width:200,height:50}, { key : 'input-submit' , icon : 'check' , text : '提交',width:200,height:50} ] } ] } }, filters: { imgUrl (name) { return Vue.globalOptions.root + '/static/server/custom/images/' + name; } }, methods: { init (info,fileList){ this.info = info this.fileList = fileList }, add (item,type){ var width,height,left,top; if(this.defaults.memorySize && this.defaults.left != 0 && item.name == this.defaults.currentCutName){ width = this.defaults.width; height = this.defaults.height; left = this.defaults.left; this.defaults.top += this.defaults.height + 10;//跟上一个area加点间距 top = this.defaults.top }else{ width = this.defaults.width = type.width; height = this.defaults.height = type.height; left = this.defaults.left = 100; top = this.defaults.top = 20; } this.defaults.currentCutName = item.name; item.areaList.push({ type:type, drag:{ move_flag:false, change_flag:false, mousePosition:{x:0,y:0}, areaPosition:{x:0,y:0}, areaSize:{width:0,height:0} }, left:left, top:top, width:width, height:height }); }, clear (item){ item.areaList = []; this.defaults.width = 0; this.defaults.height = 0; this.defaults.left = 0; this.defaults.top = 0; }, move_down (event,area){ if(!area.drag.move_flag){ this.currentMoveArea = area; area.drag.move_flag = true; area.drag.mousePosition = {x:event.clientX,y:event.clientY}; area.drag.areaPosition = {x:area.left,y:area.top}; } }, move_move (event,area){ if(area.drag.move_flag){ let left = area.drag.areaPosition.x + event.clientX - area.drag.mousePosition.x; let top = area.drag.areaPosition.y + event.clientY - area.drag.mousePosition.y; area.left = left > 0 ? left : 0; area.top = top > 0 ? top : 0; if(this.defaults.memorySize){ this.defaults.left = left; this.defaults.top = top; this.defaults.width = area.width; this.defaults.height = area.height; } } }, move_up (event,area){ if(area.drag.move_flag){ area.drag.move_flag = false; } }, remove (event,area,item){ removeObjWithArr(item.areaList,area); //设置最后一个area为默认尺寸 if(item.areaList.length>0){ let lastArea = item.areaList[item.areaList.length-1]; this.defaults.width = lastArea.width; this.defaults.height = lastArea.height; this.defaults.left = lastArea.left; this.defaults.top = lastArea.top; }else{ this.defaults.width = 0; this.defaults.height = 0; this.defaults.left = 0; this.defaults.top = 0; } }, change_down (event,area){ event.cancelBubble = true; if(!area.drag.change_flag){ this.currentChangeArea = area; area.drag.change_flag = true; area.drag.mousePosition = {x:event.clientX,y:event.clientY}; area.drag.areaSize = {width:area.width,height:area.height}; } }, change_move (event,area){ if(area.drag.change_flag){ var width = area.drag.areaSize.width + event.clientX - area.drag.mousePosition.x; var height = area.drag.areaSize.height + event.clientY - area.drag.mousePosition.y; area.width = width > 50 ? width : 50; area.height = height > 30 ? height : 30; if(this.defaults.memorySize){ this.defaults.width = width; this.defaults.height = height; this.defaults.left = area.left; this.defaults.top = area.top; } } }, change_up (event,area){ if(area.drag.change_flag){ this.currentMoveArea = null; area.drag.change_flag = false; } }, cut_move (event){//补充未快速响应的移动事件 if(this.currentMoveArea != null){ this.move_move(event,this.currentMoveArea); }else if(this.currentChangeArea != null){ this.change_move(event,this.currentChangeArea);//补充未快速响应的移动事件 } }, cut_up (event){//结束未快速响应的移动事件 if(this.currentMoveArea != null){ this.currentMoveArea.drag.move_flag = false; this.currentMoveArea = null; }else if(this.currentChangeArea != null){ this.currentChangeArea.drag.change_flag = false; this.currentChangeArea = null; } }, save (){ var form = { info:this.info, cutList:this.fileList }; var container = this.$refs.container; var width; if (window.getComputedStyle) { width = window.getComputedStyle(container, null).width; } else { width = container.currentStyle.width; } form.ratio = (parseFloat(width)/1920).toFixed(2); this.$post('activity/build', form, { emulateJSON: false }).then(function(data){ data = JSON.parse(data.bodyText); if(data.code == 0 ){ this.$message({ message: '已存在的页面地址(请确认活动路径和页面名称是否重复)!', type: 'warning' }); }else{ this.pageUrl = "//localhost:8999/preview/" + this.info.url + '/' + (this.info.type=="1"?"pc":"mobile"); } //this.$emit('close'); //this.$emit('reload'); }) } } }
生成数据结构:
代码生成:
点击生成活动时:提交到本地nodejs server,实现以下步骤:
1.新建活动代码目录build;
2.匹配活动模板,拼接HTML字符串,生成至build目录
3.拷贝默认携带的js,images等资源至build目录
4.生成build压缩包或上线代码
5.清空暂存目录
module.exports.build = function(req,res,next){ var info = req.body.info; var cutList = req.body.cutList; var ratio = req.body.ratio; var type = info.type == "1"? "pc":"mobile"; var formIndex = 1; var calculate = function(value){ if(type=="pc"){ return (value/ratio).toFixed(2) + 'px'; }else{ return (value/ratio/1920*100/10).toFixed(2) + 'rem'; } }; //check dir exist var output = Config.root + '/server/custom/output/' + info.url; if(!fsExtra.pathExistsSync(output)){ fsExtra.ensureDirSync(output); } if(fsExtra.pathExistsSync(output + '/' + type )){ res.json({success:true,code:0}); return; }else{ fsExtra.ensureDirSync(output); } //make html var html_content = ''; for(let c = 0 ; c < cutList.length ; c++){ let cut = cutList[c]; let initForm = false; if(cut.areaList.length == 0) html_content += '<img src="<%= images(\'' + cut.name + '\') %>" alt="家装季" />\n'; else{ html_content += '<div class="activity-module">\n'; html_content += '<img src="<%= images(\'' + cut.name + '\') %>" alt="家装季" />\n'; for(let a = 0 ; a < cut.areaList.length ; a++){ let area = cut.areaList[a]; let styles = 'top:' + calculate(area.top) + ';left:' + calculate(area.left) + ';width:' + calculate(area.width) + ';height:' + calculate(area.height) + ';'; switch(area.type.key){ case 'open-form': html_content += '<button class="activity-button" style="'+ styles +'"></button>\n'; break; case 'input-name': if(!initForm){ initForm = true; html_content += '<div id="j_form' + formIndex++ + '" form-baoming="' + c + '" >\n'; } html_content += '<input type="text" class="c1" data-placeholder="请输入您的姓名" style="'+ styles +'" />\n'; break; case 'input-telephone': if(!initForm){ initForm = true; html_content += '<div id="j_form' + formIndex++ + '" form-baoming="" >\n'; } html_content += '<input type="tel" class="c2" data-placeholder="请输入您的联系方式" maxlength="11" style="'+ styles +'" />\n'; break; case 'input-mianji': if(!initForm){ initForm = true; html_content += '<div id="j_form' + formIndex++ + '" form-baoming="" >\n'; } html_content += '<input type="tel" class="c3" data-placeholder="请输入您的房屋面积" maxlength="11" style="'+ styles +'" />\n'; html_content = html_content.replace(new RegExp('form-baoming=\"' + c + '\"'),'form-baoming="baojia"'); break; case 'input-text': if(!initForm){ initForm = true; html_content += '<div id="j_form' + formIndex++ + '" form-baoming="" >\n'; } html_content += '<input type="text" data-placeholder="请输入您的房屋面积" maxlength="11" style="'+ styles +'" />\n'; break; case 'input-submit': if(!initForm){ initForm = true; html_content += '<div id="j_form' + formIndex++ + '" form-baoming="" >\n'; } html_content += '<button class="btn_submit" style="'+ styles +'"></button>\n'; break; } } if(initForm) html_content += '</div>\n'; html_content += '</div>\n'; } } //build html var html_template_url = Config.root + '/server/custom/template/' + type + '.html'; var html_build_url = Config.root + '/server/custom/build/' + type + '/' + type + '.html'; var html = fs.readFileSync(html_template_url,"utf-8"); html = html.replace(/\[node-build-activity-title\]/g,info.title); html = html.replace(/\[node-build-activity-modules-placeholder\]/g,html_content); fs.writeFile(html_build_url,html,function(err){ if (err) throw err; //build js //build images var images_build_url = Config.root + '/server/custom/build/' + type + '/' + type + '/images'; fsExtra.removeSync(images_build_url); fsExtra.copySync(imagesUploadDir,images_build_url); //copy default images var images_default_url = Config.root + '/server/custom/template/' + type + '/images'; fsExtra.copySync(images_default_url,images_build_url); //copy all to custom var all_build_url = Config.root + '/server/custom/build/'; fsExtra.copySync(all_build_url + type , output); //clear pool fsExtra.removeSync(imagesUploadDir); res.json({success:true,code:1}); }); };
源码地址: JZ_Activity
原文链接:http://www.tliangl.com/article67.aspx
相关文章推荐
- RHCE 系列(三):如何使用 Linux 工具集生成和发送系统活动报告
- vue + elementUI 使用笔记1
- VUE 使用新版本 element-ui 组件库 Select 组件时, value 值为对象时的 BUG 处理
- vue使用element-ui的el-input监听不了回车事件
- webpack+vue 在使用element-ui时import 'element-ui/lib/theme-chalk/index.css‘失败
- RHCE 系列(三):如何使用 Linux 工具集生成和发送系统活动报告
- laravel5.4+vue+element-ui配置及简单使用
- VUE 使用新版本 element-ui 组件库 Select 组件时, value 值为对象时的 BUG 处理
- 关于Vue element ui 使用
- vue2.0 使用element-ui里的upload组件实现图片预览效果
- vue使用element-ui的el-input监听不了回车事件解决
- 在vue项目中使用element-ui的Upload上传组件
- 使用Vue.js和Element-UI做一个简单的登录页面
- 使用ES6+vue+elementui+webpack搭建简单项目
- [瞎折腾]使用freemarker编写MyBatis的Mapper.xml自动生成工具
- 使用Vue与ElementUI开发时,关于时间控件的问题
- 详解如何使用Node.js编写命令工具――以vue-cli为例
- 在vue中使用Element-UI
- 【PC端vue ui框架学习】vue项目如何使用基于vue的UI框架Element
- 使用ES6+vue+elementui+webpack搭建简单项目