当前位置: 首页 > news >正文

进贤网站建设网站建设尾款放在什么科目里

进贤网站建设,网站建设尾款放在什么科目里,wordpress模板命名规则,建立一个小程序多少钱应用场景 正常来说#xff0c;编辑器应用场景应该包括#xff1a; 编辑器-预览 编辑器 最终运行时 怎么去设计 上一篇推文#xff0c;我们已经大概了解了编辑器场景。接下来#xff0c;我们来看预览时的设计 编辑器-预览 点击预览按钮#xff0c;执行以…应用场景 正常来说编辑器应用场景应该包括 编辑器-预览        编辑器        最终运行时     怎么去设计 上一篇推文我们已经大概了解了编辑器场景。接下来我们来看预览时的设计 编辑器-预览 点击预览按钮执行以下逻辑 /** name 预览 **/async handlePreview() {...// 打开抽屉组件并往里面放置运行时模块createDrawer(h h(DashboardRuntime, { props: { dashboard: this.form } }),{title: 预览仪表盘,width: calc(100vw - 200px),},);} 也就是说 所以我们直接关注运行时表现 运行时设计 templateHabitContext :habitKeyhabitKey inithabitContextInit!-- loading框 --a-spin v-ifloading /divv-else:stylestyleCSSVariablebackground :backgroundthemeBackground :class$style.backgroundgrid-layout v-bindlayoutPropsdashboard-itemv-forfield in fields:keyfield.pkId//grid-layout/background/div/HabitContext /template 这里套了一层HabitContext框架是用来应用和记录用户习惯的后面讲。a-spin是加载层。紧接着和设计器差不多局部变量样式集里面套了个背景框架和grid-layout布局。 我们再看看dashboard-item的实现 templategrid-itemv-bindlayoutstatic.../grid-item /template 这里通过v-bind动态传入grid-item的属性也就是拣选出来的x/y/w/h这些。同时用static固定gird-item使其无法缩放、拖动、被其他元素影响。 templategrid-itemv-bindlayoutstaticdivv-ifshowChart.../div!-- 没权限显示占位图 --divv-elsestyleheight: 100%; width: 100%; display: flex; flex-direction: columndivspan :styletitleCss{{ field.name }}/span/div/div/grid-item /template 这里就是简单的做了一个占位 templategrid-itemv-bindlayoutstaticdivv-ifshowChartdiv :class$style.actiontemplate v-foraction in actionsa-tooltip:keyaction.keyplacementbottom:mouseLeaveDelay0:titleaction.namex-icon:typeaction.iconclickexecAction(action)//a-tooltip/template/divcomponent:iscomponent:fieldfield//div!-- 没权限显示占位图 --divv-elsestyleheight: 100%; width: 100%; display: flex; flex-direction: columndivspan :styletitleCss{{ field.name }}/span/div/div/grid-item /template 浮层按钮还有具体的图表组件 数据流设计 到这里我们已经看完了编辑器功能的大概设计。接下来该写写这套系统最核心的部分数据流设计了。 创建一个仪表盘编辑器 点下新增按钮后我们传入一些系统参数【应用id功能类别等等在这里我们并不需要关注】储存新建仪表盘在系统的位置和属性。 在接口储存完这些系统信息后跳转到仪表盘页面进行最为关键的仪表盘初始化数据生成。 async handleAddForm(category) {// 弹窗让填写名称、图标等基础信息const result await GroupForm.createModal({data: { parentId: this.groupId, appId: this.appId, category },},{title: this.getCategoryName(category),width: 427px,},);// 调用接口保存const formId await add(result);this.$message.success(this.$t(common.tips.add));// 保存完毕后跳转到页面switch (category) {case FormCategoryType.DASHBOARD:return this.$router.push(/dashboard-design/${formId});...default:return this.$router.push(/form-design/${formId}/form);}}这里是通过vue-router进行跳转。这里也简单贴出路由代码 import DashboardDesign from /views/dashboard-design;const DashboardDesignRoutes [{path: /dashboard-design/:id,component: DashboardDesign,},... ];export default DashboardDesignRoutes; 到这里结束一个仪表盘编辑器已经创建完毕了。它只存储了系统数据没有仪表盘的初始数据。而当我们进入仪表盘编辑器页面的时候完成有效编辑之后才会以正式数据存储下来。 当然这里指的是前端数据后端还是会根据我们穿进去的系统参数生成一份默认的接口向的仪表盘数据模板比如默认权限、默认刷新时间上面的 进入仪表盘编辑器页面  先通过后端接口拿到当前仪表盘编辑器id的接口数据 formDesignModule.Action init; async created() {...await this.init(this.formId).then(() {...} } 大概长这样记录一些系统信息或默认属性 。这里的init是vuex的action操作。为了是把数据保存到前端本地。更多关于本项目的vuex方法请看我另外一篇文章的介绍 讲讲项目里的状态存储器vuex_AI3D_WebEngineer的博客-CSDN博客https://blog.csdn.net/weixin_42274805/article/details/133237271?spm1001.2014.3001.5501 看看这个init的actions做了什么 actions: {async init({ commit }, formId) {const form await getFormData(formId);commit(saveForm, form);} } mutations: {saveForm(state, data) {state.form data;...state.loading false;state.changed false;} } 这里是通过调用接口获取当前仪表盘的数据并把它存到当前的formDesignModule也就是formDesign这个命名空间的仓库里。 仪表盘编辑页面的状态管理器 我们刚刚看到了代码在编辑页面created里我们执行了init。其实就是非显示地获取数据。吧获取数据的过程从页面隐式地放到了状态管理器里的actions里面。并通过state返回关注的数据。这样子无论我们在仪表盘功能里怎么去跳转页面都不需要再重新调用接口了而是直接从仓库里拿。 formDesignModule.State form;formDesignModule.Action init;formDesignModule.State loading;formDesignModule.State selectedField;formDesignModule.Getter fields;formDesignModule.Mutation updateSelectedField;formDesignModule.Mutation selectField;formDesignModule.Mutation updateSetting;formDesignModule.Mutation saveForm;formDesignModule.Mutation updateDashboardConfig;formDesignModule.Action save;大概有这些属性和方法来完成编辑器的功能实现。看看就行了。紧接着我们来讲其中一些实现 点击添加组件到仪表盘 有两种添加方法 ① 点击组件按钮添加 ② 拖拽组件添加 点击组件 handleClickAdd() {...// 初始化layoutconst layout getDashboardLayoutByType(type);const layoutList ensureArray(this.$refs.container.layout);layout.x (layoutList.length * 2) % 60;layout.y layoutList.length 60;field.widget.layout layout;// 初始化风格field this.initFieldStyle(field); } getDashboardLayoutByType是根据你点击的组件生成默认的组件layout数据。比如图片组件定义的默认layout是 export function getDashboardLayoutByType(type) {const layout getDashboardControlMeta(type, layout);return { x: 0, y: 0, ...(typeof layout function ? layout() : layout) }; } 这时返回了一个初始化的layout即{w:30,h:15,minH:7,x:0,y:0}。 const layoutList ensureArray(this.$refs.container.layout);这里是直接获取设计器组件里面的layout属性它的data值。这个layout目前是个空数组因为是新建的仪表盘里面没有组件。 layout.x (layoutList.length * 2) % 60; layout.y layoutList.length 60; field.widget.layout layout;// 更新布局 this.$refs.container.syncLayout(); 很好理解啦我们吧初始化layout的横纵坐标调整到它应该在的位置上并吧这个调整过的layout信息存储到新增组件的布局属性里(替换掉初始化layout)。讲讲为什么这么计算         可以看到实例中这两个组件的x/y值并不像上面这个逻辑计算出来的。 如果按照上面那个逻辑计算出来则应该是{x:0,y:60...}和{x:2,y:61...}。其实这个计算过程是为了保证第n1个组件的x和y一定大于第n个。从而避免重叠出错而至于精准的layout数据是借助vue-layout-grid插件行自适应生成。具体怎么做我们看代码 /** name 同步layout **/syncLayout() {this.layout ensureArray(this.fields).map(field ({...field.widget.layout,i: field.pkId,}));} grid-layoutreflayout:class$style.layout:layout.synclayout ... /grid-layout 很多人看到这里就要骂了骗人你这不是啥都没干只是把layout重新赋值了一遍。让我们改下代码看看 /** name 同步layout **/async syncLayout() {this.layout ensureArray(this.fields).map(field ({...field.widget.layout,i: field.pkId,}));console.log(this.layout);await this.$nextTick();console.log(this.layout);} 第一个输出 [{h: 10,w: 12,x: 0,y: 0},{h: 20,w: 60,x: 2,y: 61} ] 第二个输出 [ {h: 10,w: 12,x: 0,y: 0,i: 39b19b29-c8ef-4fd3-8604-d7e168196ae6 }, {h: 20,w: 60,x: 2,y: 10,i: 5d684834-26bd-4d35-b7ff-36d8de9d903e }, ] 可以看到此时this.layout已经变了。这是因为grid-layout已经自适应了布局。 由此我们的保存仪表盘布局方法也呼之欲出了 save() {// 拿到同步后的this.layoutconst layout this.$refs.container.layout;// 生成组件id和layout信息的映射表const layoutMap generateMap(layout, i, item pick(item, x, y, w, h),);... } 先看到这里这里要生成一份类似于:amdous123623: {w:10,h:20,x:0,y:0...}这样的映射表是整个仪表盘布局的储存并不是直接存储类似于girdLayout的这种数组而是由一个个组件自身的layout属性甚至无视组件排序拣选出来生成this.layout。也就是说仪表盘的存储结构为Arrayfield这样的。 save(fields) {const layout this.$refs.container.layout;const layoutMap generateMap(layout, i, item pick(item, x, y, w, h),);this.privateUpdateFields((fields || this.fields).map(field {if (!layoutMap[field.pkId]) return field;return {...field,widget: {...field.widget,layout:{...field.widget.layout,...layoutMap[field.pkId],}},};}),);} 拖拽添加组件到仪表盘 前面我们已经讲了拖拽添加组件的思路和预防错位或重叠的处理。现在来讲讲具体代码实现。 之前讲过了在control-list.vue也就是左边的组件列表拖拽出组件触发dragstart方法同时往设计器里传入dragType。设计器里根据dragType找对对应的组件初始化layout Watch(dragType)handleDragTypeChange(type) {this.isInChildCom false; // 重新拖动需要重置if (type) {this.dragLayout {i: drag,...getDashboardLayoutByType(type),};} else {this.dragLayout null;}}假设此时拖拽元素已经拖拽到在设计器也就是gird-layout上面。触发dragover.nativehandleDrag handleDrag(ev) {if (this.isInChildCom) return; // 进入子元素范围则无需触发ev.preventDefault();this._handleDrag(ev); } throttle(100) _handleDrag(ev) {if (!this.dragType || !this.$el) return;if (this.dragContext.clientX ev.clientX this.dragContext.clientY ev.clientY)return;this.dragContext.clientX ev.clientX;this.dragContext.clientY ev.clientY;this.updateInside(ev);this.updateDrag(ev); } _handleDrag每100秒记录一次拖拽元素的位置当拖拽元素发生变动时更新设计器视图。 updateInside(ev) {if (!this.dragType || !this.$el) return;const rect this.$el.getBoundingClientRect();const errorRate 10;const inside ev.clientX rect.left errorRate ev.clientX rect.right - errorRate ev.clientY rect.top errorRate ev.clientY rect.bottom - errorRate;if (inside this.dragLayoutIndex -1) {this.layout.push(this.dragLayout);}if (!inside this.dragLayoutIndex ! -1) {this.layout.splice(this.dragLayoutIndex, 1);}} 这里是获取设计器边界的位置属性errorRate为误差范围你可以理解为设计器有padding判断拖拽元素是否在设计器边界内如果是就往layout里面加入它重复则不加入如果已经超出设计器则移除。 我们往编辑器拖拽移动可以看到这个虚线框会一直跟随变动可能你们就要问了上面的代码里dragLayout一但被添加进layout那么dragLayoutIndex就不会是-1也就是说layout里面的dragLayout不会改变x或y。那这个虚框是怎么还在移动的 其实啊这个虚框并不由layout里的数据决定。而是由vue-grid-layout这个插件负责渲染的。在拖动的时候this.layout是不会变的。我们只需要每100毫秒记录一次拖拽元素的当前位置this.dragLayout直到放置生效之后用this.dragLayout去覆盖this.layout里面的那个被拖动元素。 所以updateDrag是为了更新this.dragLayout。通过clientY/X换算成vue-grid-layout的x,y const dragRef this.getDragRef();if (!this.dragType || !dragRef) return;const rect this.$el.getBoundingClientRect();const dragging {top: this.dragContext.clientY - rect.top,left: this.dragContext.clientX - rect.left,};dragRef.dragging dragging;const newLayout dragRef.calcXY(dragging.top, dragging.left);this.dragLayout.x newLayout.x;this.dragLayout.y newLayout.y;} getDragRef() {// vue-grid-layout默认在$children内存在一个组件实例了, 其实每次拖动直接取最后一个实例应该就可以了return this.$refs.layout.$children[this.$refs.layout.$children.length - 1]; } 当我们放手时触发 grid-layout组件上的drop事件我们来看看drop.nativehandleDrop的handleDrop方法 async handleDrop() {if (this.isInChildCom) return; // 进入子元素范围则无需触发if (!this.dragType) return;... } 重叠和空类型直接当做无效动作处理 async handleDrop() {if (this.isInChildCom) return; // 进入子元素范围则无需触发if (!this.dragType) return;try {...}catch (e) {this.layout.splice(this.dragLayoutIndex, 1);throw e;}finally {this.$emit(update:dragType, null);} } 这个try catch我们之前已经讲过了。try里面的逻辑也很简单 try {let field createDashboardField(this.dragType);...field.widget.layout pick(this.dragLayout, x, y, w, h);...// 更新布局this.layout.splice(this.dragLayoutIndex, 1, {...field.widget.layout,i: field.pkId,});// 提交数据存储this.$emit(add, field); } 拖拽移动组件位置 由插件处理会自动更新到this.layout 放大缩小组件 由插件处理会自动更新到this.layout 删除组件 async handleDelete(pkId) {const cloneFields deepClone(this.fields);// 摘除删除的组件数据this.updateFields(cloneFields.filter(field {return field.pkId ! pkId;}),);await this.$nextTick();this.$refs.container.syncLayout(); } /** name 同步layout **/async syncLayout() {this.layout ensureArray(this.fields).map(field ({...field.widget.layout,i: field.pkId,}));await this.$nextTick();} 额外讲一下选中组件对组件进行修改 当我们选中组件的时候需要在vuex里登记一下当前的选中状态 grid-itemv-forlayoutItem in layout...mousedown.nativehandlePointerDownmouseup.nativehandlePointerUp($event, layoutItem.i) ... /grid-item 加了一些位置判断以防这个组件位置出错或已经不在布局里 /** name 鼠标设备按下与抬起事件处理 **/_pointerContext null;handlePointerDown(ev) {this._pointerContext {x: ev.clientX,y: ev.clientY,};}handlePointerUp(ev, pkId) {if (!this._pointerContext || !this.fieldMap[pkId]) return;const { x, y } this._pointerContext;if (x ! ev.clientX || y ! ev.clientY) return;this.selectField(this.fieldMap[pkId]);}formDesignModule.Mutation selectField; 再来看看仓库的代码 // fromdesign.jsselectField(state, field) {state.selectedField field;}, 如果当前组件的内容或属性发送变更则执行 commit(selectField, newField);
http://www.dnsts.com.cn/news/52842.html

