VisualDrag低代码拖拽模板

news2024/12/23 18:12:54

目录

  • 背景
  • 技术&文档
  • 二开优化方案
    • 1. 优化侧边栏
    • 2. 优化图片插入
    • 3. 新增可插入画布的组件
    • 4. 解决组件鼠标默认事件冲突的问题
  • 数据保存对接&页面生成预览
    • 保存对接
    • 生成预览
  • 源码下载

背景

在这里插入图片描述

接到一个需求做一个拖拽模板低代码生成界面(如上图),就是可以自定义界面元素拖拽生成页面,该页面需要可以存储,并且一比一还原。

因此得研究实现一个拖拽生成低代码平台,通过查询了各种资料,找到了以下比较合适的开源的低代码平台:

  1. visual-drag-demo:https://github.com/woai3c/visual-drag-demo
  2. 拖拽大屏:https://gitee.com/gist006/vue-visual-drag
  3. 专题制作工具:https://gitee.com/Maxfengyan/visual-drag
  4. GoView低代码数据可视化:https://www.mtruning.club/
  5. 鲁班H5:https://ly525.gitee.io/luban-h5/zh/
  6. quark-h5: https://github.com/huangwei9527/quark-h5

根据自己的需求,选择了visual-drag-demo为模板进行了二开。

在线预览:
预览地址:https://qkongtao.gitee.io/visual-drag-demo
在这里插入图片描述

最后集成在后台系统中:
在这里插入图片描述

技术&文档

使用到的技术功能点:

  1. 编辑器
  2. 自定义组件(文本、图片、矩形、圆形、直线、星形、三角形、按钮、表格、组合)
  3. 接口请求(通过接口请求组件数据)
  4. 组件联动
  5. 拖拽
  6. 删除组件、调整图层层级
  7. 放大缩小
  8. 撤消、重做
  9. 组件属性设置
  10. 吸附
  11. 预览、保存代码
  12. 绑定事件
  13. 绑定动画
  14. 拖拽旋转
  15. 复制粘贴剪切
  16. 多个组件的组合和拆分
  17. 锁定组件
  18. 网格线

可以参考原作者大大的文档:
可视化拖拽组件库一些技术要点原理分析(一):https://github.com/woai3c/Front-end-articles/issues/19
可视化拖拽组件库一些技术要点原理分析(二):https://github.com/woai3c/Front-end-articles/issues/20
可视化拖拽组件库一些技术要点原理分析(三):https://github.com/woai3c/Front-end-articles/issues/21
可视化拖拽组件库一些技术要点原理分析(四):https://github.com/woai3c/Front-end-articles/issues/22

在作者的这几篇文章中把技术点介绍的很详细,虽然还是有很多不懂的,,,

二开优化方案

由于个人的能力有限,只能在作者的基础上优化成满足自己需求的拖拽模板

1. 优化侧边栏

修改侧边栏的样式
src\components\ComponentList.vue

<template>
  <div class="component-list" @dragstart="handleDragStart">
    <div
      v-for="(item, index) in componentList"
      :key="index"
      class="list"
      draggable
      :data-index="index"
    >
      <span class="iconfont" :class="'icon-' + item.icon"></span>
      <span class="btn_name">{{ item.label }}</span>
    </div>
  </div>
</template>

<script>
import componentList from "@/custom-component/component-list";

export default {
  data() {
    return {
      componentList,
    };
  },
  methods: {
    handleDragStart(e) {
      e.dataTransfer.setData("index", e.target.dataset.index);
    },
  },
};
</script>

