element(兼容2.72以下的版本)实现树形数据+复选框的效果

news2024/12/23 16:11:09

         用最新的element是可以实现树形数据的展示,但是没有复选框效果,用2.72以前的版本的话,是根本没有展开树形数据的效果,也没有复选框效果,

        需求:在2.72以下的老版本上做一个树形展示的效果,并且还要有复选框

        分享下从查找资料到解决问题的心酸之路,如果着急要效果代码的,请直接看最后一步!!!

需求效果图:

调研之路: 

element 2.72以上的版本效果与入口:点我

如下所示: 只有树形的效果,如果想要复选框效果,点我进入

 element 2.5.4的版本效果与入口:点我

注意:只能支持一个展开行类似的效果,没有复选框

 解决具体步骤:

1、思路:前提  只有展开行的效果

1、我们要给他加一个复选框的效果

2、我们要在复选框加一个icon  图标来控制他的展开与关闭

3、我们既要实现效果,有不能展示它默认的这个展示开关(因为他每一行都有,不满足树形的要求,我们只要求有子级的才可以有开关)

2、添加复选框的效果

        因为是自定义的,所以我们使用element的header插槽,保证只有一个,这个复选框是总复选框,然后再是每一行的复选框, 用  checks  字段来控制他的复选框是否勾选,这个字段是我们自己加在数据里的。

   <el-table-column width="80">
      <template slot="header" slot-scope="scope">
        <el-checkbox
          v-model="allCheckout"
          style="padding-left: 10px"
          @change="checkAllFun()"
        />
      </template>
      <template slot-scope="scope">
        <div style="position: relative">
          <el-checkbox
            v-model="scope.row.checks"
            style="padding-left: 10px"
            @change="checkChange(scope.row)"
          />
        </div>
      </template>
    </el-table-column>

总全选的事件操作:点击总全选,所有的数据都跟着改变

data:
    allCheckout:false

methods:    
// 总全选点击事件
      checkAllFun() {
        this.tableData.forEach(items => {
          this.$set(items, "checks", this.allCheckout);
          if (items.children) {
            items.children.forEach((item) => {
              this.$set(item, "checks", this.allCheckout);
            });
          }
        })
      },

单个复选框的点击事件

单个复选框的点击逻辑相对多分为三种:

1、一级复选框无子级的点击

2、一级复选框有子级的点击

3、二级复选框无子级的点击

以及他们三个点击后,对总复选框的影响

      //插槽复选框逻辑
      checkChange(row) {
        // expend 父级复选框
        if (row.children) {
          if (row.checks) {
            row.children.map((item) => {
              this.$set(item, "checks", true);
            });
            this.$set(row, "checks", true);
          } else {
            row.children.map((item) => {
              this.$set(item, "checks", false);
            });
            this.$set(row, "checks", false);
          }
        }else{
          // expend 子级复选框
          if(row.checks == undefined) row.checks = false
          this.$set(row, "checks", row.checks)
          const findTypeArr = this.tableData.filter(v=>v.id == row.id)
          let jb_type = ''
          if(findTypeArr.length>0){
            jb_type = '1'
          }else{
            jb_type = '2'
          }
          // 一级的操作
          if(jb_type == '1' && !row.checks){
            this.allCheckout = false
          }
          if(jb_type == '1' && row.checks){
            this.allCheckSetFun()
          }
          // 二级操作
          if(jb_type == '2' && !row.checks){
            this.allCheckout = false
            this.tableData.forEach(one => {
              if (one.children && one.children.length > 0) {
                one.children.forEach(two => {
                  if (two.id == row.id) {
                    this.$set(one, "checks", false)
                  }
                })
              }
            })
          }
          if(jb_type == '2' && row.checks){
            this.tableData.forEach(one => {
              if (one.children && one.children.length > 0) {
                one.children.forEach(two => {
                  if (two.id == row.id) {
                    let twoSelArr = one.children.filter(v=>v.checks)
                    if(twoSelArr.length == one.children.length){
                      this.$set(one, "checks", true)
                    }else{
                      this.$set(one, "checks", false)
                    }
                  }
                })
              }
            })
          }
        }
        // 刷新外部总全选状态
        this.allCheckSetFun()
        // 刷新
        this.uploadTable = false
        this.$nextTick(()=>{
          this.uploadTable = true
        })

      },
      // 修改外部总勾选
      allCheckSetFun(){
        let oneSelArr = this.tableData.filter(v=>v.checks)
        if(oneSelArr.length == this.tableData.length){
          this.allCheckout = true
        }else{
          this.allCheckout = false
        }
        this.getNowSelDataTwoType()
      },

