分页
// 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的数据是否全部选中来控制
}
}
})
上面totalMoney和totalNum计算属性可以复用成一个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)// 全部肥羊的工资
}
}
}