<style lang="scss" scoped>
.component-list {
  width: 200px;
  height: 55%;
  margin: 10px auto 0;
  display: grid;
  grid-gap: 10px 30px;
  grid-template-columns: repeat(auto-fill, 66px);
  grid-template-rows: repeat(auto-fill, 56px);

  .list {
    width: 66px;
    height: 56px;
    border: 1px solid #ddd;
    cursor: grab;
    text-align: center;
    color: #333;
    // background-color: #f3f3f3;
    border-radius: 8px;
    box-shadow: rgb(168 168 168 / 30%) 0px 2px 4px 0px;
    padding: 2px 5px;
    margin-left: 20px;

    &:active {
      cursor: grabbing;
    }

    .iconfont {
      display: block;
      font-size: 24px;
      margin-top: 3px;
      margin-bottom: 0px;
    }

    .icon-wenben,
    .icon-biaoge {
      font-size: 24px;
    }

    .icon-tupian {
      font-size: 24px;
    }
    .btn_name {
      font-size: 10px;
      line-height: 20px;
      color: rgb(31, 62, 104);
      width: 56px;
      padding: 0px 5px;
      word-break: keep-all;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
  }
}
</style>

src\components\RealTimeComponentList.vue

<template>
  <div class="real-time-component-list">
    <div
      v-for="(item, index) in componentData"
      :key="index"
      class="list"
      :class="{ actived: transformIndex(index) === curComponentIndex }"
      @click="onClick(transformIndex(index))"
    >
      <span class="iconfont" :class="'icon-' + getComponent(index).icon"></span>
      <span class="label">{{ getComponent(index).label }}</span>
      <div class="icon-container">
        <span
          class="iconfont icon-shangyi"
          @click="upComponent(transformIndex(index))"
        ></span>
        <span
          class="iconfont icon-xiayi"
          @click="downComponent(transformIndex(index))"
        ></span>
        <span
          class="iconfont icon-shanchu"
          @click="deleteComponent(transformIndex(index))"
        ></span>
      </div>
    </div>
  </div>
</template>

<script>
import { mapState } from "vuex";

export default {
  computed: mapState(["componentData", "curComponent", "curComponentIndex"]),
  methods: {
    getComponent(index) {
      return this.componentData[this.componentData.length - 1 - index];
    },

    transformIndex(index) {
      return this.componentData.length - 1 - index;
    },

    onClick(index) {
      this.setCurComponent(index);
    },

    deleteComponent() {
      setTimeout(() => {
        this.$store.commit("deleteComponent");
        this.$store.commit("recordSnapshot");
      });
    },

    upComponent() {
      setTimeout(() => {
        this.$store.commit("upComponent");
        this.$store.commit("recordSnapshot");
      });
    },

    downComponent() {
      setTimeout(() => {
        this.$store.commit("downComponent");
        this.$store.commit("recordSnapshot");
      });
    },

    setCurComponent(index) {
      this.$store.commit("setCurComponent", {
        component: this.componentData[index],
        index,
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.real-time-component-list {
  height: 45%;

  .list {
    height: 50px;
    cursor: grab;
    text-align: center;
    color: #333;
    background-color: #f3f3f3;
    display: flex;
    align-items: center;
    font-size: 12px;
    padding: 0 15px;
    position: relative;
    user-select: none;

    &:active {
      cursor: grabbing;
    }

    &:hover {
      background-color: #d2d2d2;

      .icon-container {
        display: block;
      }
    }

    .label {
      font-size: 16px;
      margin-left: 5px;
    }
    .iconfont {
      margin-right: 5px;
      font-size: 30px;
    }

    .icon-shangyi,
    .icon-xiayi,
    .icon-shanchu {
      font-size: 28px;
      margin-right: 0px;
    }

    .icon-wenben,
    .icon-tupian {
      font-size: 28px;
    }

    .icon-container {
      position: absolute;
      right: 10px;
      display: none;

      .iconfont {
        cursor: pointer;
      }
    }
  }

  .actived {
    background: #ecf5ff;
    color: #409eff;
  }
}
</style>

2. 优化图片插入

插入图片时的大小优化(插入图片分辨率过大时自定义缩放图片)
src\components\Toolbar.vue
修改 handleFileChange(e) 方法

handleFileChange(e) {
      const file = e.target.files[0];
      if (!file.type.includes("image")) {
        toast("只能插入图片");
        return;
      }

      const reader = new FileReader();
      reader.onload = (res) => {
        const fileResult = res.target.result;
        const img = new Image();
        img.onload = () => {
          const component = {
            ...commonAttr,
            id: generateID(),
            component: "Picture",
            label: "图片",
            icon: "",
            propValue: {
              url: fileResult,
              flip: {
                horizontal: false,
                vertical: false,
              },
            },
            style: {
              ...commonStyle,
              top: 0,
              left: 0,
              width:
                img.width > 1000
                  ? img.width * 0.3
                  : img.width < 300
                  ? img.width
                  : img.width * 0.5,
              height:
                img.width > 1000
                  ? img.height * 0.3
                  : img.width < 300
                  ? img.height
                  : img.height * 0.5,
            },
          };

          // 根据画面比例修改组件样式比例
          changeComponentSizeWithScale(component);

          this.$store.commit("addComponent", { component });
          this.$store.commit("recordSnapshot");

          // 修复重复上传同一文件,@change 不触发的问题
          $("#input").setAttribute("type", "text");
          $("#input").setAttribute("type", "file");
        };

        img.src = fileResult;
      };

      reader.readAsDataURL(file);
    },

3. 新增可插入画布的组件

可以在通过自定义封装组件,插入画布,因为在demo中,新增了几个常用的组件:

  • 音频
  • 视频
  • 浏览器

新增步骤如下:
1). 在 src\custom-component 目录下新建需要新增的组件文件夹
2). 在该文件夹下面新建两个vue文件Component.vue、Attr.vue(示例浏览器):
Component.vue
组件的具体代码内容

<template>
  <div style="overflow: hidden">
    <div class="iframe-container">
      <iframe
        name="myiframe"
        id="myiframe"
        :src="propValue.url"
        align="center"
        frameborder="0"
        allowfullscreen
      >
        <p>你的浏览器不支持iframe标签</p>
      </iframe>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    propValue: {
      type: Object,
      require: true,
      default: "",
    },
    element: {
      type: Object,
      default: () => {},
    },
  },
  methods: {},
};
</script>

<style lang="scss" scoped>
.iframe-container {
  width: 100%;
  height: 100%;
  position: relative;
}
.iframe-container iframe {
  // pointer-events: none;
  position: absolute;
  left: 0;
  top: 0;
  margin: 0px;
  width: 100%;
  height: 100%;
}
</style>

Attr.vue
组件的侧边栏动态功能(修改浏览器链接、上传文件等)

<template>
  <div class="attr-list">
    <CommonAttr></CommonAttr>
    <el-form>
      <el-form-item label="网址链接">
        <el-input
          v-model="curComponent.propValue.url"
          type="textarea"
          :rows="3"
          style="clear: both"
        />
      </el-form-item>
    </el-form>
  </div>
</template>

<script>
import CommonAttr from "@/custom-component/common/CommonAttr.vue";

export default {
  components: { CommonAttr },
  computed: {
    curComponent() {
      return this.$store.state.curComponent;
    },
  },
};
</script>

3). 在 src\custom-component\component-list.js组件列表中添加对应的组件信息
注意组件名称等信息要对应刚刚建立组件的名称

// 编辑器左侧组件列表
const list = [{
	... ...
 	... ...
 	... ...
{
        component: 'Browser',
        label: '浏览器',
        icon: 'hulianwang',
        propValue: {
            url: "https://mytab.qkongtao.cn/",
            flip: {
                horizontal: false,
                vertical: false,
            },
        },
        style: {
            width: 325,
            height: 560,
        },
 },
 	... ...
 	... ...
 	... ...
 }]

4). 封装完成后,即可以在页面中看到新增的组件

