element ui 表格组件与分页组件的二次封装

news2025/1/10 11:22:34

目录

组件封装

 parseTime函数

debounce 函数

页面使用

【扩展】vue 函数式组件

函数式组件特点:

函数式组件的优点:

【扩展】vue中的render函数

一、初步认识render函数

二、为什么使用render函数

三、render函数的解析


组件封装

这段代码是一个封装的分页表格组件。它使用了Vue.js框架,并结合了Element UI中的el-table和el-pagination组件来实现。该组件接受一系列属性作为数据源,包括列表数据(list)、表格列(columns)、操作按钮列(operates)、总数(total)、分页参数(pagination)等。

在模板中,使用el-table组件来展示表格数据,使用el-pagination组件来实现分页功能。el-table-column用来定义每列的样式和展示内容。组件中还包括其他的一些方法和事件处理函数,如handleSizeChange用于切换每页显示的数量,handleIndexChange用于切换页码,handleSelectionChange处理多行选中等。

此外,还定义了一些样式规则来美化表格的显示效果,如设置表头颜色、调整列的样式、设置操作按钮组的布局、设置筛选弹窗和表格操作弹窗的样式等。

最后,使用了scss来编写样式表,通过设置类名来控制样式的展示。

  1. <template>标签中,定义了一个表格组件,包括表格本身,列定义,按钮操作组,和分页控件。

  2. <script>标签中,导入了必要的依赖,并定义了组件的属性(props)、数据(data)、生命周期钩子(activated、beforeDestroy、deactivated、created、mounted)和方法(methods)。

  3. props属性用于接受从父组件传递进来的数据,如数据列表 list、列定义 columns、按钮操作 operates、总数 total、分页参数 pagination 等。

  4. data数据属性包括一些内部状态,如表格高度 height、监听窗口调整大小的回调函数 $_resizeHandler、当前页码 pageIndex、表格分页信息 tableCurrentPagination、多行选中数据 multipleSelection 等。

  5. 在生命周期钩子中,组件监听窗口大小调整事件,自动调整表格高度,并在适当的生命周期中初始化和销毁事件监听器。

  6. methods包括一系列方法,如计算表头宽度的方法 headSpanFit、初始化事件监听器的方法 initListener、销毁事件监听器的方法 destroyListener、调整表格高度的方法 resize、处理每页显示数量变化的方法 handleSizeChange、处理页码变化的方法 handleIndexChange、处理多行选中的方法 handleSelectionChange 等。

  7. 最后,在<style>标签中定义了一些样式,包括表格样式、分页样式、按钮样式、筛选和操作弹窗样式等。

<!--region 封装的分页 table-->
<!--region 封装的分页 table-->
<template>
  <div class="table">
    <el-table id="iTable" v-loading.iTable="options.loading" :data="list" :stripe="options.stripe" ref="mutipleTable"
      @selection-change="handleSelectionChange" :height="noStatic ? customHeight : height"
      :max-height="noStatic ? customHeight : height">
      <!--region 选择框-->
      <el-table-column v-if="options.mutiSelect" type="selection" style="width: 55px">
      </el-table-column>
      <!--endregion-->
      <!--region 数据列-->
      <template v-for="(column, index) in columns">
        <el-table-column :min-width="headSpanFit(column)" :prop="column.prop" :label="column.label" :align="column.align"
          :width="column.width">
          <template slot-scope="scope">
            <template v-if="!column.render">
              <template v-if="column.formatter">
                <span v-html="column.formatter(scope.row, column)"></span>
              </template>
              <template v-else>
                <span>{{ scope.row[column.prop] === 0
                  ? 0
                  : scope.row[column.prop] || "--" }}</span>
              </template>
            </template>
            <template v-else>
              <expand-dom :column="column" :row="scope.row" :render="column.render" :index="index"></expand-dom>
            </template>
          </template>
        </el-table-column>
      </template>
      <!--endregion-->
      <!--region 按钮操作组-->
      <el-table-column ref="fixedColumn" label="操作" align="center" :width="operates.width" :fixed="operates.fixed"
        v-if="operates.list.length > 0">
        <template slot-scope="scope">
          <div class="operate-group">
            <template v-for="(btn, key) in operates.list">
              <div class="item" v-if="typeof btn.show == 'function'
                ? btn.show(scope.$index, scope.row)
                : btn.show">
                <el-button :type="btn.type" :key="key + 'itbtn'" :size="btn.size || 'mini'" :icon="btn.icon" :disabled="typeof btn.disabled == 'function'
                  ? btn.disabled(scope.$index, scope.row)
                  : btn.disabled" :plain="btn.plain" @click.native.prevent="btn.method(scope.$index, scope.row)">{{
    btn.label }}
                </el-button>
              </div>
            </template>
          </div>
        </template>
      </el-table-column>
      <!--endregion-->
    </el-table>
    <div style="height: 12px"></div>
    <!--region 分页-->
    <el-pagination v-if="pagination" @size-change="handleSizeChange" @current-change="handleIndexChange"
      :page-size="tableCurrentPagination.pageSize" :page-sizes="this.tableCurrentPagination.pageArray"
      :current-page="tableCurrentPagination.pageIndex" layout="total,sizes, prev, pager, next,jumper"
      :total="total"></el-pagination>
    <!--endregion-->
  </div>
