课程表的实现,我想了很久,在没有现成组件库的情况下实现,我主要是用了vant weapp的宫格和单选框来实现,主要的难点有以下两个方面:
返回值给我一个包含课程节数和天数的对象数组,我把它转换成一个包含unit(5节课*7天的对应的数字来定位)的对象数组
单选框直接使用radio的插槽来贴图来适应样式需求
<van-radio-group :value="unit" @change="addClass"> <van-grid :border="false" :column-num="7" :clickable="true"> <van-grid-item v-for="value in 35" :key="value" use-slot custom-class="editCourse"> <van-button type="primary" color="#006600" v-show="map[value]!==-1?true:false" @click="editCourse(value)" custom-style="padding-left:5rpx;line-height:35rpx;padding-right:5rpx;padding-top:5rpx;height:203rpx;margin: 0 auto;width:90rpx;border-radius: 10rpx;font-size:25rpx!important;font-weight:bold"> <div>{{InfoMap[value].courseName}}</div> </van-button> <van-radio use-icon-slot :value="unit" :name="value" v-show="map[value]!==-1?false:true"> <image style="margin-top:10rpx;height:190rpx;width:90rpx;" slot="icon" :src="unit===value?icon.choosed:icon.unChoosed" /> </van-radio> </van-grid-item> </van-grid> </van-radio-group>
这样就看不出来是单选框了
其他主要是布局和样式,没啥好说的.吐槽一句,vant组件库的插槽不是真的放在组件里面,而是悬浮在它上面,有时候会出现错位的情况.
所以能用原生尽量用原生,组件样式带原生样式,样式穿透和!important都不起作用,不太好把握(主要是我太菜了,css好难)
Table.vue:
<template> <view> <bar :nav="setNav" /> <van-popup :show="chooseWeek" @close="onCloseChooseWeek" position="bottom" custom-class="height:50%"> <van-picker show-toolbar title="请选择现在的周数" :columns="weeks" @cancel="cancelChooseWeek" @confirm="confirmWeek" :loading="loadingTable" /> </van-popup> <van-row> <van-col span="22" offset="2"> <van-grid :border="false" :column-num="7" :clickable="true"> <van-grid-item use-slot custom-class="week"> <van-tag type="primary" color="#006600" custom-class="weekTag"> 周一 </van-tag> </van-grid-item> <van-grid-item use-slot custom-class="week"> <van-tag type="primary" color="#006600" custom-class="weekTag"> 周二 </van-tag> </van-grid-item> <van-grid-item use-slot custom-class="week"> <van-tag type="primary" color="#006600" custom-class="weekTag"> 周三 </van-tag> </van-grid-item> <van-grid-item use-slot custom-class="week"> <van-tag type="primary" color="#006600" custom-class="weekTag"> 周四 </van-tag> </van-grid-item> <van-grid-item use-slot custom-class="week"> <van-tag type="primary" color="#006600" custom-class="weekTag"> 周五 </van-tag> </van-grid-item> <van-grid-item use-slot custom-class="week"> <van-tag type="primary" color="#006600" custom-class="weekTag"> 周六 </van-tag> </van-grid-item> <van-grid-item use-slot custom-class="week"> <van-tag type="primary" color="#006600" custom-class="weekTag"> 周日 </van-tag> </van-grid-item> </van-grid> </van-col> </van-row> <van-row> <van-col span="2"> <van-grid :border="false" :column-num="1" :clickable="true"> <van-grid-item use-slot v-for="value in 5" :key="value" custom-class="courseNum"> <div class="course"> <van-button type="primary" color="#006600" block custom-class="courseNumBtn"> {{value+1}} </van-button> </div> </van-grid-item> </van-grid> </van-col> <van-radio-group :value="unit" @change="addClass"> <van-grid :border="false" :column-num="7" :clickable="true"> <van-grid-item v-for="value in 35" :key="value" use-slot custom-class="editCourse"> <van-button type="primary" color="#006600" v-show="map[value]!==-1?true:false" @click="editCourse(value)" custom-style="padding-left:5rpx;line-height:35rpx;padding-right:5rpx;padding-top:5rpx;height:203rpx;margin: 0 auto;width:90rpx;border-radius: 10rpx;font-size:25rpx!important;font-weight:bold"> <div>{{InfoMap[value].courseName}}</div> </van-button> <van-radio use-icon-slot :value="unit" :name="value" v-show="map[value]!==-1?false:true"> <image style="margin-top:10rpx;height:190rpx;width:90rpx;" slot="icon" :src="unit===value?icon.choosed:icon.unChoosed" /> </van-radio> </van-grid-item> </van-grid> </van-radio-group> <van-notify id="van-notify" /> </van-row> </view> </template> <script> import bar from '../../components/bar.vue'; import Notify from '../../wxcomponents/vant/dist/notify/notify'; export default { components: { bar }, data() { return { loadingTable: false, courseMap: [], map: [], InfoMap: [], weeks: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], unit: null, showBtn: false, chooseWeek: false, week: 1, icon: { unChoosed: "/static/Btn/addBtn.png", choosed: "/static/Btn/addBtn_HL.png" }, setNav: { 'bg': '#006600', 'color': "#fff", 'isdisPlayNavTitle': true, 'navTitle': '课表' }, windowHeight: null, weekHeight: null, courseHeight: null, btnHeight: null } }, mounted() { let token = "" token = wx.getStorageSync('token') if (token !== "") { this.loadDefaultData() } else { this.login() } }, onLoad() { uni.$on('choose', (chooseWeek) => { this.chooseWeek = chooseWeek }) }, onShow() { this.loadDefaultData() }, onUnload() { uni.$off('choose') }, methods: { login() { let self = this wx.login({ success(res) { wx.request({ url: getApp().globalData.baseURL + "/login", data: { "code": res.code }, success(res) { if (res.data.code === 1) { wx.setStorageSync('openid', res.data.data.openid) wx.setStorageSync('token', res.data.data.token) self.loadDefaultData() } else { Notify({ type: 'danger', message: '获取用户信息失败,请重试' }); } }, fail(err) { Notify({ type: 'danger', message: '连接服务器失败' }); } }) }, fail(err) { Notify({ type: 'danger', message: '获取用户登录态失败' }); } }) }, editCourse(value) { var Info = this.InfoMap[value] uni.$on('Send', () => { uni.$emit('courseInfo', Info) }) uni.navigateTo({ url: "../courseInfo/courseInfo" }) }, // 关闭选择周数弹出层 onCloseChooseWeek() { this.chooseWeek = false }, cancelChooseWeek(e) { this.chooseWeek = false }, // 计算并得到一个包含课程信息的数组 getMap(data) { var map = new Array() for (let i = 0; i < data.length; i++) { map[i] = { unit: (data[i].jieshu - 1) * 7 + data[i].day - 1, courseName: data[i].courseName, teacher: data[i].teacher, classroom: data[i].classroom, weeks: data[i].weeks } } this.courseMap = map }, resetMap(courseMap) { // 拿到一个排序的数组 var map = new Array() for (let i = 0; i < courseMap.length; i++) { map[i] = courseMap[i].unit } var compare = function(x, y) { if (x < y) { return -1; } else if (x > y) { return 1; } else { return 0; } } map.sort(compare) var Map = new Array(35).fill(-1) for (let i = 0; i < map.length; i++) { Map[map[i]] = map[i] } this.map = Map }, getInfoMap(courseMap) { var map = new Array() function compare(prop) { return function(x, y) { var v1 = x[prop]; var v2 = y[prop]; return v1 - v2 } } map = courseMap.sort(compare('unit')) // console.log(map) var Map = new Array(35).fill({}) for (let i = 0; i < map.length; i++) { Map[map[i].unit] = { unit: map[i].unit, teacher: map[i].teacher, classroom: map[i].classroom, courseName: map[i].courseName, weeks: map[i].weeks } } this.InfoMap = Map }, loadDefaultData() { let self = this uni.request({ url: getApp().globalData.baseURL + "/course/selectByOpenidAndWeeks", data: { "openid": wx.getStorageSync('openid'), "week": `${this.week}` }, header: { "token": wx.getStorageSync('token') }, success: (res) => { self.loadingTable = false if (res.data.code == 1) { self.getMap(res.data.data) self.resetMap(self.courseMap) self.getInfoMap(self.courseMap) } else if (res.data.code == 0) { Notify({ type: 'warning', message: '您尚未登录,无法获取课表哦', top: 64 }); } else { Notify({ type: 'danger', message: '获取课表失败', top: 64 }); } this.chooseWeek = false }, fail: (err) => { self.loadingTable = false Notify({ type: 'danger', message: '获取课表失败,请检查您的网络连接', top: 64 }); this.chooseWeek = false }, }) }, confirmWeek(e) { this.week = e.detail.value this.loadingTable = true let self = this uni.request({ url: getApp().globalData.baseURL + "/course/selectByOpenidAndWeeks", data: { "openid": wx.getStorageSync('openid'), "week": `${this.week}` }, header: { "token": wx.getStorageSync('token') }, success: (res) => { self.loadingTable = false if (res.data.code == 1) { self.getMap(res.data.data) self.resetMap(self.courseMap) self.getInfoMap(self.courseMap) Notify({ type: 'success', message: '获取课表成功!', top: 64 }); } else if (res.data.code == 0) { Notify({ type: 'warning', message: '您尚未登录,无法获取课表哦', top: 64 }); } else { Notify({ type: 'danger', message: '获取课表失败', top: 64 }); } this.chooseWeek = false console.log(res.data) }, fail: (err) => { self.loadingTable = false Notify({ type: 'danger', message: '获取课表失败,请检查您的网络连接', top: 64 }); this.chooseWeek = false }, }) }, // 添加课程 addClass(e) { this.unit = e.detail uni.navigateTo({ url: "../addCourse/addCourse" }) uni.$on('send', () => { uni.$emit('update', { msg: this.unit }) }) } } } </script> <style> .month { /* height: 60rpx; */ font-size: 32rpx; } .week { height: 60rpx; text-align: center; } .courseNum { height: 210rpx; text-align: center; } .courseNumBtn { height: 203rpx !important; width: 20rpx !important; border-radius: 10rpx !important; } .editCourse { height: 210rpx; } .weekTag { width: 60rpx; height: 50rpx; text-align: center; font-weight: bold; } .course { width: 100rpx; margin-right: 20rpx; } </style>
自定义顶部导航栏组件:
<template> <view> <view class="header" :style="{'height':titleBarHeight,'padding-top':statusBarHeight,'background-color': nav.bg}"> <text class="iconfont header-back " :style="{'border':nav.color}" v-if="nav.isdisPlayNavTitle" @click="popChooseWeek">  </text> <view class="header-title ">{{nav.navTitle}}</view> </view> <view :style="{'height':titleBarHeight,'padding-top':statusBarHeight}"></view> </view> </template> <script> export default { props: ["nav"], data() { return { chooseWeek: false, statusBarHeight: 0, titleBarHeight: 0, } }, created() { var that = this; uni.getSystemInfo({ success: function(res) { if (res.model.indexOf('iPhone') !== -1) { that.titleBarHeight = 44 + 'px'; } else { that.titleBarHeight = 48 + 'px'; } that.statusBarHeight = res.statusBarHeight + 'px' }, }) }, methods: { // 弹出选择周数框 popChooseWeek() { this.chooseWeek = true uni.$emit('choose', this.chooseWeek) } } } </script> <style> .header { display: flex; align-items: center; top: 0; position: fixed; width: 100%; z-index: 100; left: 0; } .header .header-title { position: absolute; left: 50%; font-size: 31rpx; transform: translateX(-50%); color: #fff } .header-back { position: absolute; left: 15upx; font-size: 30upx; padding: 10upx; border-radius: 50%; } @font-face { font-family: 'iconfont'; /* Project id 2568587 */ src: url('//at.alicdn.com/t/font_2568587_gslu7gcw01.woff2?t=1621863393001') format('woff2'), url('//at.alicdn.com/t/font_2568587_gslu7gcw01.woff?t=1621863393001') format('woff'), url('//at.alicdn.com/t/font_2568587_gslu7gcw01.ttf?t=1621863393001') format('truetype'); } .iconfont { font-family: "iconfont" !important; font-size: 25px !important; color: #fff !important } .weight { font-weight: bold; } </style>
效果: