table的一些常用操作(vue)

151 阅读2分钟

分页

// js部分
export default {
  data(){
    return {
      num:1
    }
  },
  props:['pageTotal','pageNumber'],// props的一种方式 或者可以写对象type校验那种
  props:{
      pageTotal:{
          type:Number,// 定义传入的类型
          default:function(){
              return 0// 默认0 防止没有传入
          }
      },
      pageNumber:{
          type:Number,
          default:function(){
              return 0// 默认0
          }
      },
  },
  created(){
      this.num = this.pageNumber;// 赋值给分页组件的num,用num来操作当前页
  },
  methods:{
          //当前页
        curPage(i){  
            if(i=='...') return;// 分页如果是字符暂时先不请求
            this.num = i;
            this.$emit('update:pageNumber',i)// 直接修改父组件的pageNumber
        },
        prePage(){ 
        if(i=='...') return;// 分页如果是字符暂时先不请求
        if(this.pageNumber>1){
          this.$emit('update:pageNumber',--this.num)// 方法1
          this.$emit('e-pagination',--this.num)// 方法2
        }
        },
        nextPage(){
        if(i=='...') return;// 分页如果是字符暂时先不请求
        if(this.pageNumber< this.pageTotal){
          this.$emit('update:pageNumber',++this.num)// 方法1
          this.$emit('e-pagination',--this.num)// 方法2 将分页组件的num传给调用的父组件使用
        }
        }
  },
  computed:{
  // 计算属性处理分页页面过多的情况,可以添加... 最多不能超过8条数据,不过每次要预留一个数据来点击
    pages(){
      let {pageNumber:start,pageTotal:end} = this.$props;// 解构起个别名
      if(end<10) return end;
      if(start<=4){// 前面
        return [1,2,3,4,5,'...',end]
      }else if(start>=end-4){// 后面
        return [1,'...',end-5,end-4,end-3,end-2,end-1,end]
      }else {// 中间
        return [1,'...',start-2,start-1,start,start+1,start+2,'...',end]
      }
      
    }
  },
}
// pagination.vue
<nav>
<ul class="pagination">
    <li @click="prePage()" :class="pageNumber<=1?'disabled':''">
        <a class="previous">
            <span> < </span>
        </a>
    </li>
    <li :class="pageNumber==index ?'active':''" v-for="index in pages" 
    :key="index" @click="curPage(index)">
    <a>{{index}}</a>
    </li>
    <li @click="nextPage()" :class="pageNumber>=pageTotal?'disabled':''">
        <a class="next">
            <span> > </span>
        </a>
    </li>
</ul>
</nav>
 // table/index.vue 调用分页
 // html部分 方法1:.sync直接将父组件属性传递给子组件Pagination
<pagination :pageTotal="page.pageTotal" :pageNumber.sync="page.pageNumber" />
// 方法2 @e-pagination接受到子组件的num数据来请求getData
<pagination :pageTotal="page.pageTotal" @e-pagination="getData()" />

 // js部分
 // data()
 page:{
  pageTotal:1,//总页数
  total:1, //总条数
  pageNumber:1, //页码
  pageSize:10//每页条数
}
  
import Pagination from './pagination.vue';// 引入
components: { pagination },// 注册分页组件
// .sync修饰符需要配合watch监听到变化
  watch:{
    'page.pageNumber'(newValue,oldValue){
      this.getData(newValue)
    }
  },
getList(i){  //获取数据
  this.page.pageNumber = i || this.page.pageNumber;
  // 
  this.$http({
    method:'get',
    url:`/xx/${this.page.pageNo}/${this.page.pageSize}`
  }).then(res=>{
   ...// 赋值total list
  })
}


增删改查,全选等

采用引入的方式vue,操作全选时需要控制表格里面的数据选中状态,同样在操作表格里的数据时,也要注意全选的状态,不过这里只针对数据一次性返回完全的情况,如果后端分页,需要另外处理

js部分:

window.onload = function(){
    new Vue({ })
}

表格的一些展示监听查询数量及字段变化,增删改查操作: 这里计算了用户的工资,用户数量,根据用户名称来前端模糊查询,后端返回数据不是前端需要的时候来使用(全局/局部)过滤器操作达到自己想要的数据。computed来计算data或者props等的一些属性直接展示在dom,还有一些vue @click的常用修饰符stop,once,prevent

 <div id='app'>
    <input v-model="input" type="text" placeholder="请输入查询"/>
    <button @click="editFlag=true">新增</button>
    <div v-show="editFlag">
      编辑/新增
      <input v-model="form.name" type="text" placeholder="请输入用户姓名"/>
    <input v-model="form.num" type="number" placeholder="请输入用户数量"/>
    <input v-model="form.sex" type="number" placeholder="选择用户性别"/>
    <input v-model="form.money" type="number" placeholder="请输入每月工资"/>
    <input v-model="form.dayMoney" type="number" placeholder="请输入每日工资"/>
    <input v-model="form.date" type="date" placeholder="出生日期"/>
    <button :disabled="form.id ||!form.name || !form.num || !form.sex|| !form.money || !form.dayMoney || !form.date" @click="addItem">提交添加</button>
    <button :disabled="!form.id || !form.name || !form.num || !form.sex|| !form.money || !form.dayMoney || !form.date" @click="editItem()">提交编辑</button>
    <button @click="editFlag=false">关闭</button>
    </div>
    <!-- 修饰符 -->
    <!-- <div @click="handleCheckAll">
      <button @change.stop="nowChange">全选(阻止了冒泡)</button>
    </div>
    <button @click.once="handleCheckAll">全选(点击只可一次)</button>
    <a href="https://juejin.cn/user/1183531281683373" @click.prevent="handleCheckAll">全选(去掉默认行为)</a> -->
    <table class="table">
      <thead>
        <tr>
          <th>
            全选<input type="checkbox" @change="handleCheckAll" v-model="checkAll">
          </th>
          <th>用户姓名</th>
          <th>用户数量</th>
          <th>用户性别</th>
          <th>出生日期</th>
          <th>工作</th>
          <th>每日工资</th>
          <th>每月工资</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="(item,i) in searchForm" :key="item.id">
          <th><input type="checkbox" @change="nowChange" v-model="item.check"></th>
          <td>{{item.name}}</td>
          <td>
            <button :disabled="item.num<=0" @click="item.num-=1">-</button>
            {{item.num}}
            <button @click="item.num+=10">+10</button>
        </td>
          <td>{{item.sex | stateFilter}}</td>
          <td>{{item.date | timeFilter}}</td>
          <td>{{item.work}}</td>
          <td>{{item.money |numFilter(1,'¥')}}</td>
          <td>{{item.dayMoney |numFilter}}</td>
          <td>
            <button @click="delItem(item,i)" :disabled="!item.check">删除</button>
            <button @click="openEdit(item)" :disabled="item.sex==1" >修改</button>
          </td>
        </tr>
        <tr>
          <td colspan="12" >{{totalNum}}个肥羊的工资总计:{{totalMoney | numFilter(2,'¥')}}</td>
      </tr>
      </tbody>
    </table>

  </div>