相关文章:

  • 给公司建网站 深圳唐山 网站建设
  • 网站的建设方式有哪些网站备案 几年
  • 手机版网站设计风格宜昌微网站建设
  • 网站广告源码免费表白网页在线生成制作
  • 哪类小网站容易做鹿泉建设网站
  • 三网合一网站建设合同微信小程序怎么上架商品
  • 做明星网站打广告购物网站怎么做推广
  • 做科学小制作的视频网站找装修公司的网站
  • 如何seo网站外贸如何推广公司网站
  • 长春seo技术seo关键词优化排名外包
  • 微信端网站开发流程图网站建设申请报告怎么写
  • 北京网站定制流程怎么样开发小程序
  • 深圳宝安高端网站建设报价网站如何防止别人抄袭
  • 北京网站优化步骤建筑模型设计网站建设
  • 一级a做爰片在线看免播放器网站什么是自建站
  • 一个网站建设的组成长沙人才招聘网最新
  • c网站开发广州建筑装饰集团有限公司
  • 制作网页框架太原网站优化怎么做
  • 织梦房产网站模板wordpress手机访问慢
  • 企业网络推广做网站推广公司京东网上商城官网
  • 芜湖网站建设哪家好安徽网新科技怎么建设网站
  • 网站栏目内链怎么做wordpress伪静
  • 网站开发用什么软件编程asp网站用什么数据库
  • 做海关授权的网站做网络推广一个月的收入
  • 宁波优化推广选哪家东莞网络排名优化
  • 公司网站推广如何做建平台网站费用
  • 2021年度关键词有哪些seo网站程序
  • 用织梦做的网站好还是cms网站服务器怎么做安全防护
  • 网站开发技术说明文档山西响应式网站建设哪家有
  • 微建站官网公众号开发教程视频