</template>
<!--endregion-->
<script>
import { debounce } from "@/utils";
const _pageArray = [20, 50, 100]; // 每页展示条数的控制集合
export default {
  props: {
    list: {
      type: Array,
      default: [], // prop:表头绑定的地段,label:表头名称,align:每列数据展示形式(left, center, right),width:列宽
    }, // 数据列表
    columns: {
      type: Array,
      default: [], // 需要展示的列 === prop:列数据对应的属性,label:列名,align:对齐方式,width:列宽
    },
    operates: {
      type: Object,
      default: {}, // width:按钮列宽,fixed:是否固定(left,right),按钮集合 === label: 文本,type :类型(primary / success / warning / danger / info / text),show:是否显示,icon:按钮图标,plain:是否朴素按钮,disabled:是否禁用,method:回调方法
    },
    total: {
      type: Number,
      default: 0,
    }, // 总数
    pagination: {
      type: Object,
      default: null, // 分页参数 === pageSize:每页展示的条数,pageIndex:当前页,pageArray: 每页展示条数的控制集合,默认 _page_array
    },
    noStatic: false, // 是否计算表格高度
    customHeight: {
      //与noStatic一起使用
      type: Number,
      default: 320,
    },
    otherHeight: {
      type: Number,
      default: 180,
    }, // 计算表格的高度
    options: {
      type: Object,
      default: {
        stripe: false, // 是否为斑马纹 table
        loading: false, // 是否添加表格loading加载动画
        highlightCurrentRow: false, // 是否支持当前行高亮显示
        mutiSelect: false, // 是否支持列表项选中功能
      },
    }, // table 表格的控制参数
  },
  components: {
    expandDom: {
      functional: true,
      props: {
        row: Object,
        render: Function,
        index: Number,
        column: {
          type: Object,
          default: null,
        },
      },
      render: (h, ctx) => {
        const params = {
          row: ctx.props.row,
          index: ctx.props.index,
        };
        if (ctx.props.column) params.column = ctx.props.column;
        return ctx.props.render(h, params);
      },
    },
  },
  data() {
    return {
      height: 250,
      $_resizeHandler: null,
      pageIndex: 1,
      tableCurrentPagination: {},
      multipleSelection: [], // 多行选中
    };
  },

  activated() {
    // 通常是在使用 Vue.js 的 <keep-alive> 包装时,组件会被缓存并在重新激活时调用这个钩子函数。
    if (!this.$_resizeHandler) {
      // avoid duplication init
      this.initListener();
    }

    // when keep-alive chart activated, auto resize
    this.resize();
  },
  //当组件即将被销毁(beforeDestroy)时,会调用这个钩子函数。
  beforeDestroy() {
    this.destroyListener();
  },
  //当组件被停用(deactivated),通常也是在 <keep-alive> 包装下,组件会调用这个钩子函数。
  deactivated() {
    this.destroyListener();
  },
  created() { },
  mounted() {
    this.initListener();
    if (this.pagination && !this.pagination.pageSizes) {
      this.pagination.pageArray = _pageArray; // 每页展示条数控制
    }
    this.tableCurrentPagination = this.pagination || {
      pageSize: this.total,
      pageIndex: 1,
    }; // 判断是否需要分页
  },
  methods: {
    //计算小列宽
    headSpanFit(column) {
      let labelLong = column.label.length; // 表头label长度
      let size = 20; // 根据需要定义标尺,直接使用字体大小确定就行,也可以根据需要定义
      let minWidth = labelLong * size < 100 ? 100 : labelLong * size; // 根据label长度计算该表头最终宽度
      return minWidth;
    },
    // 初始化监听器的方法。
    initListener() {
      this.$_resizeHandler = debounce(() => {
        this.resize();
      }, 200);
      window.addEventListener("resize", this.$_resizeHandler);
      this.$nextTick(() => {
        this.resize();
      });
    },
    //这是一个销毁监听器的方法。
    destroyListener() {
      window.removeEventListener("resize", this.$_resizeHandler);
      this.$_resizeHandler = null;
    },
    //计算表格的高度
    resize() {
      // 不需要计算
      if (this.noStatic) {
        return;
      }

      const { mutipleTable } = this.$refs;
      // 窗口的高度减去表格的顶部偏移
      let staticHeight =
        window.innerHeight - this.$refs.mutipleTable.$el.offsetTop - this.otherHeight;
      this.height = staticHeight < 250 ? 250 : staticHeight;

      console.log(this.height);
      //保表格的布局在高度调整后得以更新。
      mutipleTable && mutipleTable.doLayout();
    },
    // 切换每页显示的数量
    handleSizeChange(size) {
      if (this.pagination) {
        this.tableCurrentPagination = {
          pageIndex: 1,
          pageSize: size,
        };
        this.$emit("handleSizeChange", this.tableCurrentPagination);
      }
    },
    // 切换页码
    handleIndexChange(currnet) {
      if (this.pagination) {
        this.tableCurrentPagination.pageIndex = currnet;
        this.$emit("handleIndexChange", this.tableCurrentPagination);
      }
    },
    // 多行选中
    handleSelectionChange(val) {
      this.multipleSelection = val;
      this.$emit("handleSelectionChange", val);
    },
    // 显示 表格操作弹窗
    showActionTableDialog() {
      this.$emit("handelAction");
    },
  },
};
</script>