4. 解决组件鼠标默认事件冲突的问题

在插入audio 和 iframe等组件时,在画布上的拖拽失效,原因时鼠标事件和audio、iframe标签的原有事件冲突,外部无法对iframe内部进行操作。因此采用默认禁止有鼠标事件冲突组件的鼠标事件,等到预览展示时恢复鼠标事件。

使用css禁止元素的鼠标事件
pointer-events: none;

在src\components\Editor\index.vue 页面组件列表展示设置对应组件的样式 pointer-events: none;进行控制组件是否可以拖拽。
在src\components\Editor\ComponentWrapper.vue 预览或者导出的时候需要设置对应组件的样式style:pointer-events: auto; 恢复该组件原有的鼠标事件

src\components\Editor\index.vue

	... ...
 	... ...
 	... ...

<!--页面组件列表展示-->
    <Shape
      v-for="(item, index) in componentData"
      :key="item.id"
      :default-style="item.style"
      :style="getShapeStyle(item.style)"
      :active="item.id === (curComponent || {}).id"
      :element="item"
      :index="index"
      :class="{ lock: item.isLock }"
    >
      <component
        :is="item.component"
        v-if="item.component.startsWith('SVG')"
        :id="'component' + item.id"
        :style="getSVGStyle(item.style)"
        class="component"
        :prop-value="item.propValue"
        :element="item"
        :request="item.request"
      />
      <component
        :is="item.component"
        v-else-if="item.component == 'VText'"
        :id="'component' + item.id"
        class="component"
        :style="getComponentStyle(item.style)"
        :prop-value="item.propValue"
        :element="item"
        :request="item.request"
        @input="handleInput"
      />

      <component
        :is="item.component"
        v-else-if="item.component == 'Video'"
        :id="'component' + item.id"
        class="component"
        :style="getComponentStyle(item.style)"
        :prop-value="item.propValue"
        :element="item"
        :request="item.request"
      />

      <component
        :is="item.component"
        v-else
        :id="'component' + item.id"
        class="component"
        :style="getComponentStyle(item.style)"
        :prop-value="item.propValue"
        :element="item"
        :request="item.request"
        style="pointer-events: none"
      />
    </Shape>

