讲讲项目里的仪表盘编辑器(一)
需求
要做一个仪表盘系统,要求有:
① 设计功能(包括布局、大小、排列)
② 预览功能
③ 运行功能
布局选择
做编辑器,肯定要先选择布局。
前端有几种常用布局。
静态布局
也叫文档布局。默认的网页形式是文档流的形式,一个网页就像是一条条从左流向右的河流。在文档中有两种元素,内联元素(display:inline)和块级元素(display:block)。内联元素默认从左到右流,遇到阻碍或者宽度不够自动换行,继续按照从左到右的方式布局。而块级元素则会独占一行,按照从上往下的方式布局。内联元素的宽度和高度默认都被内容撑开。
这肯定不适合用来做编辑器。
浮动布局
浮动元素会脱离文档流并浮动到左侧或右侧。这时候其他的周围内容就会在这个被设置浮动 (float) 的元素周围环绕。
这种肯定也不行。因为元素只能向左向右浮动。并且周围元素会围绕浮动元素旋转,并不会脱离文档流,也就是无法自定义其位置。
定位布局
通过调整position这个CSS属性的值来实现(absolute/relative/fixed/static(绝对/相对/固定/静态(默认))四个值)。
static为静态布局,遵循默认文档流。这没什么好说的。
absolute绝对定位:元素会脱离文档流,通过TBLR( top,bottom,left,right) 定位,会选取最近的一个有定位设置的父级对象(非static)进行绝对定位,如果没有设置定位属性的父级对象,则将以body坐标原点进行定位。绝对定位的元素不会占有空间,也不会影响别的元素。
relative相对定位:对象不可层叠、不脱离文档流,参考自身静态位置通过 TBLR定位。设置了TBLR之后,元素位置会发生偏移,但仍然占有原来的位置,且不会影响别的元素,而是覆盖在上方。相对定位与绝对定位的区别就是相对定位是只占有原来的空间,而绝对定位不占有空间。
fixed固定定位:顾名思义,固定定位就是固定在一个位置,不会随着页面滚动而改变位置的定位方式,像常见的页面上的小广告,或者右下角的返回页面顶部等等。
如果要做编辑器,fixed(只有单页了)和static肯定不行。relative不脱离文档流,也不行。那么只能以页面为定位的absolute绝对定位了。这么做有几个缺点:
第一,每个元素都需要精准的TBLR值。这是很麻烦的。甚至需要去计算。
第二:拖拽放大缩小元素的时候,会改变其自身的TBLR值。并且可能会盖到其他元素上面去。我们需要的效果是像果冻一样挤压其他元素。使其挪到后面或下面。
瀑布布局
视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部。
瀑布流的实现方法决定了它的元素排序,具体请看我这篇推文。
瀑布流布局的实现_AI3D_WebEngineer的博客-CSDN博客瀑布流布局视觉表现为参差不齐的多栏布局,随着页面滚动条向下滚动,这种布局还会不断加载数据块并附加至当前尾部 瀑布流的实现方法决定了它的元素排序,具体请看我这篇推文。https://blog.csdn.net/weixin_42274805/article/details/132981042
flex布局
弹性盒模型。也是纯CSS布局。具体可以看廖雪峰的Flex 布局教程:语法篇 - 阮一峰的网络日志https://www.ruanyifeng.com/blog/2015/07/flex-grammar.html
但是做编辑器是不能选择flex布局的,为什么?请看下面Grid布局的介绍
Grid布局
网络布局,目前唯一一种 CSS 二维布局。擅长将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系。
与flex布局的区别:flex 布局是一维布局,Grid 布局是二维布局。flex 布局一次只能处理一个维度上的元素布局,一行或者一列。Grid 布局是将容器划分成了“行”和“列”,产生了一个个的网格,我们可以将网格元素放在与这些行和列相关的位置上,从而达到我们布局的目的。
布局实现
<body><div class="container"><div class="item"><img src="img/bg1.png" alt="" /></div><div class="item"><img src="img/bg2.png" alt="" /></div><div class="item"><img src="img/bg3.png" alt="" /></div><div class="item"><img src="img/bg4.png" alt="" /></div><div class="item"><img src="img/bg5.png" alt="" /></div><div class="item"><img src="img/bg6.png" alt="" /></div></div>
</body>
此时我们只需要对container这个父容器添加grid属性就好:
<style>.container {/* 声明一个容器 */display: grid;/* 声明列的宽度 */grid-template-columns: repeat(3, 200px);/* 声明行间距和列间距 */grid-gap: 20px;/* 声明行的高度 */grid-template-rows: 100px 200px;}.item img {width: 100%;height: 100%;}
</style>
grid-template-columns: repeat(3, 200px);
这里的2是分为3列的意思,200px是列宽
容器
我们通过在元素上声明 display:grid 或 display:inline-grid 来创建一个网格容器。一旦我们这样做,这个元素的所有直系子元素将成为网格项目。比如上面 .container所在的元素为一个网格容器,其直系子元素将成为网格项目。
网格轨道
grid-template-columns 和 grid-template-rows 属性来定义网格中的行和列。容器内部的水平区域称为行,垂直区域称为列。
网格单元
一个网格单元是在一个网格元素中最小的单位
1 2 3 4 5 6 各是一个网络单元
网格线
划分网格的线,称为"网格线"。这对我们来说是不可见的。Grid 会为我们创建编号的网格线来让我们来定位每一个网格元素。m 列有 m + 1 根垂直的网格线,n 行有 n + 1 跟水平网格线。
详细的语法请看:
最强大的 CSS 布局 —— Grid 布局 - 掘金Grid 布局即网格布局,是一种新的 CSS 布局模型,比较擅长将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系。号称是最强大的的 CSS 布局方案,是目前唯一一种 CSS 二维布局。利用 Grid 布局,我们可以轻松实现类似下图布局,演示地址 讲到布局,…https://juejin.cn/post/6854573220306255880
我的选择
Grid布局是最佳选择。因为二维布局提供的网格概念,使得元素的大小和位置可以被合理配置。但是Grid布局的兼容性很一般。考虑到有拖拽和放大缩小功能,且是基于Vue2的项目,我选择了一个网格(栅格)拖拽布局库vue-grid-layout 。他可以完美地实现自定义布局功能。
编辑器页面
这是一个完整的编辑器页面。除开上部的公共导航栏之外。编辑器由左边的组件栏和右边的设计器组成。
组件的设计器设计为弹窗模式。
拖拽、移动的浮窗效果。
dashboard-design.vue:编辑器外壳,通过插槽来插入页面模块
// dashboard-design.vue
<template><div :class="$style.design"><global-header :class="$style.header"><template slot="center"><slot name="header-center" /></template></global-header><slot /></div>
</template>
index.vue:仪表盘编辑器文件
// index.vue<template><dashboard-design-layout:id="$route.params.id">// 头部<dashboard-design-header-centerslot="header-center"/><template><divid="dashboardContent">// 左边的组件列表<a-card:class="$style.controls"><control-list :dragType.sync="dragType" @add="handleClickAddField" /></a-card>// 右边设计器区域<a-card :class="$style.main">....</a-card></div></dashboard-design-layout>
</template>
此时一个简单的编辑机页面结构就出来了,紧接着我们需要给它添加CSS样式
设计器概览
<a-card :class="$style.main">// 按钮<div :class="$style.action"><div :class="$style.actionLeft"><a-button type="link" @click="handlePreview"><x-icon type="tc-icon-search-square" /><span>预览</span></a-button></div><div :class="$style.actionRight"><async-button type="primary" :click="validateAndSave">保存</async-button></div></div>// 设计器<drag-containerref="container":fields="fields":dragType.sync="dragType":selectedField="selectedField":dashboard="form":initFieldStyle="initFieldStyle"@add="handleAdd"@edit="handleEdit"@delete="handleDelete"@select="selectField"/>
</a-card>
我们关注drag-container.vue是怎么样的实现,它一定会有的两个功能:
① 能展示现有的设计布局
② 能自适应拖拽进来的元素,并允许用户自定义它的位置和大小
让我们看看它的实现:
// drag-container.vue
<template><divid="dashboardLayout":style="styleCSSVariable"><background :background="themeBackground"><grid-layoutref="layout":class="$style.layout":layout.sync="layout":colNum="60":rowHeight="15"@dragover.native="handleDrag"@dragleave.native="handleDragLeave"@drop.native="handleDrop">....</grid-layout></background></div>
</template>
可以看到,根元素这里使用了一个名为styleCSSVariable的CSS集。这里的实现是:
get styleCSSVariable() {return createDashboardCSS(this.dashboard.setting.style);
}
这里可以根据当前仪表盘的用户设置风格(如“暗黑”、“科技”、“酷炫”)进行css样式管理。return了诸如这些设置:
return {// 文字颜色'--font': '#cccccc','--font-sub': '#999999','--font-info': '#666666',// 辅助文字'--font-color-secondary': '#aaaaaa',// 提示性文字'--font-color-info': '#ff2d2d','--font-active-light': '#ffffff',// 删除按钮/文字'--delete': '#fe5959',// 警示色'--warning': '#ff9900',// 操作成功'--success': '#19be6b'....
}
可以看到设计器的元素style样式上绑定了一堆颜色定义。这其实就是CSS中的var()函数用法。详情可以看我这篇推文。
CSS的var()函数用法与JS获取css函数变量值的方法_AI3D_WebEngineer的博客-CSDN博客https://blog.csdn.net/weixin_42274805/article/details/133135688?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22133135688%22%2C%22source%22%3A%22weixin_42274805%22%7D 往下看,这里面套了个background的背景板。紧接着是我们的主角。来自于vue-grid-layout插件的grid-layout画布组件。
colNum:画布总共设计为60列
rowHeight:每行高度
:layout.sync="layout" 这里传入的是当前的布局信息
@dragover.native 这里响应的是原生的dragover 事件。拖拉到当前节点上方时,在当前节点上持续触发(相隔几百毫秒)
@dragleave.native
拖拉操作离开当前节点范围时,在当前节点上触发
@drop.native drag 被拖拉的节点或选中的文本,释放到目标节点时,在目标节点上触发
这里为什么要设置三个事件呢?drop响应的是用户放手的事件,dragleave是用户手势离开设计器的时候响应,dragover是用户的手势在设计器里持续响应(刷新状态)。而我们知道,drag原生事件并不只三个:
dragstart:用户开始拖拉时,在被拖拉的节点上触发。
dragend:拖拉结束时(释放鼠标键或按下 ESC 键)在被拖拉的节点上触发。
dragenter:拖拉进入当前节点时,在当前节点上触发一次,该事件的target属性是当前节点。
但这些对于我们设计器来说并无作用。
设计器拖拽部分(一)
大概明白了设计器的拖拽设计,紧接着我们来看最关键的数据结构。
其实很简单,我们只需要传入一个layout-item数组到layout-grid,它就可以正常响应渲染。哪怕数组是乱序的。也就是说layout-grid将严格按照每个layout-item的x/y/w/h进行计算布局
layout-grid是不关注item的max/min-h/w属性的。因为这个事layout-item自己的事情。也就是说layout-grid甚至只是个容器。它接受的item数组是什么样,就会展示什么样。同时它响应上面的拖拽事件,方便我们生成每个layout-item数据。
直接先看@drop.native="handleDrop"部分
/** @name 拖动放置时 **/async handleDrop() {if (this.isInChildCom) return; // 进入子元素范围则无需触发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);} catch (e) {this.layout.splice(this.dragLayoutIndex, 1);throw e;}}/** @name 当前拖拽元素的layout **/dragLayout = null;/** @name 当前拖拽元素的index **/get dragLayoutIndex() {return this.layout.indexOf(this.dragLayout);}
我把代码精简一下,大概是先创建一个拖拽组件的实例(谨慎地用try方法进行尝试,只要中途有抛错就把这个拖拽进来的元素切割掉)。紧接着更新layout。并把新增的组件实例抛出去(做数据存储)。
请注意,this.layout仅仅用于当前页面layout-grid的渲染。不参与数据存储。
编辑器概览
结合一下代码来看看:
// index.vue
<a-card><!-- 左侧组件库--><control-list :dragType.sync="dragType" @add="handleClickAddField" />
</a-card>
<a-card><!-- 左侧设计器--><drag-container:dragType.sync="dragType":selectedField="selectedField"/>
</a-card><script>..../** @name 左边栏拖动时的组件类型 **/dragType = null;
</script>
这里用了sync传值的语法糖。让子组件能够通过emit修改父组件的值。
// control-list.vue<template><div :class="$style.controlList"><divv-for="control in group.list":key="control.type"@dragstart="handleDragStart(control.type, control.draggable)"@dragend="handleDragEnd(control.draggable)"><x-icon :type="control.icon" /><span>{{control.name}}</span></div></div>
</template>...@Prop() dragType;handleDragStart(type, draggable = true) {if (draggable) {this.$emit('update:dragType', type);}
}handleDragEnd(draggable = true) {if (draggable) {this.$emit('update:dragType', null);}
}
control-list.vue这里触发拖拽开始的事件就会emit一个有效的类型值给index.vue,如果拖拽停止就会emit一个空类型值给index。index再通过pro传参给drag-container,这里drag-container为什么也要用sync呢?因为当拖拽放置完成之后,drag-container会把类型值清空,以恢复起始的模式。
// drag-container.vue<template><grid-layout@dragover.native="handleDrag"@dragleave.native="handleDragLeave"@drop.native="handleDrop"><grid-itemv-for="layoutItem in layout":key="layoutItem.i"v-bind="getLayoutProps(layoutItem)"><dash-layout-item@inChildComponent="inChildComponent"><component:is="getComponent(layoutItem)"/><dash-layout-item>/></grid-item></grid-layout>
</template>@Prop() dragType;
我们来看看这个dragType的作用是什么?
/** @name 拖动放置时 **/
async handleDrop() {...try {let field = createDashboardField(this.dragType);} catch {...} finally {this.$emit('update:dragType', null);}
}
第一个作用,在拖拽放置的时候将组件类型传给创建方法。如果为null,则被捕获错误,回滚拖拽操作。不管成功与否,最后finally必须把父组件的dragType置为空以结束流程。
/** @name 左边栏拖动触发 **/@Watch('dragType')handleDragTypeChange(type) {this.isInChildCom = false; // 重新拖动,重置是否在现有组件内部的判断if (type) {// 生成默认的布局item属性this.dragLayout = {i: 'drag',...getDashboardLayoutByType(type),};} else {this.dragLayout = null;}}
第二个作用,观察dragType值。并根据传入的组件类型为其生成默认的布局属性(x,y,w,h)之类。
再来看看
<grid-itemv-for="layoutItem in layout":key="layoutItem.i"v-bind="getLayoutProps(layoutItem)"
><dash-layout-item@inChildComponent="inChildComponent"><component :is="getComponent(layoutItem)"/><dash-layout-item>/>
</grid-item>
这里为什么要套个dash-layout-item,就是为了监控拖拽元素是否已经进入到现有元素。
// dash-layout-item
<template><div@dragenter="dragenter"@dragleave="dragleave"><slot /></div>
</template><script>/** @name 进入-有效目标 **/
dragenter() {this.$emit('inChildComponent', true);
}/** @name 离开-有效目标 **/
dragleave(e) {...this.$emit('inChildComponent', false);
}</script>
相关文章:
讲讲项目里的仪表盘编辑器(一)
需求 要做一个仪表盘系统,要求有: ① 设计功能(包括布局、大小、排列) ② 预览功能 ③ 运行功能 布局选择 做编辑器,肯定要先选择布局。 前端有几种常用布局。 静态布局 也叫文档布局。默认的网页形式…...
解决方案 | 如何构建市政综合管廊安全运行监测系统?
如何构建市政综合管廊安全运行监测系统?WITBEE万宾城市生命线智能监测仪器,5年免维护设计,集成10多项结构与气体健康监测指标,毫秒级快速响应,时刻感知综合管廊运行态势...
JCEF中js与java交互、js与java相互调用
jcef中js与java相互调用,java与js相互调用,chrome与java相互调用,java与chrome相互调用、jcef与java相互调用 前提:https://blog.csdn.net/weixin_44480167/article/details/133170970(java内嵌浏览器CEF-JAVA、jcef、…...
9.20 校招 实习 内推 面经
绿泡*泡: neituijunsir 交流裙 ,内推/实习/校招汇总表格 1、校招丨智行者2024年校园招聘正式启动啦 校招丨智行者2024年校园招聘正式启动啦 2、校招 | 乐动机器人2024校园招聘 校招 | 乐动机器人2024校园招聘 3、校招丨小天才2024届秋季校园招聘 …...
基于JAVA+SpringBoot+Vue+协同过滤算法+爬虫的前后端分离的租房系统
✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取项目下载方式🍅 一、项目背景介绍: 随着城市化进程的加快…...
【Android Framework系列】第16章 存储访问框架 (SAF)
1 概述 Android 4.4(API 级别 19)引入了存储访问框架 (Storage Access Framework)。SAF让用户能够在其所有首选文档存储提供程序中方便地浏览并打开文档、图像以及其他文件。 用户可以通过易用的标准 UI,以统一方式在所有应用和提供程序中浏…...
Antdesign 4中让分页组件居中显示的方法
在Ant Design 4中分页组件默认是最右边显示的,而这个没有设置位置的属性的 解决办法: 在pagination的属性中增加: style: {textAlign: "center"} 在Ant Design 5中可以让pagination使用align: center来实现分页组件居中...
【笔记】ubuntu 20.04 + mongodb 4.4.14定时增量备份脚本
环境 ubuntu 20.04mongodb 4.4.14还没实际使用(20230922)后续到10月底如果有问题会修改 原理 只会在有新增数据时生成新的备份日期目录备份恢复时,如果恢复的数据库未删除,则会覆盖数据 准备 准备一个文件夹,用于…...
c++实现的一个定时器实例
/* * author: hjjdebug * date : 2023年 09月 23日 星期六 11:52:29 CST * description: 用std::thread 实现了一个定时器,深刻理解一下定时器是怎样工作的. * 参考Timer.h, Timer.cpp */ $ cat main.cpp #include "Timer.h" #include <unis…...
Python线程和进程
1、深度解析Python线程和进程 一篇文章带你深度解析Python线程和进程 - 知乎使用Python中的线程模块,能够同时运行程序的不同部分,并简化设计。如果你已经入门Python,并且想用线程来提升程序运行速度的话,希望这篇教程会对你有所帮…...
算法 寻找峰值-(二分查找+反向双指针)
牛客网: BM19 题目: 寻找数组峰值,可能多个返回任一个,每个值满足nums[i] ! nums[i 1] 思路: 双指针 left 0, right n-1, 相向而行,取中间位置mid, nums[mid]与nums[mid1]比较,如果nums[mid] < nums[mid1],说明…...
【数据结构】—交换排序之快速排序究极详解,手把手带你从简单的冒泡排序升级到排序的难点{快速排序}(含C语言实现)
食用指南:本文在有C基础的情况下食用更佳 🔥这就不得不推荐此专栏了:C语言 ♈️今日夜电波:靴の花火—ヨルシカ 0:28━━━━━━️💟──────── 5:03 …...
【c#-Nuget 包“在此源中不可用”】 Nuget package “Not available in this source“
标题c#-Nuget 包“在此源中不可用”…但 VS 仍然知道它吗? (c# - Nuget package “Not available in this source”… but VS still knows about it?) 背景: 今日从公司svn 上拉取很久很久以前的代码,拉取下来200报错,进一步发…...
【数据结构】二叉树之堆的实现
🔥博客主页:小王又困了 📚系列专栏:数据结构 🌟人之为学,不日近则日退 ❤️感谢大家点赞👍收藏⭐评论✍️ 目录 一、二叉树的顺序结构 📒1.1顺序存储 📒1.2堆的性质…...
电工-三极管输入输出特性曲线讲解
三极管特性曲线是反映三极管各电极电压和电流之间相互关系的曲线,是用来描述晶体三极管工作特性曲线,常用的特性曲线有输入特性曲线和输出特性曲线。这里以下图所示的共发射极电路来分析三极管的特性曲线。 输入特性曲线 该曲线表示当e极与c极之间的电…...
深入解析容器与虚拟化:技术、对比与生态
深入解析容器与虚拟化:技术、对比与生态 文章目录 深入解析容器与虚拟化:技术、对比与生态容器和虚拟化的基本概念和原理容器的定义和特点虚拟化的定义和特点 容器使用场景容器和虚拟机的对比虚拟化技术的四个特点容器实现虚拟化的原理常见容器引擎和容器…...
制作游戏demo的心得
制作这个游戏demo出来的心得 https://www.bilibili.com/video/BV1cF411m7Dh/ 制作游戏demo的心得 制作游戏demo,主要是为了表现自己的技术,那就一门心思想着如何提高表现力就行了,在整体的画面渲染风格方面或许没有什么可选择的,…...
Web Tour Server窗口闪现
1.打开该文件所在位置 2.右击选择编辑,在最后一行加上pause,保存后重新打开Server窗口 3.重新打开后,若出现以下情况: 以管理员身份打开cmd命令行,输入命令netstat -aon|findstr “1080”,查看1080端口占用…...
Linux下的基本指令
目录 01. ls 指令 02. pwd命令 03. cd 指令 04. touch指令 05.mkdir指令(重要): 06.rmdir指令 && rm 指令(重要): 07.man指令(重要): 08mv指令ÿ…...
随机数生成器代码HTML5
代码如下 <!DOCTYPE html> <html> <head> <title>随机数生成器</title> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <style> body { text-align: center; bac…...
正确理解redux Toolkits中createSlice的action.payload
使用redux Toolkits中的createSlice编写extraReducers经常看到使用action.payload来更新state状态值: 那么action.payload指的到底是什么? 让我们看看action的定义部分: 注意: action.payload不是上面ajax请求的返回内容&#x…...
YOLOv8快速复现 官网版本 ultralytics
YOLOV8环境安装教程.:https://www.bilibili.com/video/BV1dG4y1c7dH/ YOLOV8保姆级教学视频:https://www.bilibili.com/video/BV1qd4y1L7aX/ b站视频:https://www.bilibili.com/video/BV12p4y1c7UY/ 1 平台搭建YOLOv8 平台:https://www.a…...
Haproxy搭建 Web 群集实现负载均衡
目录 1 Haproxy 1.1 HAProxy的主要特性 1.2 HAProxy负载均衡策略 1.3 LVS、Nginx、HAproxy的区别 2 Haproxy搭建 Web 群集 2.1 haproxy 服务器部署 2.1.1 关闭防火墙 2.1.2 内核配置(实验环境可有可无) 2.1.3 安装 Haproxy 2.1.4 Haproxy服务…...
Tessy 5.0.4
Tessy 5.0.4 Linux 2692407267qq.com,更多内容请见http://user.qzone.qq.com/2692407267/...
mybatis-plus根据指定条件批量更新
1.service实现类中 比如我这里只针对UserEntity,在UserServiceImpl下(该实现类是继承了mybatis-plus的ServiceImpl的)新增如下代码: public boolean updateBatchByQueryWrapper(Collection<UserEntity> entityList, Funct…...
虹科方案 | LIN/CAN总线汽车零部件测试方案
文章目录 摘要一、汽车零部件测试的重要性?二、虹科的测试仿真工具如何在汽车零部件测试展露头角?三、应用场景**应用场景1:方向盘开关的功能测试****应用场景2:各类型电机的控制测试****应用场景3:RGB氛围灯的功能测试…...
[solidity]合约调用合约
先写一个简单的合约将其部署,部署后的合约地址为:0xd9145CCE52D386f254917e481eB44e9943F39138 // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;contract A{string myname;function setName(string memory _name) public{myname_name;}functi…...
Vulnhub系列靶机---JANGOW 1.0.1
文章目录 网卡配置信息收集主机发现端口扫描 漏洞利用反弹Shell提权 靶机文档:JANGOW 1.0.1 下载地址:Download (Mirror) 难易程度:. 网卡配置 水果味儿 信息收集 主机发现 端口扫描 访问80端口 点击site目录 点击页面上方的一个选项&…...
肖sir__项目环境之全流程__005
一、测试流程(h模型) 1、需求文档(产品) 需求文档(软件需求规格说明书srs) (1)如何分析需求 a、显示需求(主流程、功能,业务) b、隐性需求&#x…...
搜狗输入法下键翻页
搜狗输入法下键翻页 从官网下载 搜狗输入法智慧版关闭超级候选关闭候选...
找作文做读书笔记去什么网站/合肥头条今日头条新闻最新消息
给你两个长度相等的整数数组,返回下面表达式的最大值: |arr1[i] - arr1[j]| |arr2[i] - arr2[j]| |i - j| 其中下标 i,j 满足 0 < i, j < arr1.length。 示例 1: 输入:arr1 [1,2,3,4], arr2 [-1,4,5,6] 输…...
linux下网站开发/广点通广告平台
保定市竞秀区委宣传部17日透露,该区一企业将在保定范围投放10000台集商品售卖、信息传播和大数据采集等功能于一体的智能自动售货机。 据保定和金创业空间总经理李强介绍,在“互联网+”时代,智能自动售货机被称为“永不下班的超级…...
网站开发毕业论文任务书/seo技术培训岳阳
经过前面22小节,我们已经将自己的博客网站搭建完成了,但是只能在本机通过127.0.0.1:8000进行访问,那么如何才能够让别人通过登录自己的网站,在外网也能够访问自己的博客呢?为了完成这个目的,我们需要做如下…...
贵阳的网站建设公司/长沙seo推广外包
在IOS开发中,要做字典转模型一般情况如下: 1 /**2 * 声明方法3 */4 - (instancetype) initWithDictionary:(NSDictionary *)dict;5 (instancetype) carWithDictionary:(NSDictionary *)dict;6 7 /**8 * 实现方法9 */ 10 - (instancetype)initWith…...
产品的seo是什么意思/seo外链发布软件
1.当自变量的数值确定后,因变量的数值也随之完全确定,这种关系属于()。 A.相关关系 B.函数关系 C.回归关系 D.无关 2.对某地区工业企业职工情况进行研究,统计总体是() A.每个工业企业 B.该地…...
在哪个网站上做兼职比较好/百度收录时间
企业实施MES系统前的6大难点MES是企业生产管理服务的核心信息化系统。实施MES是为了将现代企业生产管理思想、理念引入企业生产管理,对企业生产管理流程进行重组和优化,促进企业生产管理水平的提高。但是大多数制造企业在考虑MES时会遇到很多难点&#x…...