<style lang="scss">
.table {
  height: 100%;

  .el-pagination {
    float: right;
    margin: 20px;
  }

  .el-table__header-wrapper,
  .el-table__fixed-header-wrapper {
    thead {
      tr {
        th {
          color: #333333;
        }
      }
    }
  }

  .el-table-column--selection .cell {
    padding: 0;
    text-align: center;
  }

  .el-table__fixed-right {
    bottom: 0 !important;
    right: 6px !important;
    z-index: 1004;
  }

  .operate-group {
    display: flex;
    flex-wrap: wrap;

    .item {
      margin-top: 4px;
      margin-bottom: 4px;
      display: block;
      flex: 0 0 50%;
    }
  }

  .filter-data {
    top: e("calc((100% - 100px) / 3)");
    background-color: rgba(0, 0, 0, 0.7);
  }

  .table-action {
    top: e("calc((100% - 100px) / 2)");
    background-color: rgba(0, 0, 0, 0.7);
  }

  .fix-right {
    position: absolute;
    right: 0;
    height: 100px;
    color: #ffffff;
    width: 30px;
    display: block;
    z-index: 1005;
    writing-mode: vertical-rl;
    text-align: center;
    line-height: 28px;
    border-bottom-left-radius: 6px;
    border-top-left-radius: 6px;
    cursor: pointer;
  }
}
</style>

 parseTime函数

// 日期格式化
export function parseTime(time, pattern) {
  if (arguments.length === 0 || !time) {
    return null
  }
  const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
  let date
  if (typeof time === 'object') {
    date = time
  } else {
    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
      time = parseInt(time)
    } else if (typeof time === 'string') {
      time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
    }
    if ((typeof time === 'number') && (time.toString().length === 10)) {
      time = time * 1000
    }
    date = new Date(time)
  }
  const formatObj = {
    y: date.getFullYear(),
    m: date.getMonth() + 1,
    d: date.getDate(),
    h: date.getHours(),
    i: date.getMinutes(),
    s: date.getSeconds(),
    a: date.getDay()
  }
  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
    let value = formatObj[key]
    // Note: getDay() returns 0 on Sunday
    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
    if (result.length > 0 && value < 10) {
      value = '0' + value
    }
    return value || 0
  })
  return time_str
}