3、我们要添加,点击自定义的icon来控制本身的展开与关闭事件

1)添加icon图标

这里只涉及子级的复选框,然后定义  expend  字段来表示是否打开

<template slot-scope="scope">
   <div style="position: relative">
      <el-checkbox
         v-model="scope.row.checks"
         style="padding-left: 10px"
         @change="checkChange(scope.row)"
       />
      <span class="expendIcon" v-if="scope.row.children && scope.row.children.length>0" @click="expendClick(scope.row,scope.row.expend)">
         <i class="el-icon-arrow-right" v-if="!scope.row.expend"></i>
         <i class="el-icon-arrow-down" v-if="scope.row.expend"></i>
       </span>
    </div>
</template>

2)点击图标,展开或者关闭当前行的展开行

data里面需要添加两个属性,第一个是唯一字段,第二个是数组,数组内部是展开的id信息

         row-key="id"
        :expand-row-keys="expandRowArr"

然后点击事件里面,动态修改他的 expandRowArr

data

    expandRowArr:[],//展开内容


methods:

// 是否展开
expendClick(row,title){
   if(!title){
      // 打开
      this.expandRowArr.push(row.id)
      this.tableData.forEach(items => {
        if(items.id == row.id){
          if(items.expend == undefined) items.expend = false
            this.$set(items, "expend", true);
          }
       })
     }else{
      // 关闭
       let oldArr = this.expandRowArr
       let newArr = []
       oldArr.forEach(item=>{
          if(item != row.id){
            newArr.push(item)
          }
       })
       this.expandRowArr = newArr
       this.tableData.forEach(items => {
          // this.$refs.multipleTable.data.forEach(items => {
          if(items.id == row.id){
            this.$set(items, "expend", false);
          }
       })
    }
},

3) 功能实现以后,我们要隐藏掉他的原本的展开与关闭开关

 <el-table-column type="expand" width="1">
      <template slot-scope="props">
            //展开后的内容...
        
      </template>
</el-table-column>

4、到目前位置,功能都有了,在我们封装的内容里面增加支持插槽与render函数

<template v-for="(column, index) in columns">
      <!-- slot 添加自定义配置项 -->
      <slot v-if="column.slot" :name="column.slot" :tit='index'></slot>
      <!-- 默认渲染列-渲染每一列的汉字 -->
      <el-table-column
        v-else
        :prop="column.prop"
        :label="column.title"
        :align="column.align"
        :width="column.width"
        :show-overflow-tooltip="true">
        <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]}}</span>
            </template>
          </template>
          <!--render函数-->
          <template v-else>
            <expandDom :column="column" :row="scope.row" :render="column.render" :index="index"></expandDom>
          </template>
        </template>
      </el-table-column>
    </template>
components: {
      /**
       * render函数渲染组件
       * */
      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)
        }
      }
    },

源码分享:

注意:展开内容请根据自己的需要进行改动,我这里是私有功能

引入代码:

 <checkTable ref="checkTable" :columns="productColumns" :tableData="productList" >
     <el-table-column slot="col_slot_1" label="商品列表" width="180">
        <template slot-scope="scope">
           <img :src="scope.row.goods_image" class="goods-image" />
        </template>
     </el-table-column>
</checkTable>


data:
productColumns:{
    slot:'col_slot_1'
    
}

productList:[{
    id:1,
    name:'张三',
    children:[{ //有该字段的有子级
        id:1,
        name:'张三儿子',
    }]

}]

封装代码:checkTable.vue

