el-tree组件展示节点过多时造成页面卡顿、奔溃的解决办法

2023-11-09

解决el-tree组件展示节点过多时造成页面卡顿、奔溃

前几天测试提了个BUG,文件列表展示5w个文件页面会卡顿甚至奔溃。
项目用的是vue+element-ui框架,我是使用el-tree进行渲染文件列表的。
参考网上使用virtual-scroll-list插件与el-tree源码写成一个新组件。virtual-scroll-list可以只渲染页面呈现部分的节点,这样就不会造成卡顿了,源el-tree是直接将5w个节点直接渲染到页面,导致页面奔溃。
这是使用virtual-scroll-list插件与el-tree源码结合后的组件:github组件下载gitee组件下载
组件使用方法(传入的属性)与el-tree一致,可根据自己的业务需求更改,我做的需求只是进行文件导出。
组件使用示例:

<virtualNodeTree
      ref="dirTree"
      :data.sync="treeData"
      :load="loadDir"
      :keeps="50"
      :check-strictly="false"
      :props="{
        isLeaf: 'leaf'
      }"
      lazy
      show-checkbox
      node-key="path"
      class="treeWrap"
      @check-change="handleCheckChange">
      <span slot-scope="{ data }">
        <svg-icon v-if="data.ftype === '1'" style="color: #fdd300;" icon-class="faFolder"/>
        <span v-else>
          <svg-icon :icon-class="fileInputHandle(data).icon" :style="{color: fileInputHandle(data).color}"/>
        </span>
        <span>{{ data.fname }}</span>
      </span>
    </virtualNodeTree>

组件引入:
在这里插入图片描述

效果图:
请添加图片描述

more文件下面有5w个文件,实际页面渲染50个文件,根据组件传入的keeps展示文件数,默认30个;
注意:
1.搜索只能搜到已渲染的节点,可以自己做递归搜索源数据,不过这样的话数据一多会很卡,建议后端写个搜索api
2.该组件的父容器一定要确定高度,不能以整个body作为父容器,这样有可能滚动时渲染不出下面的文件。

补充:
我使用的完整代码

<template>
  <div class="app-container">
    <div>
      <el-button
        class="ame-button"
        size="mini"
        type="primary"
        @click="exportHandle"
        :loading="exportLoading"
        :disabled="exportLoading"
      >导出
      </el-button>
    </div>
    <virtualNodeTree
      v-loading="loading"
      ref="dirTree"
      :data.sync="treeData"
      :load="loadDir"
      :keeps="50"
      :check-strictly="false"
      :props="{
        isLeaf: 'leaf'
      }"
      lazy
      show-checkbox
      node-key="path"
      class="treeWrap"
      @check="handleNodeCheck"
    >
      <span slot-scope="{ data }">
        <svg-icon v-if="data.ftype === '1'" style="color: #fdd300;" icon-class="faFolder"/>
        <span v-else>
          <svg-icon :icon-class="fileInputHandle(data).icon" :style="{color: fileInputHandle(data).color}"/>
        </span>
        <span>{{ data.fname }}</span>
      </span>
    </virtualNodeTree>
    <!--
    <el-tree
      ref="dirTree"
      :data.sync="treeData"
      :load="loadDir"
      :check-strictly="false"
      :props="{
        isLeaf: 'leaf'
      }"
      lazy
      show-checkbox
      node-key="path"
      class="treeWrap"
      @check-change="handleCheckChange"
    >
      <span slot-scope="{ data }">
        <svg-icon v-if="data.ftype === '1'" style="color: #fdd300;" icon-class="faFolder"/>
        <span v-else>
          <svg-icon :icon-class="fileInputHandle(data).icon" :style="{color: fileInputHandle(data).color}"/>
        </span>
        <span>{{ data.fname }}</span>
      </span>
    </el-tree>
    -->
  </div>
</template>

<script>
import { slotFileList, slotFileExport } from '@/api/disc.js'
import { downloadFile } from '@/utils/index'
import getFileIcon from '@/utils/getFileIcon'
import { getFilesNumFromFolder } from '@/api/mtoptical'
import { Message } from 'element-ui'
import virtualNodeTree from '@/components/virtualNodeTree/tree'