src\components\Editor\ComponentWrapper.vue

<template>
  <div @click="onClick" @mouseenter="onMouseEnter">
    <component
      :is="config.component"
      v-if="config.component.startsWith('SVG')"
      ref="component"
      class="component"
      :style="getSVGStyle(config.style)"
      :prop-value="config.propValue"
      :element="config"
      :request="config.request"
      :linkage="config.linkage"
    />
    <component
      :is="config.component"
      v-if="
        config.component.startsWith('Music') ||
        config.component.startsWith('Browser')
      "
      ref="component"
      class="component"
      :style="getSVGStyle(config.style)"
      :prop-value="config.propValue"
      :element="config"
      :request="config.request"
      :linkage="config.linkage"
      style="pointer-events: auto !important"
    />

    <component
      :is="config.component"
      v-else
      ref="component"
      class="component"
      :style="getStyle(config.style)"
      :prop-value="config.propValue"
      :element="config"
      :request="config.request"
      :linkage="config.linkage"
    />
  </div>
</template>

数据保存对接&页面生成预览

保存对接

本项目中在记录和传递数据中频繁的使用vuex,最后保存的数据为:
画布数据:this.$store.state.canvasStyleData;
画布内容数据:this.$store.state.componentData;
保存示例如下:

{
	"canvasStyleData": {
		"width": 1280,
		"height": 720,
		"scale": 90,
		"color": "#000",
		"opacity": 1,
		"background": "#fff",
		"fontSize": 14
	},
	"componentData": [{
		"animations": [],
		"events": {},
		"groupStyle": {},
		"isLock": false,
		"collapseName": "style",
		"linkage": {
			"duration": 0,
			"data": [{
				"id": "",
				"label": "",
				"event": "",
				"style": [{
					"key": "",
					"value": ""
				}]
			}]
		},
		"component": "Picture",
		"label": "图片",
		"icon": "charutupian",
		"propValue": {
			"url": "http://localhost:8000/api/files/getImage/5865ef7d990e40a88a08ceca3e7c118c",
			"flip": {
				"horizontal": false,
				"vertical": false
			}
		},
		"style": {
			"rotate": 0,
			"opacity": 1,
			"width": 270,
			"height": 180,
			"borderRadius": "",
			"top": 89,
			"left": 72
		},
		"id": "fcn3XAGtR50D_JcImnBbc"
	}, {
		"animations": [],
		"events": {},
		"groupStyle": {},
		"isLock": false,
		"collapseName": "style",
		"linkage": {
			"duration": 0,
			"data": [{
				"id": "",
				"label": "",
				"event": "",
				"style": [{
					"key": "",
					"value": ""
				}]
			}]
		},
		"component": "Video",
		"label": "视频",
		"icon": "shipin",
		"propValue": {
			"url": "https://qiniu.qkongtao.cn/2022/10/20221016134256839.mp4?_\u003d1",
			"flip": {
				"horizontal": false,
				"vertical": false
			}
		},
		"style": {
			"rotate": 0,
			"opacity": 1,
			"width": 360,
			"height": 270,
			"top": 89,
			"left": 722
		},
		"id": "1HqDupYn-KA-1Xl4gorHA"
	}, {
		"animations": [],
		"events": {},
		"groupStyle": {},
		"isLock": false,
		"collapseName": "style",
		"linkage": {
			"duration": 0,
			"data": [{
				"id": "",
				"label": "",
				"event": "",
				"style": [{
					"key": "",
					"value": ""
				}]
			}]
		},
		"component": "Browser",
		"label": "浏览器",
		"icon": "hulianwang",
		"propValue": {
			"url": "https://qkongtao.cn/",
			"flip": {
				"horizontal": false,
				"vertical": false
			}
		},
		"style": {
			"rotate": 0,
			"opacity": 1,
			"width": 397,
			"height": 265,
			"top": 352,
			"left": 63
		},
		"id": "DyIYmOGLRgUt1iKCuoloC"
	}, {
		"animations": [],
		"events": {},
		"groupStyle": {},
		"isLock": false,
		"collapseName": "style",
		"linkage": {
			"duration": 0,
			"data": [{
				"id": "",
				"label": "",
				"event": "",
				"style": [{
					"key": "",
					"value": ""
				}]
			}]
		},
		"component": "CircleShape",
		"label": "圆形",
		"propValue": "\u0026nbsp;",
		"icon": "24gl-circle",
		"style": {
			"rotate": 0,
			"opacity": 1,
			"width": 180,
			"height": 180,
			"fontSize": "",
			"fontWeight": 400,
			"lineHeight": "",
			"letterSpacing": 0,
			"textAlign": "center",
			"color": "rgba(213, 148, 27, 1)",
			"borderColor": "rgba(110, 204, 17, 1)",
			"borderWidth": 10,
			"backgroundColor": "rgba(186, 104, 104, 1)",
			"borderStyle": "solid",
			"borderRadius": "",
			"verticalAlign": "middle",
			"top": 188,
			"left": 497
		},
		"id": "hOIKf550JqWwA1uM3KGtD"
	}]
}