<template>
  <el-table
    v-if="uploadTable"
    class="multipleTable"
    ref="multipleTable"
    border
    row-key="id"
    :expand-row-keys="expandRowArr"
    :data="tableData"
  >
    <el-table-column width="80">
      <template slot="header" slot-scope="scope">
        <el-checkbox
          v-model="allCheckout"
          style="padding-left: 10px"
          @change="checkAllFun()"
        />
      </template>
      <template slot-scope="scope">
        <div style="position: relative">
          <el-checkbox
            v-model="scope.row.checks"
            style="padding-left: 10px"
            @change="checkChange(scope.row)"
          />
          <span class="expendIcon" v-if="scope.row.children && scope.row.children.length>0" @click="expendClick(scope.row,scope.row.expend)">
            <i class="el-icon-arrow-right" v-if="!scope.row.expend"></i>
            <i class="el-icon-arrow-down" v-if="scope.row.expend"></i>
          </span>
        </div>
      </template>
    </el-table-column>
    <el-table-column type="expand" width="1">
      <template slot-scope="props">
            //展开的内容展示
             ...
    

      </template>
    </el-table-column>
    <template v-for="(column, index) in columns">
      <!-- slot 添加自定义配置项 -->
      <slot v-if="column.slot" :name="column.slot" :tit='index'></slot>
      <!-- 默认渲染列-渲染每一列的汉字 -->
      <el-table-column
        v-else
        :prop="column.prop"
        :label="column.title"
        :align="column.align"
        :width="column.width"
        :show-overflow-tooltip="true">
        <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]}}</span>
            </template>
          </template>
          <!--render函数-->
          <template v-else>
            <expandDom :column="column" :row="scope.row" :render="column.render" :index="index"></expandDom>
          </template>
        </template>
      </el-table-column>
    </template>



  </el-table>

</template>