export default {
  name: 'DiscFileDetail',
  components: { virtualNodeTree },
  data() {
    return {
      treeData: [],
      dirInfos: [],
      lock: false,
      loading:false,
      exportLoading:false,
      exportMaxNum: 10000 // 允许导出文件的最大数量
    }
  },
  mounted() {},
  methods: {
    async handleNodeCheck(data, selctedInfo) {
      const checked = selctedInfo.checkedKeys.includes(data.path)
      if (data.ftype == '1' && checked) {
        if (typeof data.allFileNum === 'number') {
          // 已获悉该文件夹数量的不再查询
          this.exportUtils('fileNumChange', { dirInfos: this.dirInfos, data, fileNum: parseInt(data.allFileNum), checked })
          return
        }
        const params = {
          nodeId: this.$route.query.nodeId || '',
          libId: this.$route.query.libId || '',
          grooveId: this.$route.query.grooveId || '',
          path: data.path || '/'
        }
        if (this.$route.query.rfid) params.rfid = this.$route.query.rfid
        const res = await this.getFilesNumFromFolder(params)
        data.allFileNum = res
        this.exportUtils('fileNumChange', { dirInfos: this.dirInfos, data: data || '/', fileNum: parseInt(res), checked })
        // if (res > this.exportMaxNum) {
        //   this.$message.error(`导出文件数量不能超过${this.exportMaxNum}`)
        //   // 取消勾选
        //   this.$refs.dirTree.setChecked(data, false, true)
        // } else {
        //   data.allFileNum = res
        //   this.exportUtils('fileNumChange', { dirInfos: this.dirInfos, data: data || '/', fileNum: parseInt(res), checked })
        //   console.log('添加数量完成', this.dirInfos[0]);
        // }
      } else if (data.ftype != '1' && checked) {
        // 勾选文件
        this.exportUtils('fileNumChange', { dirInfos: this.dirInfos, data, fileNum: null, checked })
      } else if (data.ftype != '1') {
        // 取消勾选文件
        this.exportUtils('fileNumChange', { dirInfos: this.dirInfos, data, fileNum: null, checked })
      } else {
        // 取消勾选文件夹
        this.exportUtils('fileNumChange', { dirInfos: this.dirInfos, data, fileNum: null, checked })
      }
    },
    getFilesNumFromFolder(params) {
      return new Promise((resolve, reject) => {
        const loaderTip = this.$loading({
          lock: true,
          text: '请稍等......',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        })
        getFilesNumFromFolder(params).then(res => {
          // console.log('获取到的文件数量', res);
          loaderTip.close()
          resolve(typeof res === 'number' ? parseInt(res) : 0)
        }).catch(() => {
          loaderTip.close()
          reject(0)
        })
      })
    },
    fileInputHandle(file) {
      const nameSplit = file.fname.split('.')
      let iconInfo = null
      if (nameSplit.length > 1) {
        iconInfo = getFileIcon(nameSplit[nameSplit.length - 1])
      } else {
        iconInfo = getFileIcon('其他')
      }
      return iconInfo
    },
    async exportUtils(fn, params) {
      return new Promise(async(resolve, reject) => {
        let fileTotal, dataPath
        switch (fn) {
          // 添加文件夹信息到文件夹信息集合内
          case 'addDirInfo':
            for (let i = 0; i < params.dirInfos.length; i++) {
              if (params.node.data.path === params.dirInfos[i].path) {
                params.dirInfos[i].children = params.addInfo
                resolve('finished')
              }
              if (params.dirInfos[i].children) {
                const status = this.exportUtils('addDirInfo', { ...params, dirInfos: params.dirInfos[i].children })
                if (status === 'finished') resolve()
              }
            }
            break
          // 添加文件夹数量到文件夹信息集合内
          case 'fileNumChange':
            // 勾选的是文件比对时需要删除path后面的文件名后再比对
            if (params.data.ftype != '1') {
              const tmp = params.data.path.split('/')
              dataPath = tmp.slice(0, tmp.length - 1).join('/')
            } else {
              dataPath = params.data.path || '/'
            }
            for (let i = 0; i < params.dirInfos.length; i++) {
              // 找到该文件夹信息
              if (dataPath === params.dirInfos[i].path) {
                // console.log('已找到该信息', params);
                if (params.checked) {
                  const curDirSelFileNum = params.data.ftype == '1' ? (typeof params.dirInfos[i].curSelFileNum === 'number' ? params.dirInfos[i].curSelFileNum : 0) : 0
                  const curAllCheckedFileNum = await this.exportUtils('getFileTotal') + (params.fileNum || 1) - curDirSelFileNum
                  // 添加前检查是否超出最大导出数量
                  if (curAllCheckedFileNum > this.exportMaxNum) {
                    this.$message.error(`导出文件数量不能超过${this.exportMaxNum}`)
                    // 取消勾选
                    this.$refs.dirTree.setChecked(params.data, false, true)
                    if (params.data.ftype == '1') {
                      params.dirInfos[i].curSelFileNum = 0
                    }
                    resolve(params.data.ftype == '1' ? -curDirSelFileNum : 0)
                    return
                  }
                  // console.log('当前勾选文件数', curAllCheckedFileNum);
                  // 勾选的是文件夹
                  if (params.data.ftype == '1') {
                    params.dirInfos[i].allFileNum = params.fileNum
                    params.dirInfos[i].curSelFileNum = params.fileNum
                    this.exportUtils('setAllChildrenChecked', { children: params.dirInfos[i].children })
                    resolve(params.fileNum - curDirSelFileNum)
                  } else {
                    if (params.dirInfos[i].curSelFileNum === 'unknown') {
                      params.dirInfos[i].curSelFileNum = 1
                    } else {
                      params.dirInfos[i].curSelFileNum += 1
                    }
                    resolve(1)
                  }
                } else {
                  // 取消勾选
                  if (params.data.ftype == '1') {
                    params.dirInfos[i].curSelFileNum = 0
                    if (params.dirInfos[i].allFileNum === 'unknown') {
                      const queryParams = {
                        nodeId: this.$route.query.nodeId || '',
                        libId: this.$route.query.libId || '',
                        grooveId: this.$route.query.grooveId || '',
                        path: params.data.path || '/'
                      }
                      resolve(await this.getFilesNumFromFolder(queryParams))
                    }
                    resolve(params.dirInfos[i].allFileNum)
                  } else {
                    if (params.dirInfos[i].curSelFileNum !== 'unknown') {
                      params.dirInfos[i].curSelFileNum -= 1
                    }
                    resolve(1)
                  }
                }
              }
              if (params.dirInfos[i].children && params.dirInfos[i].children.length !== 0) {
                const num = await this.exportUtils('fileNumChange', { ...params, dirInfos: params.dirInfos[i].children })
                if (typeof num === 'number') {
                  if (params.dirInfos[i].curSelFileNum === 'unknown') {
                    params.dirInfos[i].curSelFileNum = num
                  } else {
                    params.dirInfos[i].curSelFileNum += params.checked ? num : -num
                  }
                  resolve(num)
                }
              }
              if (i === params.dirInfos.length - 1) resolve('continue')
            }
            break
          // 获取已勾选的文件总数
          case 'getFileTotal':
            fileTotal = this.dirInfos.reduce((total, item) => {
              const tmp = item.curSelFileNum === 'unknown' ? 0 : item.curSelFileNum
              return total + tmp
            }, 0)
            resolve(fileTotal)
            break
          // 当父文件夹勾选后,将所有已知文件总数量的子文件夹的curSelFileNum设置为allSelFileNum
          case 'setAllChildrenChecked':
            if (Array.isArray(params.children) && params.children.length !== 0) {
              for (const i in params.children) {
                const allFileNum = params.children[i].allFileNum
                params.children[i].curSelFileNum = allFileNum === 'unknown' ? 'unknown' : allFileNum
                if (params.children[i].children && params.children[i].children.length !== 0) {
                  this.exportUtils('setAllChildrenChecked', params.children[i].children)
                }
              }
            }
            break
        }
      })
    },
    loadDir(node, resolve) {
      const temp = {
        nodeId: this.$route.query.nodeId || '',
        libId: this.$route.query.libId || '',
        oid: this.$route.query.oid || '',
        path: node.data.path || '/'
      }
      if (this.$route.query.src === 'warehouseTask' &&
        this.$route.query.rfid
      ) {
        temp.rfid = this.$route.query.rfid
      } else {
        temp.grooveId = this.$route.query.grooveId || ''
      }
      this.loading = true;
      slotFileList(temp).then(res => {
        this.loading = false;
        if (res && res instanceof Array) {
          const addInfo = []
          for (const i in res) {
            if (res[i].ftype == '1') {
              addInfo.push({
                path: (node.data.path || '') + '/' + res[i].fname,
                level: node.level + 1,
                allFileNum: 'unknown',
                curSelFileNum: 'unknown',
                children: null
              })
            }
          }
          if (this.dirInfos.length === 0) {
            this.dirInfos.push({
              path: node.data.path || '/',
              allFileNum: 'unknown',
              curSelFileNum: 'unknown',
              level: node.level,
              children: addInfo
            })
          } else {
            this.exportUtils('addDirInfo', { dirInfos: this.dirInfos, node, addInfo })
          }
          const list = res.map(item => {
            return {
              ...item,
              path: (node.data.path || '') + '/' + item.fname,
              leaf: item.ftype != '1'
              // disabled: item.ftype == '1'
            }
          })
          resolve(list)
        } else {
          resolve([])
        }
      }).catch(() => {
        this.loading = false;
        resolve([])
      })
    },
    exportHandle() {
      const checkeNodes = this.$refs.dirTree.getCheckedNodes()
      if (checkeNodes.length < 1) {
        this.$message.error('请选择需要导出的数据')
        return
      }
      this.exportLoading = true;
      setTimeout(() => {
        try {
          // const paths = checkeNodes.map(item => {
          //   return { fileName: item.path, fileType: item.ftype === '1' ? '1' : '2' }
          // })
          let paths = checkeNodes.map(item => {
            return { pathArr: item.path.split('/'), fileType: item.ftype === '1' ? '1' : '2' }
          })
          // 如果文件夹与子文件件都勾选了,只保留顶级文件夹
          for (let i = 0; i < paths.length; i++) {
            if (!paths[i]) continue
            out: for (let j = i + 1; j < paths.length; j++) {
              if (!paths[j]) continue out
              for (let k = 0; k < paths[i].pathArr.length; k++) {
                if (paths[i].pathArr[k] !== paths[j].pathArr[k]) {
                  continue out
                }
              }
              paths[j] = null
            }
          }
          // 过滤掉null的元素
          paths = paths.filter(item => item)
          // const paths = checkeNodes.map(item => item.path)
          const temp = {
            nodeId: this.$route.query.nodeId || '',
            libId: this.$route.query.libId || '',
            grooveId: this.$route.query.grooveId || '',
            oid: this.$route.query.oid || '',
            exportFiles: paths.map(item => {
              return { fileName: item.pathArr.join('/'), fileType: item.fileType === '1' ? '1' : '2' }
            })
          }
          if (this.$route.query.rfid) temp.rfid = this.$route.query.rfid
          // console.log('提交参数', temp);
          // return
          slotFileExport(temp).then(res => {
            downloadFile(res, '导出', 'xlsx')
            this.exportLoading = false;
          }).catch(error => {
            const fileReader = new FileReader()
            fileReader.onload = function(e) {
              Message.error(this.result)
            }
            fileReader.readAsText(error.response.data)
            this.exportLoading = false;
          })
        } catch (e) {
          this.$message.error(e)
          this.exportLoading = false;
        }
      }, 20)
    }
  }
}
</script>

