• 原生table表头固定写法和checkbox样式重写


    一个由面试题引起的案例分享

    需求如下:

     在不使用任何UI框架的前提下完成上图效果

    提供数据源的函数如下:

    function generate () {
      let data = [['Index', `Data1`, `Data2`, `Data3`]]
    
      for (let i = 0; i < 15; i++) {
        data.push([
          i+1, 
          parseInt(Date.now() + Math.random() * 10000000).toString(16), 
          parseInt(Date.now() + Math.random() * 10000000).toString(16),
          parseInt(Date.now() + Math.random() * 10000000).toString(16)
        ])
      }
      return data
    }

    细节要求:

    1. 表头固定:当表格高度超出外部容器高度时,表格内部出现垂直滚动条,表头始终处于顶部可见

    2. 第一列为多选列,支持单行勾选和全选。当部分行选中时,表头的勾选状态为“不确定”(即勾选框填充为横线),参考描述中的视图

    代码实现如下(vue):

    页面代码:

    <template>
      <div class="container">
        <table cellspacing="0">
          <thead>
          <tr>
            <th class="w2">
              <span class="checkbox-span"
                    :class="[isAllChecked ? 'is-checked' : (isIndeterminate ? 'is-indeterminate' : '')]">
                <span class="checkbox-inner" @click="getAllChecked()"></span>
                <input type="checkbox" class="checkbox-original" ref="allCheckedRef"/>
              </span>
            </th>
            <th v-for="item in allData[0]" class="tl">{{item}}</th>
          </tr>
          </thead>
          <tbody>
          <tr v-for="items in contentData">
            <td class="w2">
              <input type="checkbox" :value="items[0]" v-model="checkedId"/></td>
            <td v-for="item in items" class="tl">
              {{item}}
            </td>
          </tr>
          </tbody>
        </table>
      </div>
    </template>

    JS代码:

    <script>
      export default {
        name: "Home",
        data() {
          return {
            // 所有的源数据(包括表头和内容)
            allData: [],
            // 内容数据
            contentData: [],
            // 是否全部选中
            isAllChecked: false,
            // 是否部分选中
            isIndeterminate: false,
            // 所有的id
            ids: [],
            // 选中的id
            checkedId: [],
          }
        },
        mounted() {
          // 获取源数据
          this.generate();
          // 获取所有的ids
          this.getIds();
        },
        watch: {
          // 监听选中的id
          checkedId: {
            handler: function (val, oldVal) {
              // 如果选中的id和全部id长度相等,表示全选中
              if (val.length === this.ids.length) {
                // 设置全选状态为true
                this.isAllChecked = true;
                // 设置部分选中状态为false
                this.$refs.allCheckedRef.indeterminate = false;
                this.isIndeterminate = false;
                // 表示部分选中
              } else if (val.length != 0 && val.length != this.ids.length) {
                this.isAllChecked = false;
                this.$refs.allCheckedRef.indeterminate = true;
                this.isIndeterminate = true;
              } else {
                // 表示一个都没有选中
                this.isAllChecked = false;
                this.$refs.allCheckedRef.indeterminate = false;
                this.isIndeterminate = false;
              }
    
              console.log("提交到后台的id");
              console.log(val);
            },
            deep: true
          }
        },
        methods: {
          // 点击全选按钮事件
          getAllChecked() {
            this.isAllChecked = !this.isAllChecked;
            // 全选了
            if (this.isAllChecked) {
              this.checkedId = [];
              // 将选中的id设置为所有的id,提交到后台
              for (let i = 0; i < this.ids.length; i++) {
                this.checkedId.push(this.ids[i]);
              }
            // 没有全选
            } else {
              this.checkedId = [];
            }
          },
          // 获取所有的ids
          getIds() {
            if (this.allData && this.allData.length > 0) {
              if (this.contentData && this.contentData.length > 0) {
                for (let i = 0; i < this.contentData.length; i++) {
                  this.ids.push(this.contentData[i][0]);
                }
              }
            }
          },
          // 获取源数据
          generate() {
            let data = [['Index', `Data1`, `Data2`, `Data3`]]
            for (let i = 0; i < 15; i++) {
              data.push([
                i + 1,
                parseInt(Date.now() + Math.random() * 10000000).toString(16),
                parseInt(Date.now() + Math.random() * 10000000).toString(16),
                parseInt(Date.now() + Math.random() * 10000000).toString(16)
              ])
            }
            this.allData = data;
            // 获取内容数据
            this.contentData = this.allData.slice(1);
          }
        },
    
      }
    </script>

    样式代码:

    <style scoped lang="scss">
    
      table {
        margin: 3rem auto;
        width: 20rem;
        overflow: scroll;
      }
      /***************重写 checkbox 样式 start*****************/
      .checkbox-span {
        white-space: nowrap;
        cursor: pointer;
        outline: none;
        display: inline-block;
        line-height: 1;
        position: relative;
        vertical-align: middle;
      }
    
    
    
      .checkbox-inner {
        display: inline-block;
        position: relative;
        border: 1px solid rgb(44, 62, 80);
        border-radius: 2px;
        box-sizing: border-box;
        width: 14px;
        height: 14px;
        background-color: #fff;
        z-index: 1;
        transition: border-color .25s cubic-bezier(.71, -.46, .29, 1.46), background-color .25s cubic-bezier(.71, -.46, .29, 1.46);
    
        /*鼠标悬浮样式*/
        &:hover {
          border-color: #409eff;
        }
    
        &:after {
          box-sizing: content-box;
          content: "";
          border: 1px solid #fff;
          border-left: 0;
          border-top: 0;
          height: 7px;
          left: 4px;
          position: absolute;
          top: 1px;
          transform: rotate(
              45deg
          ) scaleY(0);
          width: 3px;
          transition: transform .15s ease-in .05s;
          transform-origin: center;
        }
    
      }
    
      /*默认checkbox样式*/
      .checkbox-original {
        opacity: 0;
        outline: none;
        position: absolute;
        margin: 0;
        width: 0;
        height: 0;
        z-index: -1;
      }
    
      /*部分选中*/
      .checkbox-span.is-indeterminate .checkbox-inner {
        background-color: #409eff;
        border-color: #409eff;
    
        &:before {
          content: "";
          position: absolute;
          display: block;
          background-color: #fff;
          height: 2px;
          transform: scale(.5);
          left: 0;
          right: 0;
          top: 5px;
        }
      }
    
      /*全部选中*/
      .checkbox-span.is-checked .checkbox-inner {
        background-color: #409eff;
        border-color: #409eff;
    
        &:after {
          transform: rotate(
              45deg
          ) scaleY(1);
        }
      }
    
      /***************重写 checkbox 样式 end*****************/
    
      th, td {
        border: 1px solid rgb(225, 225, 225);
        min-width: 10rem;
        height: 0.5rem;
        padding: 0.3rem;
      }
    
      thead {
        display: block;
      }
    
      tbody {
        display: block;
        height: 23rem;
        overflow-y: scroll;
      }
    
      .tl {
        text-align: left;
      }
      .w2 {
        min-width: 2rem;
      }
      th, tr:nth-child(even){
        background-color: rgb(249,249,249);
      }
    
      /********** 设置滚动条的样式 start************ */
      ::-webkit-scrollbar {
        width: 5px;
      }
    
      /* 滚动槽 */
      ::-webkit-scrollbar-track {
        border-radius: 10px;
      }
    
      /* 滚动条滑块 */
      ::-webkit-scrollbar-thumb {
        border-radius: 10px;
        background: rgba(0, 0, 0, 0.1);
      }
    
      /********** 设置滚动条的样式 end ************ */
    </style>

    该demo是在vue环境中写的,使用的时候需要vue环境,样式使用了scss编译器

    主要参考价值在于:

    1.原生table实现表头固定,内容出现滚动条

    2.重写checkbox样式,使最上方checkbox在部分选中是展示蓝色背景、白色横线样式效果

    3.因为时间有限,没有改写所有的checkbox,只改写了最上方的一个

    4.将所有的ID和选中的ID存入数组,通过遍历来记录和读取该项选中与否

  • 相关阅读:
    SVN——Jenkins自动发布
    IIS之虚拟目录学习
    SVN迁移
    通过配置host,自定义域名让本地访问
    比较两个时间的大小 举例:CompareDate("12:00","11:15")
    [转]SQL Server 批量完整备份
    js前台编码,asp.net后台解码 防止前台传值到后台为乱码
    前端将图片二进制流显示在html端
    【转】解析<button>和<input type="button"> 的区别
    利用bat批处理——实现数据库的自动备份和删除
  • 原文地址:https://www.cnblogs.com/lilililiwang/p/14894254.html
Copyright © 2020-2023  润新知