<script>
  /**
   * @封装的复选框加列表expend展开功能列表
   * @createTime 2023.6
   * @auth ry
   * */
  export default {
    name: "checkTable.vue",
    props:{
      // 表格数据
      tableData:{
        type: Array,
        deep:true,
        immediate:true,
        default:()=>[]

      },
      //表头
      columns: {
        type:Array,
        default:()=>[]
      },
      tableClass: {
        type: String,
        default: 'checkTable'
      },
      ifChangeTrue:{
        type:String | Number,
      }
    },
    watch:{
      tableData(arr){
        this.tableData.map(item=>{
          if(item.children && item.children.length>0) item.expend = false
          return item
        })
      }
    },
    components: {
      /**
       * render函数渲染组件
       * */
      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{
        allCheckout: false, //全选
        expandRowArr:[],//展开内容
        uploadTable:true,
      }
    },
    mounted(){
      this.clearCheckFun()
    },
    methods:{
      // 获取当前选中的数据,有子级的,子级+父级
      getNowSelData(){
        let selData = []
        this.tableData.forEach(item=>{
          // 一级无子级
          if(item.checks && !item.children){
            selData.push(item)
          }
          // 一级有子级
          if(item.checks && item.children && item.children.length){
            selData.push(item)
            selData = selData.concat(item.children)
          }
          // 二级无子级
          if(!item.checks && item.children && item.children.length){
            item.children.forEach(two=>{
              if(two.checks){
                selData.push(two)
              }
            })
          }
        })
        return selData
      },
      // 获取当前选中的数据-有子级的,父级(内部有children)
      getNowSelDataOneType(){
        let selData = []
        this.tableData.forEach(item=> {
          // 一级无子级
          if(item.checks && !item.children){
            selData.push(item)
          }
          // 一级有子级
          if(item.checks && item.children && item.children.length){
            selData.push(item)
          }
          // 二级无子级
          if(!item.checks && item.children && item.children.length){
            item.children.forEach(two=>{
              if(two.checks){
                selData.push(two)
              }
            })
          }
        })
        return selData
      },
      // 获取当前选中的数据-有子级是子级,没有则是他自己
      getNowSelDataTwoType(){
        let selData = []
        this.tableData.forEach(item=> {
          // 一级无子级
          if(item.checks && !item.children){
            selData.push(item)
          }
          // 一级有子级
          if(item.checks && item.children && item.children.length){
            selData = selData.concat(item.children)
          }
          // 二级无子级
          if(!item.checks && item.children && item.children.length){
            item.children.forEach(two=>{
              if(two.checks){
                selData.push(two)
              }
            })
          }
        })
        this.$emit('changeShopNum',selData)
        return selData
      },
      // 清理选中效果
      clearCheckFun(){
        setTimeout(()=>{
          if(this.ifChangeTrue=='1'){
            this.allCheckout = true
          }else{
            this.allCheckout = false
          }

          this.checkAllFun()
        },500)
      },
      // 总全选点击事件
      checkAllFun() {
        this.tableData.forEach(items => {
          this.$set(items, "checks", this.allCheckout);
          if (items.children) {
            items.children.forEach((item) => {
              this.$set(item, "checks", this.allCheckout);
            });
          }
        })
        this.getNowSelDataTwoType()
      },
      //插槽复选框逻辑
      checkChange(row) {
        // expend 父级复选框
        if (row.children) {
          if (row.checks) {
            row.children.map((item) => {
              this.$set(item, "checks", true);
            });
            this.$set(row, "checks", true);
          } else {
            row.children.map((item) => {
              this.$set(item, "checks", false);
            });
            this.$set(row, "checks", false);
          }
        }else{
          // expend 子级复选框
          if(row.checks == undefined) row.checks = false
          this.$set(row, "checks", row.checks)
          const findTypeArr = this.tableData.filter(v=>v.id == row.id)
          let jb_type = ''
          if(findTypeArr.length>0){
            jb_type = '1'
          }else{
            jb_type = '2'
          }
          // 一级的操作
          if(jb_type == '1' && !row.checks){
            this.allCheckout = false
          }
          if(jb_type == '1' && row.checks){
            this.allCheckSetFun()
          }
          // 二级操作
          if(jb_type == '2' && !row.checks){
            this.allCheckout = false
            this.tableData.forEach(one => {
              if (one.children && one.children.length > 0) {
                one.children.forEach(two => {
                  if (two.id == row.id) {
                    this.$set(one, "checks", false)
                  }
                })
              }
            })
          }
          if(jb_type == '2' && row.checks){
            this.tableData.forEach(one => {
              if (one.children && one.children.length > 0) {
                one.children.forEach(two => {
                  if (two.id == row.id) {
                    let twoSelArr = one.children.filter(v=>v.checks)
                    if(twoSelArr.length == one.children.length){
                      this.$set(one, "checks", true)
                    }else{
                      this.$set(one, "checks", false)
                    }
                  }
                })
              }
            })
          }
        }
        // 刷新外部总全选状态
        this.allCheckSetFun()
        // 刷新
        this.uploadTable = false
        this.$nextTick(()=>{
          this.uploadTable = true
        })

      },
      // 修改外部总勾选
      allCheckSetFun(){
        let oneSelArr = this.tableData.filter(v=>v.checks)
        if(oneSelArr.length == this.tableData.length){
          this.allCheckout = true
        }else{
          this.allCheckout = false
        }
        this.getNowSelDataTwoType()
      },
      // 是否展开
      expendClick(row,title){
        if(!title){
          // 打开
          this.expandRowArr.push(row.id)
          this.tableData.forEach(items => {
            if(items.id == row.id){
              if(items.expend == undefined) items.expend = false
              this.$set(items, "expend", true);
            }
          })
        }else{
          // 关闭
          let oldArr = this.expandRowArr
          let newArr = []
          oldArr.forEach(item=>{
            if(item != row.id){
              newArr.push(item)
            }
          })
          this.expandRowArr = newArr
          this.tableData.forEach(items => {
            // this.$refs.multipleTable.data.forEach(items => {
            if(items.id == row.id){
              this.$set(items, "expend", false);
            }
          })
        }
      },

    }
  }
</script>

<style scoped>
  .expendIcon{
    position: absolute;
    right:10px;
    cursor: pointer;
    margin-left:10px;
  }
  .expandUl{
    display: flex;
    padding:10px 0 10px 30px;
  }
  .expandUlSon{
    width: 95%;
    display: flex;
    justify-content: space-around;
  }
  .expandUlSonDiv{
    min-width: 100px;
    margin-left:20px;
  }