<style lang="scss" scoped>
  .el-tree {
    height: calc(100vh - 136px - 90px);
  }

  .app-container {
    background: #fff;
    padding: 20px;
    margin: 0px 10px 0 10px;
    /* height: 800px; */
    overflow-y: auto;
    border-radius: 5px;
  }

  .treeWrap {
    margin-top: 20px;
    border-radius: 4px;
    border: 1px solid #9e9e9e;
  }
</style>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

el-tree组件展示节点过多时造成页面卡顿、奔溃的解决办法 的相关文章

  • R Shinydashboard 自定义 CSS 到 valueBox

    我一直在尝试将 valueBox 的颜色更改为自定义颜色 超出 validColors 中可用的颜色 但一直无法这样做 我知道有一种方法可以使用标签来包含自定义 CSS 但是我无法将它们放在正确的位置 ui lt dashboardPage
  • 如何在php中使用一张图像绘制形状

    我需要使用图像的一部分来创建帧图像 例如 用户将从后端上传图像片段 现在我需要根据前端用户的要求在前端创建一个框架 用户将选择框架的高度和宽度 然后他将选择该图像片段 如下所示 我没有办法做到这一点 我尝试通过 css 和 html can
  • 如果用户在 Laravel 中经过身份验证,如何检查 Vue 组件?

    正如标题所述 我有点困惑如何根据用户是否登录并使用 Laravel 的 Auth 外观进行身份验证 使用 if else 语句处理 Vue 组件中的方法 我正在发出各种 Axios 请求 我需要根据用户是否登录来允许 禁止这些请求 我有 V
  • 宽度:适合内容;在 Chrome 上工作,但在资源管理器上不工作

    我构建了一个应用程序 所有内容都在 Chrome 中完美显示 但如果我在 Windows 资源管理器中打开该应用程序 容器会比应有的小 我在用着width fit content 这是只适用于 Chrome 的东西吗 我怎样才能使其适用于所
  • 如何为 TBODY 应用垂直滚动条

    我的表中有 4 列和 5 行数据 我必须为 TBODY 应用垂直滚动条 TH 标题内容不应滚动 我对场景进行了编码 并且在我将滚动类应用于 TBODY 之前它工作正常 一旦我将滚动样式类应用于 TBODY 它就会破坏之前的对齐方式 任何人都
  • 弹出窗口的动态高度取决于内容,可能吗?

    是否有可能获得一个宽度始终为 400px 的弹出窗口 但根据弹出窗口中的内容动态高度 我已经看到了这个 但不知道如何将其应用到弹出窗口 调整 iframe 的宽度高度以适应其中的内容 https stackoverflow com ques
  • 在具有多级分组的 HTML 表格中显示数据

    我必须通过使用 rowspan 进行分组来显示 HTML 表中的一些数据 下面是预期的 GUI 我有如下所示的 JSON 数据 JSON数据here https jsoneditoronline org id 1014438e5489485
  • 输入类型=图像 - onclick(),将触发其事件,但在 jquery 中的函数上表现不佳

    我认为这可能是两篇文章 2个问题 所以如果你对此发表评论 我会将它们分开 主要问题实际上是 我怎样才能为按钮设置图像背景 简单且正确 我想现在我可以确定这些事实了 因为我在将图像设置为按钮背景时遇到了 小 问题 我想 好吧 如果很难设置的话
  • 如何在文本区域中使用除“文本插入符号”之外的透明字体?

    我有一个简单的文本区域 我需要制作透明字母 同时允许文本插入符可见 当我应用以下规则时 我会得到隐形插入符 textarea background transparent opacity 0 当我键入不可见文本时 我需要看到文本插入符移动
  • php中的条件格式化html表与时间戳比较

    echo table style width 100 tr echo td Order td echo td Destination td echo td Location td echo td Status td echo td Time
  • 如何通过单击图像预览上的“x”从文件输入中删除图像?

    我目前有一个文件输入 一旦用户上传图像 就会显示图像预览 在图像预览上 有一个 x 可以从列表中删除图像预览 单击此 x 后 有什么方法可以从输入中的文件集中删除图像吗
  • 如何将udp发送到udp node.js服务器?

    我对此很陌生 所以我真的不知道我在做什么 但我已经设置了一个 node js udp 服务器 我想从客户端 来自网站 向它发送一个数据包 但我不知道如何在 javascript 中做到这一点 或者是否可能 我不是在研究如何从 Node js
  • jquery 验证错误位置

    这看起来很简单 但我无法弄清楚 我正在使用 jquery 验证插件 我验证所有文件 但我想要的是在输入文本行中显示验证消息警报 例如在电子邮件输入中 请填写电子邮件地址 但现在它出现在所有字段下 在我的html中
  • 如何将此 HTML 表格布局解决方案转换为浮动 div 解决方案?

    我经常需要列出各种尺寸的项目images在左边和text在右边 像这样 替代文本 http www deviantsart com upload 7s01l5 png http www deviantsart com upload 7s01
  • 如何使用canvas.toDataURL()将画布保存为图像?

    我目前正在构建一个 HTML5 Web 应用程序 Phonegap 本机应用程序 我似乎不知道如何将画布保存为图像canvas toDataURL 有人可以帮我吗 这是代码 有什么问题吗 我的画布被命名为 canvasSignature J
  • 按百分比设置 bootstrap 模态身高

    我正在尝试制作一个带有主体的模态 当内容变得太大时 该主体会滚动 但是 我希望模式能够响应屏幕尺寸 当我将最大高度设置为 40 时 它没有任何效果 但是 如果我将最大高度设置为 400px 它会按预期工作 但不会响应 我确信我只是错过了一些
  • iOS7 中“-webkit-overflow-scrolling: touch” 最初的屏幕外元素被破坏

    既然转基因种子已经发布了 我们现在可以谈谈了 看起来 iOS7 中的 webkit overflow scrolling touch 已损坏 最初不在屏幕上的元素的触摸事件不会触发 或者在某些情况下只是不可靠 这是一个例子
  • 如何延迟加载嵌入在 iframe 上的 YouTube 视频?

    如何将延迟加载应用于iframe嵌入视频 我尝试添加loading eager loading auto and loading lazyload 您可以使用srcdoc你里面的属性iframe标签来加载图像 请参阅以下示例作为参考
  • 在d3.js中将2D形状转换为3D,并根据ANGULAR中的值调整高度

    我正在使用 d3 js v6 创建以下 2D 图表表示的 3D 图表 这个圆圈中有多个正方形 每个正方形都根据值分配了一种颜色 值越大 正方形越暗 现在我想将其转换为 3D 形状 其中当值变高时 只有特定正方形的高度会增加 因此结果在某种程
  • 如何将送货地址复制到帐单地址

    我想知道是否可以将送货地址复制到帐单地址 当用户单击与送货地址相同的复选框时 送货地址值将被复制到账单输入字段 我完成了大部分部分 但我不确定如何将选择菜单 状态 值复制到帐单地址 我真的很感谢任何帮助 My code document r

