!(function(v, g){ g["DataV"] || (g["DataV"] = v()); })(function(){ const zoom = [0, 20, 40, 60, 80, 99]; // 获取唯一序列码 let xid_i = 0; const getXid = function(){ xid_i++; return "xid_" + (xid_i); } const getInt = function(string){ let i = parseInt(string); return isNaN(i) ? 0 : i; } // 初始化DataV对象 const exports = {}; // 初始化容器内容 const createApp = exports.createApp = function(dom, opt){ return new DataV(dom, opt); } // dataV 初始化配置 const opt_def = { width: "100%", height: "100%" } // dataV容器对象 const DataV = function(dom, opt){ this.opt = Object.assign(opt_def, opt); this.dom = dom; this.plugin = []; // 容器内部组件 this.domInit(this.dom); this.dataVInit(this.dom); // 初始化对象属性 // 创建右键事件对象 this.rightFunctionOpt = new RightFunction({ dom: this.dom, menu: [{ name: "新增一个div" , value: this.addDiv.bind(this) }] }); // 首先威触发dom绑定事件 this.initEvent(this.dom, "contextmenu"); } const domInit = function(dom){ const opt = this.opt; dom.style.cssText = `width: ${opt.width}; height: ${opt.height};`; dom.setAttribute("data-contextmenu", "onDomContextmenu") } const dataVInit = function(dom){ // 初始化内部组件事件监听 this.initEvent(dom, "click"); } const add = function(plugin){ this.plugin.push(plugin); this.dom.appendChild(plugin.dom); } const remove = function(){ } const initEvent = function(dom, type, fnName){ dom.addEventListener(type,(e) => { e.preventDefault(); var _this = e.target; for( ; ; ){ e.target = _this; if( !_this || !_this.parentElement ) break; if( _this.dataset[e.type] ) { const fn = _this.dataset[e.type]; typeof fn === "string" && this[fn] && this[fn](e, this); } if( _this == dom ){ // if( this[fnName || "on"+e.type] ) { // this[fnName || "on"+e.type](e, this); // break; // } break; } _this = _this.parentElement; } }); } const DataVonDomContextmenu = function(e){ this.rightFunctionOpt.show(e.pageX, e.pageY); } const addDiv = function(){ this.add(new DivElement()); } DataV.prototype = { add, // 添加组件 remove, // 删除组件 initEvent, // 初始化组件事件监听 domInit, // 初始化dom dataVInit, // 初始化数据 onDomContextmenu: DataVonDomContextmenu, addDiv: addDiv } // -------------------- 右键功能 const RightFunctionOpt = { dom: document.body, menu: [{ name: "测试", value: ()=>{ alert("测试") }, dom: null}] } const RightFunction = function(_opt){ const opt = this.opt = Object.assign(RightFunctionOpt, _opt); this.dom = this.createDom(); this.initEvent(this.dom, "contextmenu"); this.initEvent(this.dom, "click"); this.render(); this.cssText = ` .\${xid} { left: \${left}; top: \${top}; position: absolute; border: solid 1px #000000; border-radius: 3px; } .\${xid} div { padding: 4px; border-bottom: 1px #333333; } `; this.datas = { left: "0px", top: "0px", } this.styled = this.createStyle(); } RightFunction.prototype = { createStyle (){ return new Styled(this.dom, this.cssText, this.datas); }, createDom (){ const div = document.createElement("div"); div.className = "rightFunction"; return div; }, render (){ const menu = this.opt.menu; const optionDom = menu.map((options, i)=>{ return `<div data-index='${i}' data-click='selectOption'>${ options.name }</div>`; }) this.dom.innerHTML = optionDom; }, show (x, y){ this.datas.left = x + "px"; this.datas.top = y + "px"; this.styled.setDatas(this.datas); this.opt.dom.appendChild(this.dom); }, hide (){ this.dom.remove(); }, initEvent: initEvent, selectOption (e){ const menu = this.opt.menu[e.target.dataset.index] menu.value && menu.value(menu, this.opt.menu, this); } } // ----------------------- 关于样式管理器 const Styled = function(dom, styled, datas, isOnlyXid){ this.xid = isOnlyXid || getXid(); this.dom = dom; this.dom.classList.add(this.xid); this.styled = styled.replace(/\t|\n/g,""); this.datas = datas; this.styleElement = this.createStyle(); this.render(); } Styled.prototype = { // 生成唯一识别码 createStyle (){ const o = document.head.querySelector("."+this.xid); if( o ){ return o; } const style = document.createElement("style"); document.head.appendChild(style); style.classList.add(this.xid); return style; }, setDatas(opt) { this.datas = Object.assign(this.datas, opt); this.render(); }, render (){ // this.styleElement.innerHTML = eval(`()=>{ var {${Object.keys(this.datas)}} = this.datas, xid=${this.xid}; return {} }()`); this.styleElement.innerHTML = function(){ eval(`var {${Object.keys(this.datas)}} = this.datas, xid="${this.xid}"`); return eval("\`"+this.styled+"\`"); }.call(this); } } // 一个Div对象 class DivElement { constructor(arg) { this.dom = this.createElement(); // 数据模型 this.datas = {}; // 样式数据模型 this.styleDatas = { position: "", top: "", left: "", transformX: 0, transformY: 0, color: "", width: "", height: "100px", fontWeight: "", fontSize: "12px" , padding: "4px 4px 4px 4px", margin: "4px 4px 4px 4px", border: "solid 1px #f0f0f0", borderTop: "solid 1px #ffffff", borderBottom: "solid 1px #ffffff", borderLeft: "solid 1px #ffffff", borderRight: "solid 1px #ffffff", backgroundColor: "", backgroundImage: "", }; // 样式模型 this.style = ` .\${xid} { color: \${color}; font-size: \${fontSize}; font-weight: \${fontWeight}; // border: \${border}; border-top: \${borderTop}; border-bottom: \${borderBottom}; border-left: \${borderLeft}; border-right: \${borderRight}; padding: \${padding}; margin: \${margin}; height: \${height}; width: \${width}; background-color: \${backgroundColor}; background-image: url(\${backgroundImage}); background-repeat: no-repeat; background-size: contain; position: \${position}; top: \${top}; left: \${left}; transform: translate(\${transformX}px, \${transformY}px); `; // 样式模型 this.styled = new Styled(this.dom, this.style ,this.styleDatas); // 蒋婷点击事件 this.initEvent(this.dom, "click"); } isCanDrop (){ return this.styleDatas.position === "absolute"; } editOptionChange (ary){ } // 进入选中状态 showSelectModel (){ // 当前选中模式 selectModel.setPlugin(this); // 弹出样式编辑 styleEdit.setPlugin(this); } clickDiv (){ this.showSelectModel(); } createElement (){ const div = document.createElement("div"); div.setAttribute("data-click", "clickDiv"); return div; } render (){ } // 渲染数据 renderData (){ } // 渲染样式 renderStyle (){ } initEvent (){ return initEvent.apply(this, arguments); } onstyleEdit (styleEdit){ // 编辑模块 this.editOption = [{ type: "computed", value: this.styleDatas, change: (e)=> { this.styleDatas = { ...this.styleDatas, ...e }; } },{ type: "img", name: "背景图片", value: this.styleDatas.backgroundImage, change: (e)=> { this.styleDatas.backgroundImage = e } },{ type: "select", name: "定位类型", value: this.styleDatas.position, options: [{ name: "全局定位", value: "absolute" }, { name: "默认定位", value: "" }], change: (e)=> { this.styleDatas.position = e; } }]; styleEdit.onchange = ()=>{ this.styled.setDatas(this.styleDatas); // 当前选中模式 selectModel.setPlugin(this); }; } } // 选中,操作模块 class SelectModel { constructor(plugin) { this.parentPlugin = this.plugin; this.dom = this.createElement(); this.style = ` .\${xid} { position: absolute; top: \${top}; left: \${left}; width: \${width}; height: \${height}; border: solid 1px #2e78ff; transform: translate(\${offx}px, \${offy}px); } `; this.styleDatas = { top: "0px", left: "0px", width: "0px", height: "0px", offx: 0, offy: 0 }; this.styled = new Styled(this.dom, this.style, this.styleDatas) } setDrop (Drop){ this.drop = new Drop(this.dom, this.dropMoveChange.bind(this), this.dropMoveChangeEnd.bind(this)); } dropMoveChangeEnd (){ if( !this.plugin.isCanDrop() ) return; this.styleDatas.top = getInt(this.styleDatas.top) + this.styleDatas.offy + "px"; this.styleDatas.left = getInt(this.styleDatas.left) + this.styleDatas.offx + "px"; this.styleDatas.offy = 0; this.styleDatas.offx = 0; this.styled.setDatas(this.styleDatas); // 联动当前选中的组件 this.plugin.styleDatas.top = getInt(this.plugin.styleDatas.top) + this.plugin.styleDatas.transformY + "px"; this.plugin.styleDatas.left = getInt(this.plugin.styleDatas.left) + this.plugin.styleDatas.transformX + "px"; this.plugin.styleDatas.transformX = 0; this.plugin.styleDatas.transformY = 0; this.plugin.styled.setDatas(this.plugin.styleDatas); } dropMoveChange (x, y){ if( !this.plugin.isCanDrop() ) return; this.styleDatas.offx = x; this.styleDatas.offy = y; this.styled.setDatas(this.styleDatas); // 联动当前选中的组件 this.plugin.styleDatas.transformX = x; this.plugin.styleDatas.transformY = y; this.plugin.styled.setDatas(this.plugin.styleDatas); } createElement (){ const div = document.createElement("div"); return div; } // 获取当前组件的dom位置信息 getDomRects(dom){ return dom.getClientRects()[0]; } setPlugin (plugin){ this.plugin = plugin; const rect = this.getDomRects(plugin.dom); this.styleDatas.width = rect.width + "px"; this.styleDatas.height = rect.height + "px"; this.styleDatas.top = rect.top + "px"; this.styleDatas.left = rect.left + "px"; this.styled.setDatas(this.styleDatas); this.show(); } show(){ document.body.appendChild(this.dom); } hide(){ this.dom.remove(); } } // 创建全局得选中管理器 const selectModel = new SelectModel(); // 关于style编辑器 class StyleEdit { constructor(styleEditOption) { // 需要控制的内容 this.editOption = [{ name: "颜色", inputType: "color" , type: "input" }]; this.editElement = []; this.dom = this.createElement(); // this.initEvent(this.dom, "change"); this.getStyled(); } getStyled (){ this.styled = new Styled(this.dom, ` .\${xid} { position: absolute; top: 15px; right: 15px; border: solid 1px #000000; padding: 8px; background: #fff; z-index: ${zoom[5]}; }`, {}, this.constructor.xid); } createElement (){ const div = document.createElement("div"); div.classList.add("styleEdit"); return div; } render (){ this.dom.remove(); this.dom.innerHTML = ""; // 根据配置的可编辑方案填补内容 this.editOption.forEach((e)=>{ this.dom.appendChild(this.getRenderDom(e)); }) } getRenderDom (opt){ let el = this.editElement.find((element)=>{ return element.type === opt.type }); el = new el(opt); el.setEdit(this); return el.dom; } setPlugin (plugin){ this.plugin = plugin; plugin.onstyleEdit(this); this.editOption = plugin.editOption; this.render(); this.show(); } addElementType (EditElement){ this.editElement.push(EditElement); } show (){ document.body.appendChild(this.dom); } hide (){ this.dom.remove(); } // 完整得组件变化调用事件 外部定义得 内部不需要实现 onchange (){ } // 每一行变化触发 changeElement (){ this.onchange(); } } // 拖动插件 const Drop = function(dom, fn, efn){ this.dom; this.cover = this.createCover(); this.setBox(dom); this.onchange = fn; this.onchengeEnd = efn; } Drop.prototype = { createCover (){ const divCover = document.createElement("div"); divCover.style.cssText = ` position: absolute; top:0; left: 0; width: 100%; height:100%; ` return divCover; }, setBox : function(dom){ this.element = dom; dom.addEventListener("mousedown",this.down.bind(this)); }, down : function(event){ // 再地图上创建一个全屏 document.body.appendChild(this.cover); this._move = this.move.bind(this); this._up = this.up.bind(this); // this._enter = this.enter.bind(this); // this.cover.addEventListener("mouseenter",this.__enter); this.cover.addEventListener("mousemove",this._move); this.cover.addEventListener("mouseup",this._up); // 绑定释放事件 }, enter (event){ this.startX = event.pageX; this.startY = event.pageY; }, up : function(event){ this.cover.removeEventListener("mousemove",this._move); this.cover.removeEventListener("mouseup",this._up); // 绑定释放事件 // this.cover.addEventListener("mouseenter",this.__enter); this._move = null; this._up = null; this.startX = null; this.startY = null; // this.__enter = null; this.cover.remove(); this.onchengeEnd(); }, move : function(event){ if( !this.startX ) return this.enter(event); var left = event.pageX - this.startX; var top = event.pageY - this.startY; console.log( this.startX, this.startY, event.pageX, event.pageY) this.onchange(left, top); } } selectModel.setDrop(Drop); // 实例化样式编辑实例 const styleEdit = new StyleEdit(); // 输入框的编辑类型 class EditInputElement { static type = "input"; static xid = getXid(); initEvent (){ return initEvent.apply(this, arguments); } constructor(arg) { this.edit = null; this.options = arg; this.dom = this.getRenderDom(arg); this.initEvent(this.dom, "change"); this.getStyled(); } getStyled (){ this.styled = new Styled(this.dom, ` .\${xid} { border: solid 1px #000000; padding: 8px; }`, {}, this.constructor.xid); } getRenderDom ( { name, value, inputType } ){ const div = document.createElement("div"); div.classList.add("styleEditRow"); div.innerHTML = ` <div> ${name} </div> <div> <input data-change='changeValue' value='${value}' type='${inputType}' ></div> ` return div; } setEdit (edit){ this.edit = edit; } changeValue (options){ this.options.change(options.target.value); this.edit.changeElement(options); } } // 盒子模型编辑插件 class ComputedElement extends EditInputElement { static type = "computed"; static xid = getXid(); constructor (arg){ super(arg); this.initEvent(this.dom,"click"); } getStyled (){ const xid = this.constructor.xid; const options = this.options.value; this.styleDatas = { ...options, borderTop: options.borderTop.split(" "), // "border 1px #ffffff".split(" "), borderBottom: options.borderBottom.split(" "), // "border 1px #ffffff".split(" "), borderLeft: options.borderLeft.split(" "), // "border 1px #ffffff".split(" "), borderRight: options.borderRight.split(" ") // "border 1px #ffffff".split(" "), }; this.styled = new Styled(this.dom, ` .\${xid} { border: solid 1px #000000; padding: 8px; } .\${xid} .computedBx_${xid} { height: 35px; line-height: 35px; position: relative;text-align: center; font-size: 12px; } .\${xid} .top_${xid}{ position: absolute; padding: 2px; border: solid 1px #f0f0f0; top: 0px; left: 0px; width: 100%; height: 4px; background-color: \${borderTop[2]}; box-sizing: border-box; } .\${xid} .bottom_${xid}{ position: absolute; padding: 2px; border: solid 1px #f0f0f0; bottom: 0px; left: 0px; width: 100%; height: 4px; background-color: \${borderBottom[2]}; box-sizing: border-box;} .\${xid} .left_${xid}{ position: absolute; padding: 2px; border: solid 1px #f0f0f0; top: 0px; left: 0px; width: 4px; height: 100%; background-color: \${borderLeft[2]}; box-sizing: border-box;} .\${xid} .right_${xid}{ position: absolute; padding: 2px; border: solid 1px #f0f0f0; top: 0px; right: 0px; width: 4px; height: 100%; background-color: \${borderRight[2]}; box-sizing: border-box;} `, this.styleDatas, this.constructor.xid); } getRenderDom ( { name, value, inputType } ){ const div = document.createElement("div"); div.classList.add("styleEditRow"); const xid = this.constructor.xid; const options = this.options.value; div.innerHTML = ` <div> 盒子模型 </div> <div class='computedBx_${xid}'> <div data-click='border' data-bordertype='borderTop' class='top_${xid}'></div> <div data-click='border' data-bordertype='borderBottom' class='bottom_${xid}'></div> <div data-click='border' data-bordertype='borderLeft' class='left_${xid}'></div> <div data-click='border' data-bordertype='borderRight' class='right_${xid}'></div> <div data-click='border' data-borderType='border'>border颜色</div> </div> <div class='computedBx_wh'> <div> <div>宽度</div> <input type='text' data-change='changeAttr' data-type='width' value='${options.width}' /> </div> <div> <div>高度</div> <input type='text' data-change='changeAttr' data-type='height' value='${options.height}' /> </div> </div> ` return div; } // 改变属性 changeAttr (e){ this.styleDatas[e.target.dataset.type] = e.target.value; this.changeValue(this.getJson()); } border (e){ let type = [e.target.dataset.bordertype]; if( type[0] == "border" ) { type = ["borderTop", "borderBottom", "borderLeft", "borderRight"] } this.getColor().then((color)=>{ type.forEach((t)=>{ // 修改对应的样式 this.styleDatas[t][2] = color; }) this.styled.setDatas(this.styleDatas); this.changeValue(this.getJson()); }) } getJson (){ return { ...this.styleDatas, borderTop: this.styleDatas.borderTop.join(" "), borderBottom: this.styleDatas.borderBottom.join(" "), borderLeft: this.styleDatas.borderLeft.join(" "), borderRight: this.styleDatas.borderRight.join(" "), } } getColor (){ return new Promise((resovle)=>{ const ipt = document.createElement("input"); ipt.type = "color"; ipt.onchange = function(e){ resovle(e.target.value); } ipt.click(); }) } changeValue (options){ this.options.change(options); this.edit.changeElement(options); } } const fs = new FileReader(); // 图片编辑类型 class ImageElement extends EditInputElement { static type = "img"; static xid = getXid(); constructor (arg){ super(arg); this.initEvent(this.dom,"click"); } getStyled (){ const xid = this.constructor.xid; const options = this.options.value; this.styleDatas = { imagesUrl: options }; this.styled = new Styled(this.dom, ` .\${xid} { margin: 4px; padding: 8px; height: 150px; width: 100%; } .computedBx_\${xid} { background: url(\${imagesUrl}); width: 100%; height: 100%; background-repeat: no-repeat;background-size: contain;} `, this.styleDatas, this.constructor.xid); } getRenderDom ( { name, value, inputType } ){ const div = document.createElement("div"); div.classList.add("styleEditRow"); const xid = this.constructor.xid; div.innerHTML = ` <div> ${name} </div> <div class='computedBx_${xid}' data-click='updateImage'> </div> ` return div; } getImage (){ return new Promise((resovle)=>{ const ipt = document.createElement("input"); ipt.type = "file"; ipt.onchange = function(e){ // resovle(e.target.value); fs.onload = function(e){ resovle(e.currentTarget.result); } fs.readAsDataURL(e.target.files[0]); } ipt.click(); }) } updateImage (){ this.getImage().then((base64)=>{ this.styleDatas.imagesUrl = base64; this.styled.setDatas(this.styleDatas); this.changeValue(this.styleDatas); }) } changeValue (options){ this.options.change(options.imagesUrl); this.edit.changeElement(options.imagesUrl); } } // 多选 // 图片编辑类型 class SelectElement extends EditInputElement { static type = "select"; static xid = getXid(); constructor (arg){ super(arg); this.initEvent(this.dom,"click"); } getStyled (){ const xid = this.constructor.xid; const options = this.options.value; this.styleDatas = { // imagesUrl: options }; this.styled = new Styled(this.dom, ` .\${xid} { margin: 4px; padding: 8px; height: 150px; width: 100%; } `, this.styleDatas, this.constructor.xid); } getRenderDom ( { name, value, options } ){ const div = document.createElement("div"); div.classList.add("styleEditRow"); const xid = this.constructor.xid; div.innerHTML = ` <div> ${name} </div> <div class='computedBx_${xid}'> <select data-change="changeValue"> ${ options.map((e)=> `<option ${e.value === value && "selected"} value='${e.value}'>${e.name}</option>` ) } </select> </div> ` return div; } changeValue (options){ this.options.change(options.target.value); this.edit.changeElement(); } } // input编辑类型 styleEdit.addElementType(EditInputElement); styleEdit.addElementType(ComputedElement); styleEdit.addElementType(ImageElement); styleEdit.addElementType(SelectElement); return exports; }, window)
标签:xid,dom,styleDatas,options,写不动,弃坑,DataV,div,const From: https://www.cnblogs.com/liao1992/p/17260921.html