</style>

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

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

相关文章

初识Notes Domino 14 Drop1

大家好&#xff0c;才是真的好。 周末花了点时间&#xff0c;安装了一下Notes Domino 14 Drop1版本。考虑到大多数人的习惯&#xff0c;没采用Docker或K8s方式来部署&#xff0c;也没采用一键配置功能&#xff0c;依旧通过传统方式一步一步进行安装和配置&#xff0c;这样大家…

【Spring Boot 初识丨五】beans 详解

上一篇讲了 Spring Boot 的主程序类 本篇来讲一讲 beans 详解 Spring Boot 初识&#xff1a; 【Spring Boot 初识丨一】入门实战 【Spring Boot 初识丨二】maven 【Spring Boot 初识丨三】starter 【Spring Boot 初识丨四】主应用类 beans 一、 定义二、 命名三、 生命周期3.1 …

Linux防火墙学习笔记7

安装apahce&#xff1a; yum install -y httpd echo 123 >> /var/www/html/index.html systemctl start httpd curl http://localhost 然后给iptables插入一条防火墙策略&#xff1a; iptables -t filter -I INPUT -p tcp --dport 80 -j ACCEPT注意&#xff1a;这里使…

【Spring学习之更简单的读取和存储Bean对象】教会你使用五大类注解和方法注解去存储 Bean 对象

前言&#xff1a; &#x1f49e;&#x1f49e;今天我们依然是学习Spring&#xff0c;这里我们会更加了解Spring的知识&#xff0c;知道Spring是怎么更加简单的读取和存储Bean对象的。也会让大家对Spring更加了解。 &#x1f49f;&#x1f49f;前路漫漫&#xff0c;希望大家坚持…

高能预警!融云WICC发布《社交泛娱乐出海作战地图》

最近圈子里风很大的《社交泛娱乐出海作战地图》, 必须说&#xff0c;真的有亿点点厉害&#xff01;这简直是一张集社交泛娱乐市场、品类知识和出海实战指南于一体的教材级地图&#xff0c;实感入手不亏。关注【融云全球互联网通信云】了解更多 首先&#xff0c;容我先秀一把实…

Definition of regularity in PDE theory