随机推荐

  • Java中IO流——详解字节流之FileOutputStream和FileInputStream

    文章目录 前言 一 Java流的概述 二 常用字节流分类 1 字节输出输入流 1 FileOutputStream 2 FileInputStream 3 复制小练习 4 异常捕获 总结 前言 我们之前学习了Java中的异常机制和File类
  • 【区块链】Python开发EOS机器人与WAX链游脚本常用工具

    前言 众所周知 开发EOS机器人与WAX链游脚本 我们都需要调用eosio chain api https developers eos io manuals eos latest nodeos plugins chain api plug
  • mybatis多表联查sql用法示例

    用到sql变量 sql复用
  • ssm打印sql如何开启_ssm环境下配置log4j打印mybatis的sql语句

    首先附上官网的说明文档 mybatis Logging 环境spring4 3 0 springmvc4 3 0 mybatis3 4 0 按官方文档的说明 1 SLF4J 2 Apache Commons Logging 3 Log4j
  • 使用invoke方法解决跨线程访问的问题

    C 中禁止跨线程直接访问控件 InvokeRequired是为了解决这个问题而产生的 当一个控件的InvokeRequired属性值为真时 说明有一个创建它以外的线程想访问它 获取一个值 该值指示调用方在对控件进行方法调用时是否必须调用 I
  • js+bootstrap+jquery+vue实现房贷计算器

    代码链接 loan 使用vue js html css实现房贷的计算 版权声明 本文为CSDN博主 小样还想跑 的原创文章 遵循CC 4 0 BY SA版权协议 转载请附上原文出处链接及本声明
  • 23 种设计模式详解(全23种)

    设计模式的分类 总体来说设计模式分为三大类 创建型模式 共五种 工厂方法模式 抽象工厂模式 单例模式 建造者模式 原型模式 结构型模式 共七种 适配器模式 装饰器模式 代理模式 外观模式 桥接模式 组合模式 享元模式 行为型模式 共十一种
  • 人手一份核武器:Android手机装Kali Linux

    首先这是安卓手机的专属工具 因为Android基于Linux 所以就有了得天独厚的优势 1 先下载好Linux Deploy 前提是本手机已root 2 按下图配置 不过有地方需要说明 Distribute Suite已经改为sana 但无
  • Windows Server 2012 R2 设置 smtp 服务器

    Windows Server 2012 2012 R2 安装和配置 SMTP 服务器 安装 SMTP 服务器 以下是安装 SMTP 服务器功能的步骤 打开 服务器管理器 单击键盘上的 Windows 按钮 输入 服务器管理器 在 结果 窗口
  • FW-1设备配置命令

    DCFW 1800 config hostname FW 1 FW 1 config ip vrouter trust vr FW 1 config vrouter ip route 0 0 0 0 0 202 11 33 26 FW 1
  • cmd创建用户并初始化新用户桌面

    author skate time 2013 12 20 功能 在win2003上创建用户 并初始化新用户的桌面 echo InternetShortcut gt gt MysqlTool url echo URL C Program Fi
  • Qt之pro配置多个子工程/子模块

    简述 进行Qt项目开发的时候 尤其是大型项目 经常涉及多工程 多模块问题 其主要思想还是模块化 目的是为了降低程序复杂度 使程序设计 调试和维护等操作简单化 简述 配置 效果 多工程 多模块 更多参考 配置 效果 多工程 如果需要管理多工程
  • JavaMap集合&Stream流

    1 Map集合 1 1Map集合概述和特点 Map集合概述 interface Map
  • Python-Thread(通俗易懂)

    此类表示在单独的控制线程中运行的活动 有两种方法可以指定该活动 一是将可调用对象传递给构造函数 二是通过覆盖子类中的run 方法 如果你对线程不太理解 我们可以打个比方 把线程数看作车辆数 我们来完成一个简单的客运运输工作 以下为了方便理解
  • 第8届Python编程挑战赛初赛真题剖析-2022年全国青少年信息素养大赛

    导读 超平老师计划推出 全国青少年信息素养大赛Python编程真题解析 50讲 这是超平老师解读Python编程挑战赛系列的第1讲 全国青少年信息素养大赛 原全国青少年电子信息智能创新大赛 是 世界机器人大会青少年机器人设计与信息素养大赛
  • VC++ MapWinGis篇(二)

    添加高德图层 ArcGisProvider h pragma once include BaseProvider h class ArcGisBaseProvider public BaseProvider public ArcGisBas
  • Java RMI 远程代码执行漏洞

    0x01 漏洞描述 Java RMI 远程代码执行漏洞 Java RMI服务是远程方法调用 是J2SE的一部分 能够让程序员开发出基于JAVA的分布式应用 一个RMI对象是一个远程Java对象 可以从另一个Java虚拟机上 甚至跨过网络 调
  • 这篇文章带你了解sql语句是怎么执行的

    一条sql语句是怎么执行的 一 mysql架构分析 二 语句分析 2 1 查询语句 2 2 更新语句 三 总结 mysql有各种版本的架构图 但基本上都可以分为Server层和存储引擎层 一 mysql架构分析 下面是mysql的一个简要架
  • web压测工具http_load原理分析

    01 前言 http load是一款测试web服务器性能的开源工具 从下面的网址可以下载到最新版本的http load http www acme com software http load 这个软件一直在保持着更新 不像webbench
  • el-tree组件展示节点过多时造成页面卡顿、奔溃的解决办法

    解决el tree组件展示节点过多时造成页面卡顿 奔溃 前几天测试提了个BUG 文件列表展示5w个文件页面会卡顿甚至奔溃 项目用的是vue element ui框架 我是使用el tree进行渲染文件列表的 参考网上使用virtual sc