如果需要对接后端,记录canvasStyleData、componentData即可。

生成预览

本项目中有一个页面预览的封装组件
src\components\Editor\Preview.vue
预览的方案就是先根据画布数据(canvasStyleData)新建一个总container,然后在该container中遍历组件数据(componentData),然后通过component组件和is属性实现动态组件的渲染还原。
在这里插入图片描述

源码下载

源码链接:https://gitee.com/qkongtao/visual-drag-demo

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/23529.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

项目交付过程中,进度失控的原因有哪些?

在项目交付过程中&#xff0c;会出现项目交付的进度与计划有较大的偏差&#xff0c;导致这种偏差的原因往往是多种多样的&#xff0c;一般常见的引起进度延期的原因有哪些&#xff1f; 1、计划不清晰 项目开始前必须有个计划&#xff0c;工作思路必须事前理清。 项目经理最…

springboot+ssm大学生家教课程订购平台的设计与实现

制作一个大学生家教平台的设计与实现是非常必要的。本网站是借鉴其他人的开发基础上&#xff0c;用MySQL数据库和JSP定制了大学生家教平台的设计与实现。系统前台实现了用户注册、登录、学习课程、家教准则、通知公告、双减政策等功能&#xff0c;并且还可以修改密码、个人信息…

windows10复制文件需要管理员权限,复制需要管理员权限怎么办