debounce 函数

export function debounce(func, wait, immediate) {
  let timeout, args, context, timestamp, result

  const later = function() {
    // 据上一次触发时间间隔
    const last = +new Date() - timestamp

    // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
    if (last < wait && last > 0) {
      timeout = setTimeout(later, wait - last)
    } else {
      timeout = null
      // 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
      if (!immediate) {
        result = func.apply(context, args)
        if (!timeout) context = args = null
      }
    }
  }

  return function(...args) {
    context = this
    timestamp = +new Date()
    const callNow = immediate && !timeout
    // 如果延时不存在,重新设定延时
    if (!timeout) timeout = setTimeout(later, wait)
    if (callNow) {
      result = func.apply(context, args)
      context = args = null
    }

    return result
  }
}

页面使用

<template>
  <div class="table-page">
    <!--region table 表格-->
    <app-table :list="list" :total="total" :otherHeight="otherHeight" :options="options" :pagination="pagination"
      :columns="columns" :operates="operates" @handleSizeChange="handleSizeChange" @handleIndexChange="handleIndexChange"
      @handleSelectionChange="handleSelectionChange">
    </app-table>
    <!--endregion-->
  </div>
</template>
<script>
import {
  parseTime,

} from "@/utils/ruoyi";
export default {
  data() {
    return {
      total: 0,
      list: [
        {
          id: 1,
          title: '标题',
          state: 0,
          author: '张三',
          phone: '12346788901',
          email: '1234556778@qq.com',
          createDate: "2023-04-23 16:11:38"
        }
      ],
      otherHeight: 208,
      columns: [
        {
          prop: 'id',
          label: '编号',
          align: 'center',
          width: 60
        },
        {
          prop: 'title',
          label: '标题',
          align: 'center',
          width: 400,
          formatter: (row, column, cellValue) => {
            return `<span style="white-space: nowrap;color: dodgerblue;">${row.title}</span>`
          }
        },
        {
          prop: 'state',
          label: '状态',
          align: 'center',
          width: '160',
          render: (h, params) => {
            return h('el-tag', {
              props: { type: params.row.state === 0 ? 'success' : params.row.state === 1 ? 'info' : 'danger' } // 组件的props
            }, params.row.state === 0 ? '上架' : params.row.state === 1 ? '下架' : '审核中')
          }
        },
        {
          prop: 'author',
          label: '作者',
          align: 'center',
          width: 120
        },
        {
          prop: 'phone',
          label: '联系方式',
          align: 'center',
          width: 160
        },
        {
          prop: 'email',
          label: '邮箱',
          align: 'center',
          width: 240
        },
        {
          prop: 'createDate',
          label: '发布时间',
          align: 'center',
          width: 180,
          formatter: (row, column, cellValue) => {
            return parseTime(row.createDate)
          }
        }
      ], // 需要展示的列
      operates: {
        width: 200,
        fixed: 'right',
        list: [
          {
            label: '编辑',
            type: 'warning',
            show: (index, row) => {
              return true
            },
            icon: 'el-icon-edit',
            plain: true,
            disabled: false,
            method: (index, row) => {
              this.handleEdit(index, row)
            }
          },
          {
            label: '删除',
            type: 'danger',
            icon: 'el-icon-delete',
            show: true,
            plain: false,
            disabled: (index, row) => {
              return false
            },
            method: (index, row) => {
              this.handleDel(index, row)
            }
          }
        ]
      }, // 操作按钮组
      pagination: {
        pageIndex: 1,
        pageSize: 20
      }, // 分页参数
      options: {
        stripe: true, // 是否为斑马纹 table
        loading: false, // 是否添加表格loading加载动画
        highlightCurrentRow: true, // 是否支持当前行高亮显示
        mutiSelect: true // 是否支持列表项选中功能
      } // table 的参数
    }
  },
  components: {
    expandDom: {
      props: {
        column: {
          required: true
        },
        row: {
          required: true
        }
      },
      render(h) {
        return h('div', {}, ([this.column.render(this.row, this.column)]))
      }
    }
  },
  mounted() {
  },
  methods: {
    // 切换每页显示的数量
    handleSizeChange(pagination) {
      this.pagination = pagination
    },
    // 切换页码
    handleIndexChange(pagination) {
      this.pagination = pagination
    },
    // 选中行
    handleSelectionChange(val) {
      console.log('val:', val)
    },
    // 编辑
    handleEdit(index, row) {
      console.log(' index:', index)
      console.log(' row:', row)
    },
    // 删除
    handleDel(index, row) {
      console.log(' index:', index)
      console.log(' row:', row)
    },

  }
}
</script>