Regularity is one of the vague yet very useful terms to talk about a vast variety of results in a uniform way. Other examples of such words include “dynamics” in dynamical systems (I have never seen a real definition of this term but everyone uses it, an…

学习Vue 之 创建一个 Vue 应用

文章目录 Vue.js概述了解 Vue创建一个 Vue 应用参考 Vue.js 概述 计划学习前端&#xff0c;已有一些HTML&#xff0c;js&#xff0c;CSS的基础知识&#xff0c;下一步学习Vue.js。 以下是一些适合新手的Vue.js教程&#xff0c;你可以根据自己的实际情况和需求选择适合自己的…

独家揭秘:Kotlin编译器前端—解析阶段

独家揭秘&#xff1a;Kotlin编译器前端&#xff1a;解析阶段 Kotlin编译器对我来说就像一个黑盒子&#xff0c;虽然有关于Kotlin PSI在IDE插件中有使用的文档&#xff0c;但除了源代码中留下的注释之外&#xff0c;几乎没有其他信息可用。接下来的文章中我们来探索Kotlin编译器…

6. WebGPU 将图像导入纹理

我们在上一篇文章中介绍了有关使用纹理的一些基础知识。在本文中&#xff0c;我们将介绍从图像导入纹理。 在上一篇文章中&#xff0c;通过调用 device.createTexture 创建了一个纹理&#xff0c;然后通过调用 device.queue.writeTexture 将数据放入纹理中。 device.queue 上还…

Axure教程—穿梭框(中继器+动态面板)

本文将教大家如何用AXURE中动态面板和中继器制作穿梭框效果 一、效果 预览地址&#xff1a;https://8k99mh.axshare.com 下载地址&#xff1a;https://download.csdn.net/download/weixin_43516258/87897661?spm1001.2014.3001.5503 二、功能 在待选区域选项中可以选择一个选…

CURL获取与使用

背景&#xff1a;在日常工作中&#xff0c;经常会遇到需要获取CURL构造请求来进行问题定位&#xff0c;那如何获取及使用CURL则成为一个测试人员必备的技能&#xff1b; CURL是什么 CURL是一个命令行工具&#xff0c;开发人员使用它来与服务器进行数据交互。 如何获取完整 C…

Python开源自动化工具Playwright安装及介绍

目录 前言 1、Playwright介绍 2、Playwright安装 3、实操演示 4、小结 总结&#xff1a; 前言 微软开源了一个非常强大的自动化项目叫 playwright-python 它支持主流的浏览器&#xff0c;包含&#xff1a;Chrome、Firefox、Safari、Microsoft Edge 等&#xff0c;同时支…

简单使用Hystrix

使用Hystrix之前&#xff0c;需要先对SpringCloud有所了解&#xff0c;然后才会使用的顺畅&#xff0c;它是我们SpringCould的一种保护机制&#xff0c;非常好用。 下面直接开始 先导入Hystrix所需要的依赖 <!-- 引入openfiegn--> <dependency> <groupId>org…

Java学习笔记(视频:韩顺平老师)3.0

如果你喜欢这篇文章的话&#xff0c;请给作者点赞哟&#xff0c;你的支持是我不断前进的动力。 因为作者能力水平有限&#xff0c;欢迎各位大佬指导。 目录 如果你喜欢这篇文章的话&#xff0c;请给作者点赞哟&#xff0c;你的支持是我不断前进的动力。 算数运算符 号使用…

体验 TDengine 3.0 高性能的第一步,请学会控制建表策略

正如我们之前所言&#xff0c;在 3.0 当中&#xff0c;我们在产品底层做了很大的变化调整&#xff0c;除了架构更加科学高效以外&#xff0c;用户体验也是我们重点优化的方向。以之前一篇文章为例&#xff1a;对于 Update 功能&#xff0c;用户不再需要任何配置 &#xff0c;默…

社交泛娱乐出海如何抓住AIGC?我在融云WICC上看到了答案

大模型掀起的AIGC时代&#xff0c;所有企业的所有业务与产品都值得利用大模型技术重做一遍&#xff0c;接下来也将有越来越多依托AIGC技术的创新应用涌现。关注【融云全球互联网通信云】了解更多 在社交泛娱乐赛道&#xff0c;AI大模型技术也呈现出了加速落地的态势。日前&…

功能测试如何转型自动化测试

在互联网行业&#xff0c;我们是那些被遗忘的技术人。 很多人都觉得&#xff0c;传统开发、运维才是技术含量的一个工作。 但是测试的入门门槛比较低&#xff0c;所做的事情相对有限&#xff0c; 这是我之前跟一些大型互联网软件测试负责人大牛们聊天的时候发现&#xff0c;…

学网络安全常用的10大工具

从事网络安全工作&#xff0c;手上自然离不开一些重要的网络安全工具。今天&#xff0c;分享10大网络安全工具。 一、Kali Linux Kali 是一个基于 Debian 的 Linux 发行版。它的目标就是为了简单&#xff1a;在一个实用的工具包里尽可能多的包含渗透和审计工具。Kali 实现了这…

【JMeter】 二次开发插件开发 Dubbo 接口测试插件浅析

概述 在一些企业中&#xff0c;各类业务系统非常丰富&#xff0c;相互之间或对外提供很多的服务或接口 这些服务或接口中&#xff0c;有很多是需要强契约约束的&#xff0c;服务的提供方、服务的使用方必须遵守相同契约 这类服务最典型的就是RPC&#xff0c;其中应用广泛的有Du…

一文读懂,WAF阻止恶意攻击的8种方法

WAF&#xff08;Web 应用程序防火墙&#xff09;是应用程序和互联网流量之间的第一道防线&#xff0c;它监视和过滤 Internet 流量以阻止不良流量和恶意请求&#xff0c;WAF 是确保 Web 服务的可用性和完整性的重要安全解决方案。 它通过充当保护 Web 应用程序服务器免受恶意客…