在Windows10操作系统的电脑中&#xff0c;很多用户都遇到这样的问题&#xff1a;windows10复制文件需要管理员权限&#xff0c;很多用户都不知道该怎么解决这个问题。在本文中&#xff0c;我们写出了详细的解决方法&#xff0c;让你可以轻松复制文件&#xff0c;并且也修复了需…

SpringBoot中任务是什么/Quartz和SpringTask在Spring Boot中怎么使用/SpringBoot怎么给用户发邮件

写在前面&#xff1a; 继续记录自己的SpringBoot学习之旅&#xff0c;这次是SpringBoot应用相关知识学习记录。若看不懂则建议先看前几篇博客&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 3.5.2 任务 3.5.2.1 简述 定时任务是企业应用中常…

多种BCN点击试剂:1426827-79-3,endo BCN-PEG4-COOH,1841134-72-2

双环[6,1,0]壬炔 (BCN) &#xff08;环丙烷环辛炔&#xff09;可以通过无铜的点击化学与叠氮化物标记的分子或生物分子反应生成稳定的三氮唑连接。同样其可以和多种不同的基团进行连接&#xff0c;包括acid&#xff0c;NHS ester&#xff0c;amine等。西安凯新生物科技有限公司…

Oracle SQL执行计划操作(7)——排序相关操作

7. 排序相关操作 该类操作和SQL语句执行计划中的排序操作相关。根据不同的具体SQL语句及其他相关因素&#xff0c;如下各操作可能会出现于相关SQL语句的执行计划。 1&#xff09;BUFFER SORT 在会话服务进程内存中对某个行源数据进行排序或其他相关操作&#xff0c;该操作最…

Vue高级篇--实现前后端分离

目录 一、安装Nodejs服务器 二、安装Npm 三、安装vue脚手架 四、使用vue脚手架搭建vue工程 五、vue工程安装需要的插件和依赖 六、安装前端的开发工具 七、使用webstorm打开vue工程 7.1 运行vue工程 八、src目录结构的介绍 一、安装Nodejs服务器 等价于我们java端的Tomcat服务…

聊聊自制的探索大全扑克牌

这是鼎叔的第四十篇原创文章。 行业大牛和刚毕业的小白&#xff0c;都可以进来聊聊。 欢迎关注本人专栏和微信公众号《敏捷测试转型》&#xff0c;大量原创思考文章陆续推出。 这是鼎叔的第四十篇原创文章。 行业大牛和刚毕业的小白&#xff0c;都可以进来聊聊。 欢迎关注…

Oracle中ALTER TABLE的五种用法(一)

首发微信公众号&#xff1a;SQL数据库运维 原文链接&#xff1a;https://mp.weixin.qq.com/s?__bizMzI1NTQyNzg3MQ&mid2247485212&idx1&sn450e9e94fa709b5eeff0de371c62072b&chksmea37536cdd40da7a94e165ce4b4c6e70fb1360d51bed4b3566eee438b587fa231315d0a5a…

(必经点)局部优化达到全局最优的最短路径算法探讨

首先&#xff0c;存在无序的点集. 记. 再记初始路径为. 于是&#xff0c;我们称以下为一次变换&#xff1a; if |C[i]-C[i1]||C[i2]-C[i3]| > |C[i]-C[i2]||C[i1]-C[i3]| {swap(C[i1],C[i2]); } 需要注意的是. 最直观的就是如下的变换&#xff1a; 我们对C上的每一点&a…

论文阅读【3】Efficient Estimation of Word Representations in Vector Space

1.概述 1.1 论文相关 题目&#xff1a;基向量空间中词表示的有效估计&#xff08;Efficient Estimation of Word Representations in Vector Space&#xff09;发表时间&#xff1a;出版&#xff1a;原文地址&#xff1a;代码 1.2 动机 2.对比模型 2.1 NNLM&#xff08;前…

