From 0c40ce583bb380bbecf167e008e30ecdbff3f53d Mon Sep 17 00:00:00 2001 From: xiaochong0302 Date: Sun, 11 Jul 2021 15:15:27 +0800 Subject: [PATCH] =?UTF-8?q?1.=E6=9B=B4=E6=96=B0uview-ui=202.=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E8=AF=BE=E7=A8=8B=E5=88=97=E8=A1=A8=E4=B8=8D=E8=83=BD?= =?UTF-8?q?=E7=82=B9=E5=87=BB=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- pages/course/list.vue | 46 ++--- template.h5.html | 4 +- uview-ui/components/u-avatar/u-avatar.vue | 2 +- uview-ui/components/u-calendar/u-calendar.vue | 4 +- uview-ui/components/u-card/u-card.vue | 1 + .../components/u-cell-item/u-cell-item.vue | 6 +- .../u-line-progress/u-line-progress.vue | 147 +++++++++++++++ uview-ui/components/u-dropdown/u-dropdown.vue | 3 +- uview-ui/components/u-image/u-image.vue | 5 +- uview-ui/components/u-mask/u-mask.vue | 2 +- uview-ui/components/u-rate/u-rate.vue | 4 +- uview-ui/components/u-tabbar/u-tabbar.vue | 4 +- uview-ui/components/u-tabs/u-tabs.vue | 1 + uview-ui/components/u-upload/u-upload.vue | 4 +- uview-ui/index.js | 4 + uview-ui/libs/config/config.js | 4 +- uview-ui/libs/function/colorGradient.js | 36 +++- uview-ui/libs/function/route.js | 177 +++++++++++------- uview-ui/libs/function/test.js | 2 +- uview-ui/libs/function/timeFormat.js | 15 +- uview-ui/libs/function/timeFrom.js | 15 +- uview-ui/libs/mixin/mixin.js | 14 ++ uview-ui/libs/request/index.js | 2 +- uview-ui/package.json | 2 +- 25 files changed, 376 insertions(+), 131 deletions(-) create mode 100644 uview-ui/components/u-circle-progress/u-line-progress/u-line-progress.vue diff --git a/.gitignore b/.gitignore index 4cc1c23..2f9dfdd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +/.hbuilderx /unpackage -/common/config.js +/common/config.js \ No newline at end of file diff --git a/pages/course/list.vue b/pages/course/list.vue index a906807..a7e841a 100644 --- a/pages/course/list.vue +++ b/pages/course/list.vue @@ -1,22 +1,17 @@ @@ -33,8 +28,7 @@ hasMore: false, showEmpty: false, loadMore: 'loadmore', - enableSticky: true, - scrollTop: 0, + openFlag: false, sc: 0, level: 0, model: 0, @@ -97,16 +91,13 @@ this.loadCourses() } }, - onPageScroll(e) { - this.scrollTop = e.scrollTop - }, - onShow() { - this.enableSticky = true - }, - onHide() { - this.enableSticky = false - }, methods: { + openFilter(index) { + this.$refs.uDropdown.openFlag = true; + }, + closeFilter(index) { + this.$refs.uDropdown.openFlag = false; + }, switchLevel(level) { this.level = level this.doFilter() @@ -158,8 +149,17 @@ diff --git a/uview-ui/components/u-dropdown/u-dropdown.vue b/uview-ui/components/u-dropdown/u-dropdown.vue index a62e469..aff2b80 100644 --- a/uview-ui/components/u-dropdown/u-dropdown.vue +++ b/uview-ui/components/u-dropdown/u-dropdown.vue @@ -19,7 +19,7 @@ - diff --git a/uview-ui/components/u-rate/u-rate.vue b/uview-ui/components/u-rate/u-rate.vue index 1e44d56..17eb3a8 100644 --- a/uview-ui/components/u-rate/u-rate.vue +++ b/uview-ui/components/u-rate/u-rate.vue @@ -178,14 +178,14 @@ export default { // 获取评分组件盒子的布局信息 getElRectById() { // uView封装的获取节点的方法,详见文档 - this.$u.getRect('#' + this.elId).then(res => { + this.$uGetRect('#' + this.elId).then(res => { this.starBoxLeft = res.left }) }, // 获取单个星星的尺寸 getElRectByClass() { // uView封装的获取节点的方法,详见文档 - this.$u.getRect('.' + this.elClass).then(res => { + this.$uGetRect('.' + this.elClass).then(res => { this.starWidth = res.width // 把每个星星右边到组件盒子左边的距离放入数组中 for (let i = 0; i < this.count; i++) { diff --git a/uview-ui/components/u-tabbar/u-tabbar.vue b/uview-ui/components/u-tabbar/u-tabbar.vue index 448206c..2e1b6a2 100644 --- a/uview-ui/components/u-tabbar/u-tabbar.vue +++ b/uview-ui/components/u-tabbar/u-tabbar.vue @@ -22,7 +22,7 @@ :custom-prefix="item.customIcon ? 'custom-icon' : 'uicon'" > @@ -295,6 +295,8 @@ bottom: 14rpx; left: 50%; transform: translateX(-50%); + width: 100%; + text-align: center; } } diff --git a/uview-ui/components/u-tabs/u-tabs.vue b/uview-ui/components/u-tabs/u-tabs.vue index d25d616..0c59658 100644 --- a/uview-ui/components/u-tabs/u-tabs.vue +++ b/uview-ui/components/u-tabs/u-tabs.vue @@ -202,6 +202,7 @@ 'transition-duration': `${this.barFirstTimeMove ? 0 : this.duration }s`, 'background-color': this.activeColor, height: this.barHeight + 'rpx', + opacity: this.barFirstTimeMove ? 0 : 1, // 设置一个很大的值,它会自动取能用的最大值,不用高度的一半,是因为高度可能是单数,会有小数出现 'border-radius': `${this.barHeight / 2}px` }; diff --git a/uview-ui/components/u-upload/u-upload.vue b/uview-ui/components/u-upload/u-upload.vue index 2fec19d..f4d4b76 100644 --- a/uview-ui/components/u-upload/u-upload.vue +++ b/uview-ui/components/u-upload/u-upload.vue @@ -246,7 +246,9 @@ export default { limitType:{ type: Array, default() { - return ['png', 'jpg', 'jpeg', 'webp', 'gif']; + // 支付宝小程序真机选择图片的后缀为"image" + // https://opendocs.alipay.com/mini/api/media-image + return ['png', 'jpg', 'jpeg', 'webp', 'gif', 'image']; } }, // 在各个回调事件中的最后一个参数返回,用于区别是哪一个组件的事件 diff --git a/uview-ui/index.js b/uview-ui/index.js index ddda341..d38a3bf 100644 --- a/uview-ui/index.js +++ b/uview-ui/index.js @@ -82,6 +82,7 @@ const $u = { date: timeFormat, // 另名date timeFrom, colorGradient: colorGradient.colorGradient, + colorToRgba: colorGradient.colorToRgba, guid, color, sys, @@ -112,6 +113,9 @@ const $u = { throttle, } +// $u挂载到uni对象上 +uni.$u = $u + const install = Vue => { Vue.mixin(mixin) if (Vue.prototype.openShare) { diff --git a/uview-ui/libs/config/config.js b/uview-ui/libs/config/config.js index 22bb74e..44925a1 100644 --- a/uview-ui/libs/config/config.js +++ b/uview-ui/libs/config/config.js @@ -1,5 +1,5 @@ -// 此版本发布于2020-10-31 -let version = '1.7.8'; +// 此版本发布于2020-03-17 +let version = '1.8.4'; export default { v: version, diff --git a/uview-ui/libs/function/colorGradient.js b/uview-ui/libs/function/colorGradient.js index 7157513..eca30a2 100644 --- a/uview-ui/libs/function/colorGradient.js +++ b/uview-ui/libs/function/colorGradient.js @@ -93,8 +93,42 @@ function rgbToHex(rgb) { } } + +/** +* JS颜色十六进制转换为rgb或rgba,返回的格式为 rgba(255,255,255,0.5)字符串 +* sHex为传入的十六进制的色值 +* alpha为rgba的透明度 +*/ +function colorToRgba(color, alpha = 0.3) { + color = rgbToHex(color) + // 十六进制颜色值的正则表达式 + var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/ + /* 16进制颜色转为RGB格式 */ + let sColor = color.toLowerCase() + if (sColor && reg.test(sColor)) { + if (sColor.length === 4) { + var sColorNew = '#' + for (let i = 1; i < 4; i += 1) { + sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1)) + } + sColor = sColorNew + } + // 处理六位的颜色值 + var sColorChange = [] + for (let i = 1; i < 7; i += 2) { + sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2))) + } + // return sColorChange.join(',') + return 'rgba(' + sColorChange.join(',') + ',' + alpha + ')' + } + else { + return sColor + } +} + export default { colorGradient, hexToRgb, - rgbToHex + rgbToHex, + colorToRgba } \ No newline at end of file diff --git a/uview-ui/libs/function/route.js b/uview-ui/libs/function/route.js index 1e39057..28a81b7 100644 --- a/uview-ui/libs/function/route.js +++ b/uview-ui/libs/function/route.js @@ -1,85 +1,122 @@ -import queryParams from '../../libs/function/queryParams.js'; /** - * 路由跳转 - * 注意:本方法没有对跳转的回调函数进行封装 + * 路由跳转方法,该方法相对于直接使用uni.xxx的好处是使用更加简单快捷 + * 并且带有路由拦截功能 */ -function route(options = {}, params = false) { - let config = { - type: 'navigateTo', - url: '', - delta: 1, // navigateBack页面后退时,回退的层数 - params: {}, // 传递的参数 - animationType: 'pop-in', // 窗口动画,只在APP有效 - animationDuration: 300, // 窗口动画持续时间,单位毫秒,只在APP有效 - }; - config = Object.assign(config, options); - // 如果url没有"/"开头,添加上,因为uni的路由跳转需要"/"开头 - if (config.url[0] != '/') config.url = '/' + config.url; - // 判断是否有传递显式的参数,Object.keys转为数组并判断长度,switchTab类型时不能携带参数 - if (Object.keys(config.params).length && config.type != 'switchTab') { - // 判断用户传递的url中,是否带有参数 + +class Router { + constructor() { + // 原始属性定义 + this.config = { + type: 'navigateTo', + url: '', + delta: 1, // navigateBack页面后退时,回退的层数 + params: {}, // 传递的参数 + animationType: 'pop-in', // 窗口动画,只在APP有效 + animationDuration: 300, // 窗口动画持续时间,单位毫秒,只在APP有效 + intercept: false, // 是否需要拦截 + } + // 因为route方法是需要对外赋值给另外的对象使用,同时route内部有使用this,会导致route失去上下文 + // 这里在构造函数中进行this绑定 + this.route = this.route.bind(this) + } + + // 判断url前面是否有"/",如果没有则加上,否则无法跳转 + addRootPath(url) { + return url[0] === '/' ? url : `/${url}` + } + + // 整合路由参数 + mixinParam(url, params) { + url = url && this.addRootPath(url) + // 使用正则匹配,主要依据是判断是否有"/","?","="等,如“/page/index/index?name=mary" // 如果有url中有get参数,转换后无需带上"?" - let query = ''; - if (/.*\/.*\?.*=.*/.test(config.url)) { + let query = '' + if (/.*\/.*\?.*=.*/.test(url)) { // object对象转为get类型的参数 - query = queryParams(config.params, false); + query = uni.$u.queryParams(params, false); // 因为已有get参数,所以后面拼接的参数需要带上"&"隔开 - config.url += "&" + query; + return url += "&" + query } else { - query = queryParams(config.params); - config.url += query; + // 直接拼接参数,因为此处url中没有后面的query参数,也就没有"?/&"之类的符号 + query = uni.$u.queryParams(params); + return url += query } } - // 简写形式,把url和参数拼接起来 - if (typeof options === 'string' && typeof params == 'object') { - let query = ''; - if (/.*\/.*\?.*=.*/.test(options)) { - // object对象转为get类型的参数 - query = queryParams(params, false); - // 因为已有get参数,所以后面拼接的参数需要带上"&"隔开 - options += "&" + query; + + // 对外的方法名称 + async route(options = {}, params = {}) { + // 合并用户的配置和内部的默认配置 + let mergeConfig = {} + + if (typeof options === 'string') { + // 如果options为字符串,则为route(url, params)的形式 + mergeConfig.url = this.mixinParam(options, params) + mergeConfig.type = 'navigateTo' } else { - query = queryParams(params); - options += query; + mergeConfig = uni.$u.deepClone(options, this.config) + // 否则正常使用mergeConfig中的url和params进行拼接 + mergeConfig.url = this.mixinParam(options.url, options.params) + } + + if(params.intercept) { + this.config.intercept = params.intercept + } + // params参数也带给拦截器 + mergeConfig.params = params + // 合并内外部参数 + mergeConfig = uni.$u.deepMerge(this.config, mergeConfig) + // 判断用户是否定义了拦截器 + if (typeof uni.$u.routeIntercept === 'function') { + // 定一个promise,根据用户执行resolve(true)或者resolve(false)来决定是否进行路由跳转 + const isNext = await new Promise((resolve, reject) => { + uni.$u.routeIntercept(mergeConfig, resolve) + }) + // 如果isNext为true,则执行路由跳转 + isNext && this.openPage(mergeConfig) + } else { + this.openPage(mergeConfig) } } - // 判断是否一个字符串,如果是,直接跳转(简写法) - // 如果是中情形,默认第二个参数为对象形式的参数 - if (typeof options === 'string') { - if (options[0] != '/') options = '/' + options; - return uni.navigateTo({ - url: options - }); - } - // navigateTo类型的跳转 - if (config.type == 'navigateTo' || config.type == 'to') { - return uni.navigateTo({ - url: config.url, - animationType: config.animationType, - animationDuration: config.animationDuration, - }); - } - if (config.type == 'redirectTo' || config.type == 'redirect') { - return uni.redirectTo({ - url: config.url, - }); - } - if (config.type == 'switchTab' || config.type == 'tab') { - return uni.switchTab({ - url: config.url, - }); - } - if (config.type == 'reLaunch') { - return uni.reLaunch({ - url: config.url - }); - } - if (config.type == 'navigateBack' || config.type == 'back') { - return uni.navigateBack({ - delta: parseInt(config.delta ? config.delta : this.delta) - }); + + // 执行路由跳转 + openPage(config) { + // 解构参数 + const { + url, + type, + delta, + animationType, + animationDuration + } = config + if (config.type == 'navigateTo' || config.type == 'to') { + uni.navigateTo({ + url, + animationType, + animationDuration + }); + } + if (config.type == 'redirectTo' || config.type == 'redirect') { + uni.redirectTo({ + url + }); + } + if (config.type == 'switchTab' || config.type == 'tab') { + uni.switchTab({ + url + }); + } + if (config.type == 'reLaunch' || config.type == 'launch') { + uni.reLaunch({ + url + }); + } + if (config.type == 'navigateBack' || config.type == 'back') { + uni.navigateBack({ + delta + }); + } } } -export default route; +export default (new Router()).route \ No newline at end of file diff --git a/uview-ui/libs/function/test.js b/uview-ui/libs/function/test.js index b8418a6..fd25e18 100644 --- a/uview-ui/libs/function/test.js +++ b/uview-ui/libs/function/test.js @@ -9,7 +9,7 @@ function email(value) { * 验证手机格式 */ function mobile(value) { - return /^1[23456789]\d{9}$/.test(value) + return /^1[3-9]\d{9}$/.test(value) } /** diff --git a/uview-ui/libs/function/timeFormat.js b/uview-ui/libs/function/timeFormat.js index 1238010..0372f2f 100644 --- a/uview-ui/libs/function/timeFormat.js +++ b/uview-ui/libs/function/timeFormat.js @@ -21,15 +21,14 @@ if (!String.prototype.padStart) { } } -function timeFormat(timestamp = null, fmt = 'yyyy-mm-dd') { - // 其他更多是格式化有如下: - // yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 - timestamp = parseInt(timestamp); +// 其他更多是格式化有如下: +// yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 +function timeFormat(dateTime = null, fmt = 'yyyy-mm-dd') { // 如果为null,则格式化当前时间 - if (!timestamp) timestamp = Number(new Date()); - // 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位) - if (timestamp.toString().length == 10) timestamp *= 1000; - let date = new Date(timestamp); + if (!dateTime) dateTime = Number(new Date()); + // 如果dateTime长度为10或者13,则为秒和毫秒的时间戳,如果超过13位,则为其他的时间格式 + if (dateTime.toString().length == 10) dateTime *= 1000; + let date = new Date(dateTime); let ret; let opt = { "y+": date.getFullYear().toString(), // 年 diff --git a/uview-ui/libs/function/timeFrom.js b/uview-ui/libs/function/timeFrom.js index 52d858e..68cd990 100644 --- a/uview-ui/libs/function/timeFrom.js +++ b/uview-ui/libs/function/timeFrom.js @@ -6,13 +6,14 @@ import timeFormat from '../../libs/function/timeFormat.js'; * @param String | Boolean format 如果为时间格式字符串,超出一定时间范围,返回固定的时间格式; * 如果为布尔值false,无论什么时间,都返回多久以前的格式 */ -function timeFrom(timestamp = null, format = 'yyyy-mm-dd') { - if (timestamp == null) timestamp = Number(new Date()); - timestamp = parseInt(timestamp); - // 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位) - if (timestamp.toString().length == 10) timestamp *= 1000; - var timer = (new Date()).getTime() - timestamp; - timer = parseInt(timer / 1000); +function timeFrom(dateTime = null, format = 'yyyy-mm-dd') { + // 如果为null,则格式化当前时间 + if (!dateTime) dateTime = Number(new Date()); + // 如果dateTime长度为10或者13,则为秒和毫秒的时间戳,如果超过13位,则为其他的时间格式 + if (dateTime.toString().length == 10) dateTime *= 1000; + let timestamp = + new Date(Number(dateTime)); + + let timer = (Number(new Date()) - timestamp) / 1000; // 如果小于5分钟,则返回"刚刚",其他以此类推 let tips = ''; switch (true) { diff --git a/uview-ui/libs/mixin/mixin.js b/uview-ui/libs/mixin/mixin.js index 43742f4..e388986 100644 --- a/uview-ui/libs/mixin/mixin.js +++ b/uview-ui/libs/mixin/mixin.js @@ -46,5 +46,19 @@ module.exports = { }, onReachBottom() { uni.$emit('uOnReachBottom') + }, + beforeDestroy() { + // 判断当前页面是否存在parent和chldren,一般在checkbox和checkbox-group父子联动的场景会有此情况 + // 组件销毁时,移除子组件在父组件children数组中的实例,释放资源,避免数据混乱 + if(this.parent && uni.$u.test.array(this.parent.children)) { + // 组件销毁时,移除父组件中的children数组中对应的实例 + const childrenList = this.parent.children + childrenList.map((child, index) => { + // 如果相等,则移除 + if(child === this) { + childrenList.splice(index, 1) + } + }) + } } } diff --git a/uview-ui/libs/request/index.js b/uview-ui/libs/request/index.js index ced1744..1f5f471 100644 --- a/uview-ui/libs/request/index.js +++ b/uview-ui/libs/request/index.js @@ -23,7 +23,7 @@ class Request { options.responseType = options.responseType || this.config.responseType; options.url = options.url || ''; options.params = options.params || {}; - options.header = Object.assign(this.config.header, options.header); + options.header = Object.assign({}, this.config.header, options.header); options.method = options.method || this.config.method; return new Promise((resolve, reject) => { diff --git a/uview-ui/package.json b/uview-ui/package.json index b0e2476..431d585 100644 --- a/uview-ui/package.json +++ b/uview-ui/package.json @@ -1,6 +1,6 @@ { "name": "uview-ui", - "version": "1.7.8", + "version": "1.8.4", "description": "uView UI,是uni-app生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水", "main": "index.js", "keywords": [ -- Gitee