【扩展】vue 函数式组件

函数式组件特点:

  • 没有管理任何状态
  • 没有监听任何传递给它的状态
  • 没有生命周期方法
  • 它只是接收一些prop的函

我们将这样的组件标记为functional

  • 无状态 == 无响应式数据
  • 无实例 == 无this上下文

函数式组件的优点:

  • 渲染开销低,因为函数式组件只是函数;
 {
  functional: true,
  // Props 是可选的
  props: {
    // ...
  },
  // 为了弥补缺少的实例
  // 提供第二个参数作为上下文
  render: function (createElement, context) {
    // ...
  }
}

props: 提供所有prop的对象
children:VNode 子节点的数组
slots: 一个函数,返回了包含所有插槽的对象
scoptedSlots:(2.6.0) 一个暴露传入的作用域插槽的对象,也以函数形式暴露普通插槽
data:传递个组件的整个数据对象,作为createElement的第二个参数传入组件
parent:对父组件的引用
listeners:(2.3.0+) 一个包含了:所有父组件为当前组件祖册的事件监听器对象,是data.on的一个别名
injections:(2.3.0+) 如果使用了inject选项,则改对象包含了:应当被注入的属性;

【扩展】vue中的render函数

一、初步认识render函数

import Vue from 'vue'
import App from './App'

Vue.config.productionTip = false

new Vue({
  el: '#app',
  render: h => h(App)
})

在使用脚手架创建vue项目的过程,我们很容易看到render这个函数,相对于其他标签,我们对于render还是比较陌生的,因此写下这篇文章你我共同理解。

二、为什么使用render函数


VUE推荐在绝大多数情况下使用template来创建我们的HTML。然而在一些场景中,我们真的需要JavaScript的完全编程的能力,这就是render函数,它比template更接近编译器。(这是官方的话)
简单来说,我们为什么要使用render函数呢?? 便是因为我们最经常使用的一个引入。

import Vue from "vue";

这一个引入你看似没有任何问题,但问题恰恰就是出在这。在不同版本的vue中,有vue.js和vue.runtime.xxx.js这两种js文件。其中

(1)vue.js是完整版的vue,包含核心功能+模板解析器。

(2)vue.runtime.xxx.js是运行版vue,只包含核心功能,没有模板解析器。

VUE开发者为了让我们打包的文件能尽可能小一点,在上述引入的是运行版vue。因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,这时候就需要使用render函数去接收到的createElement函数去指定具体内容,创建html模板。

三、render函数的解析


render 函数即渲染函数,它是个函数,它的参数 createElement 也是个函数。

上边的代码中 render: h => h(App) ,这是 ES6的箭头函数的写法,可以把 h 当作 createElement 的别名。所以这段代码其实相当于

render: function (createElement) {
    return createElement(App)
}

这个函数的作用就是生成一个 VNode节点,render 函数得到这个 VNode 节点之后,返回给 Vue.js 的 mount 函数,渲染成真实 DOM 节点,并挂载到根节点上。

createElement 函数的返回值是 VNode(即:虚拟节点)

createElement 函数的3个参数

  • 一个 HTML 标签字符串,组件选项对象,或者解析上述任何一种的一个 async 异步函数。类型:String | Object | Function。必需。
  • 一个包含模板相关属性的数据对象,你可以在 template 中使用这些特性。类型:Object。可选。
  • 子虚拟节点 (VNodes),由 createElement() 构建而成,也可以使用字符串来生成“文本虚拟节点”。类型:String | Array。可选
new Vue({
  el: '#app',
  render:function (createElement) {
    //1.普通用法
    // createElement(标签,{属性},[内容])
    return createElement("h2",{class:"box"},['hello',createElement("button",["按钮"])])
  }
})