表单控件绑定:checkbox表单绑定v-model

表单checkbox&#xff0c;绑定的v-model是一个布尔值&#xff0c;要么为true&#xff0c;要么为false&#xff1b;因为它是勾选&#xff0c;或者不勾选的形式&#xff1b;为true了就是勾选&#xff0c;为false了就是不勾选&#xff1b; 代码&#xff1a; <body><div …

Vue-cli3 通过配置 public 目录下的 config.js 和config.json 实现一次编译,修改生效

文章目录1.背景2.配置步骤3.小结1.背景 最近实施部门&#xff0c;有个需求就是研发人员通过vue 写完代码&#xff0c;yarn build 编译完成代码后&#xff0c;移交实施&#xff0c;通过修改public 文件夹下的 config 文件来实现修改&#xff0c;请求后台的 requestUrl 和 titil…

day10 分布式缓存

单机的 Redis 存在以下四大问题&#xff1a; 1、Redis持久化 Redis有两种持久化方案&#xff1a; RDB 持久化AOF 持久化 1.1、RDB 持久化 RDB 全称 Redis Database Backup file&#xff08;Redis数据备份文件&#xff09;&#xff0c;也被叫做 Redis 数据快照。简单来说就是把…

《500强高管谈VE》-面向STAKEHOLDERS东方企业的VM

文章出处&#xff1a;日本VE协会杂志文章翻译&#xff1a;泰泽项目部 关注泰泽&#xff1a;实现高利润企业 《500强高管谈VE》-面向STAKEHOLDERS东方企业的VM 作者&#xff1a;常务董事八木隆 本公司的日高工厂和丰浦工厂两个事业所获得了迈尔斯奖。这些都是支持企业活动的V…

无代码开发平台选型指南

一、如何选购SaaS SaaS评测网的面世&#xff0c;也原因在于有感于选型难于&#xff0c;期望可以提供更多有用的信息协助大家找出更可信赖与最合适的产品。简而言之授之以鱼、比不上授之以渔&#xff0c;接下来的系列产品该文&#xff0c;则是撷取选型的方法及避坑实战经验。 …

【大数据处理技术】第二篇 大数据存储与管理(持续更新)

文章目录第3章 分布式文件系统HDFS3.1 分布式文件系统3.1.1 计算机集群结构3.1.2 分布式文件系统的结构3.1.3 分布式文件系统的设计需求3.2 HDFS3.2.1 HDFS 简介及相关概念3.2.2 HDFS 体系结构3.2.3 HDFS 存储原理3.2.4 HDFS 数据读写过程3.2.5 HDFS 编程实践第4章 分布式数据库…

独立产品灵感周刊 DecoHack #038 - 纽约市 90 年代的街景长什么样

本周刊记录有趣好玩的独立产品设计开发相关内容&#xff0c;每周发布&#xff0c;往期内容同样精彩&#xff0c;感兴趣的伙伴可以点击订阅我的周刊。为保证每期都能收到&#xff0c;建议邮件订阅。欢迎通过 Twitter 私信推荐或投稿。产品推荐 1. 1940s.nyc - 这个网站可以看到…

Python版本机访问GEE,CoLab配置

一、本机Jupyter notebook访问GEE 首先感谢知乎这两篇文章提供的解决思路&#xff1a; Python版GEE学习笔记&#xff08;一&#xff09;-环境配置 - 知乎 GEE之Python学习——前期准备工作 - 知乎 前期尝试解决&#xff1a; 1. Anaconda 安装&#xff0c;重新创建虚拟环境…

2021年度聚合支付评级如何?

截至2022年11月15日&#xff0c;完成收单外包服务备案机构为15041家&#xff0c;其中含聚合支付类型的机构为481家。 2022年11月15日&#xff0c;中国支付清算协会正式发布了2021年度收单外包服务机构评级等级消息。显示共有包括银行和非银行支付机构在内的143家收单机构对958…