// 全局过滤器
Vue.filter('zeroFilter',(num)=>num<10?'0'+num:num);// 给小于10的数据展示为2位
Vue.filter('timeFilter',(tpm)=>new Date(tpm).toLocaleDateString());// 时间戳转换人类易懂的方式
let vm = new Vue({
el:'#app',
data:{
    checkAll:false,// 全选
    items:[],
    form:{
        id:null,
        name:'肥羊',
        sex:2,
        money:1,
        work:2,
        dayMoney:1,
        check:false,
        date:null,
    },// 添加
    editFlag:false,// 编辑/新增数据
    input:''// 查询

},
filters:{
    // 布局过滤器,cli里面写法不一样
    numFilter(state,len=2,type='$'){
        return type+Number(state).toFixed(len)// 保留len位小数点,金额数字
    },
    stateFilter(type){
        switch (type) {
            case 0:
            case 5:
                return '女生'
            case 1:
            case 7:
                return '男生'
            default:
                return '其他'
        }
    }
},
computed:{// 计算属性,用来计算操作data或者路由其他里面的一些属性,展示在html
    searchForm:function(){
        // 这里要慎用箭头函数,因为this
        return this.items.filter(v=>v.name.includes(this.input))// 根据name模糊查询table数据
    },
    totalNum:function(){
        // return this.items.reduce((total,now)=>total+now.num,0)// 计算table中肥羊多少个
        return this.searchForm.reduce((total,now)=>total+now.num,0)// 计算table中肥羊多少个

    },
    totalMoney:function(){
        return this.searchForm.reduce((total,now)=>total+now.num*now.money,0)// 全部肥羊的工资
    }
},
mounted(){
    for (let i = 0; i < 3; i++) {
        this.items = [...this.items,{id:i,name:'肥羊'+i+9,num:i,date:1656240278167,sex:i,work:'工作'+i,money:i,dayMoney:100+i,check:false}]
    }
},
methods:{
    // 新增元素
    addItem(){
        // 添加的时候全选需要重新设置
        this.checkAll = false
        //  Math.random()作为id容易重复,当然index也会重复,所以取累加的id最大的加一
        let id = Math.max(...this.items.map(v=>v.id))+1
        this.items.push({...this.form,id})// 或者es6的方法如下
        // this.items = [...this.items,{...this.form,id}]
    },
    // 删除元素
    delItem(item,i){
        // this.items.splice(i,1);// item用来操作其他关联列表或者用filter删除
        this.items = this.items.filter(v=>v.id!==item.id)
    },
    // 打开编辑框
    openEdit(item){
        this.editFlag=true
        this.form = {...item,date:new Date(item.date).toLocaleDateString().replace(/\//g,'-')}// 月份小于10需要加0,用于匹配input date "yyyy-MM-dd"
    },
    // 提交编辑
    editItem(){
        let index = this.items.findIndex(v=>this.form.id===v.id)
        console.log(`编辑第${index+1}个`)
        this.items[index] = this.form;
        this.$set(this.items,index,this.form)// 数组修改后需要让页面检测到
        // vue2的响应式官网 https://cn.vuejs.org/v2/guide/reactivity.html
        this.editFlag = false
    },
    // 全选 控制表格选中
    handleCheckAll(){
        console.log('全选')
        // this.checkAll = !this.checkAll click事件用这个,change事件不用
        this.items.forEach(item => {
            item.check = this.checkAll
        });
    },
    // 选中表格控制全选按钮状态
    nowChange(){
        console.log('table控制选中')
        // 方法一
        let selectNum = this.items.filter(item=>item.check).length// 选中的个数
        this.checkAll = selectNum===this.items.length ? true :false// 选中按钮的状态
        // 方法二
        // this.checkAll = this.items.every(i => i.check)// 全选按钮状态根据table的数据是否全部选中来控制
    }
}
})

上面totalMoneytotalNum计算属性可以复用成一个totals

<td colspan="12" >
{{totals('count')}}个肥羊的工资总计:{{totals('money') | numFilter(2,'¥')}}
</td>
 // 复用计算属性 totalNum totalMoney
totals:function(){
    return function(type){
        if(type==='count'){
            return this.searchForm.reduce((total,now)=>total+now.num,0)// 计算table中肥羊多少个
        }else{
            return this.searchForm.reduce((total,now)=>total+now.num*now.money,0)// 全部肥羊的工资
        }
    }
}