同时createElement也可以传进去一个组件,因此 

render: h => h(App)

等同于 

render:function (createElement) {
    return createElement(App)
  }

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

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

相关文章

异步编程 - 05 基于JDK中的Future实现异步编程(中)_CompletableFuture

文章目录 Pre概述显式设置CompletableFuture结果基于CompletableFuture实现异步计算与结果转换1&#xff09;基于runAsync系列方法实现无返回值的异步计算2&#xff09;基于supplyAsync系列方法实现有返回值的异步计算3&#xff09;基于thenRun实现异步任务A&#xff0c;执行完…

[管理与领导-73]:IT基层管理者 - 辅助技能 - 4- 职业发展规划 - 如何持续提升自我

目录 一、能力三核 1.1 专业知识能力 1.2 通用管理能力 1.3 优秀品质能力 二、能力发展策略 三、学习的四种渠道 四、有效的刻意练习 一、能力三核 1.1 专业知识能力 专业知识能力是指在特定领域或行业中所掌握的专业知识和技能。它是在特定领域内取得成功并为组织或个…

MySQL——DQL union合并、limit限制与DDL建表和删表

一、Union 合并 union:是实现两个查询结果的合并。 例如&#xff1a;当我们查询员工名字为manager 和 salesman的员工名字和 工作&#xff1f; select e.ename,e.job from emp e where e.jobmanager or e.job salesman; select e.ename,e.job from emp e where e.job in(man…

pandas笔记:显示中间的省略号

比如我们有这样一个数据&#xff08;Geolife中的数据&#xff09; 如何把中间的省略号完整地输出呢&#xff1f; pd.set_option(display.max_rows, None) data

【图解RabbitMQ-4】Docker安装RabbitMQ详细图文过程

&#x1f9d1;‍&#x1f4bb;作者名称&#xff1a;DaenCode &#x1f3a4;作者简介&#xff1a;CSDN实力新星&#xff0c;后端开发两年经验&#xff0c;曾担任甲方技术代表&#xff0c;业余独自创办智源恩创网络科技工作室。会点点Java相关技术栈、帆软报表、低代码平台快速开…

「网页开发|前端开发|Vue」06 公共组件与嵌套路由:让每一个页面都平等地拥有导航栏

本文主要介绍在多个页面存在相同部分时&#xff0c;如何提取公共组件然后在多个页面中导入组件重复使用来减少重复代码。在这基础上介绍了通过嵌套路由的方式来避免页面较多或公共部分较多的情况下&#xff0c;避免不断手动导入公共组件的麻烦&#xff0c;并且加快页面跳转的速…

烟感报警器单片机方案开发,解决方案

烟感报警器也叫做烟雾报警器。烟感报警器适用于火灾发生时有大量烟雾&#xff0c;而正常情况下无烟的场所。例如写字楼、医院、学校、博物馆等场所。烟感报警器一般安装于所需要保护或探测区域的天花板上&#xff0c;因火灾中烟雾比空气轻&#xff0c;更容易向上飘散&#xff0…

快速教程:如何更新AirPods固件!

让我们弄清楚一件事——你通常不需要学习如何更新AirPods固件。当苹果发布更新时&#xff0c;无论你使用的是标准的第三代AirPods还是AirPods Pro 2&#xff0c;固件都会自动安装在你的AirPods上。但是&#xff0c;这是一个很大的问题&#xff0c;但事情并不总是按计划进行。有…

【进阶篇】Redis缓存击穿, 穿透, 雪崩, 污染详解

【进阶篇】Redis缓存穿击, 穿透, 雪崩, 污染详解 文章目录 【进阶篇】Redis缓存穿击, 穿透, 雪崩, 污染详解0. 前言大纲缓存穿击缓存穿透缓存雪崩缓存污染 1. 什么是缓存穿透&#xff1f;1.1. 发生原因1.2. 导致问题1.3. 解决方案 2. 什么是缓存击穿3.1. 发生原因3.1. 解决方案…

PHP自己的框架留言板功能实现

目录 1、实现留言板功能效果 2、创建留言板数据表 3、控制器提交和显示方法 4、提交留言板html 5、留言板列表html 1、实现留言板功能效果 2、创建留言板数据表 CREATE TABLE msg (id int(11) NOT NULL AUTO_INCREMENT,name varchar(30) DEFAULT NULL COMMENT 留言板姓…

FullGC 40 次/天优化为 10 天 1 次

问题 前一段时间,线上服务器的 FullGC 非常频繁,平均一天 40 多次,而且隔几天就有服务器自动重启了,这表明服务器的状态已经非常不正常了,得到这么好的机会,当然要主动请求进行调优了。 未调优前的服务器 GC 数据,FullGC 非常频繁。 首先服务器的配置非常一般(2 核 4…

公园气象站:用科技力量,感知气象变化

在城市的喧嚣中&#xff0c;公园成为人们休闲娱乐的宁静之地。而在这些公园中的公园气象站静静地矗立着&#xff0c;不仅为公园的日常运营提供着重要数据&#xff0c;还在为游客的安全保驾护航。 用科技力量&#xff0c;感知气象变化 科技的创新为气象监测提供了更为精准的手…

iOS 16.4更新指南:问题解答与新功能一览

我应该更新到iOS 16.4吗&#xff1f;这是许多iPhone用户在新更新可用时问自己的一个常见问题。最新的iOS版本提供了各种功能和改进&#xff0c;因此更新的诱惑力很大。 但是&#xff0c;在更新之前&#xff0c;你应该考虑几个因素&#xff0c;以确保安装过程顺利成功。这些因素…

Android 九宫格布局

效果图 实现思路&#xff1a; 1.使用GridView来实现九宫格布局&#xff0c;设置numColumns3。 2.图标使用的是Font Awesome矢量图标&#xff0c;详情可以参考Android 在APP中使用 Font Awesome 图标_.fa-headphones_清山博客的博客-CSDN博客 实现步骤&#xff1a; 1.布局文…

关于vscode的GitLens插件里的FILE HISTORY理解

最近在用vscode的GitLens插件开发项目遇到这个疑问&#xff0c;先看图&#xff1a; 每当我点击FILE HISTORY 一个commit时&#xff0c;正常来说显示器会自动将点击的提交版本和它上一个提交版本进行比较&#xff0c;如果单纯这么理解的话就错了&#xff0c;因为GitLens的File …

基于循环队列和信号量的生产和消费者模型

这一节为什么要基于信号量来实现同一个模型&#xff0c;原因&#xff1a; void push(const T& in){pthread_mutex_lock(&_lock);while(is_Full()){//这里说明阻塞队列是满的&#xff0c;需要让生产者等待pthread_cond_wait(&_pcond,&_lock);}//这里说明阻塞队列…

jupyter 格式化与快捷键

1、标题&#xff1a; # 一级标题 ## 二级标题 ### 三级标题 2、 加粗文本&#xff1a; **加粗文本** 3、斜体文本&#xff1a; _斜体_ 4、删除线 ~删除线~ 5、高亮文本 高亮文本 6、区块引用 > 我是引用文字 >> 我是第二层 >&g…

提高广播新闻自动语音识别模型的准确性

语音识别技术的存在让机器能够听懂人类的语言&#xff0c;让机器理解人类的语言。语音识别技术发展至今&#xff0c;已经应运而上了各种各样的语音智能助手&#xff0c;可能有一天我们身边的物体都能和我们说话&#xff0c;万物相连的时代也如期而至。 数据从何而来&#xff1…

FPN模型

【简介】 2017年&#xff0c;T.-Y.Lin等人在Faster RCNN的基础上进一步提出了特征金字塔网络FPN(Feature Pyramid Networks)技术。在FPN技术出现之前&#xff0c;大多数检测算法的检测头都位于网络的最顶层(最深层)&#xff0c;虽说最深层的特征具备更丰富的语义信息&#xff0…

Mybatis 动态SQL - 使用foreach标签查询数据、批量新增、批量修改、删除数据

前面我们介绍了使用Mybatis完成数据的增删改查&#xff0c;并且也了解了如何在Mybatis中使用JDK的日志系统打印日志&#xff1b;本篇我们介绍使用Mybatis的动态SQL完成查询数据、批量新增、批量修改、删除数据。 如果您对数据的增删改查操作和Mybatis集成JDK日志系统不太了解&…