diff --git a/.gitignore b/.gitignore
index 4cc1c234fcc611bb32278f77f3c8adcaf43da2a7..2f9dfddf4024e5b7572a11c5dfa25009f120f769 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 a906807b74765ea034ed9369e3f255ef69d3ca3c..a7e841a48b2572b03a4258e76063c181b5d9cedd 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 a62e469aee7574d8b9666b37b869a0acdd8bedd7..aff2b804619badeceec2adce784b8c132f6dab3c 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 1e44d56f6d354580fa4b6b7cad2b7e5498729de8..17eb3a87a678dcd6ccd0c859a6dc2543634c23dc 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 448206c043f9daa7541af7995fedfda3f66e181c..2e1b6a2fa8a065c4eb48e43c803a62aa34590418 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 d25d6167daa16b4f152ff884d805b04dde1fdd27..0c596585386183522883c11a24d81cc198de24b3 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 2fec19d5bfc3fcfb152825018d5bded526b96ad2..f4d4b763efc45cbd38cfd751a243799b491eadbd 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 ddda3415f84a0ec34f7ca7276395c25913a08110..d38a3bf5cbd9e381362353958bb525a22e507cb1 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 22bb74ebd08f9c9e5b6f4b701e72074bce6366f6..44925a1d3d5ef603fd5b63287ee6736ff79c6372 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 7157513b06559bf4bfc1d0019296ddeeab417169..eca30a27afb6f61178a65715475f5f84eff49afd 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 1e39057b5358a60fc4cf6b2484614d13f83dc645..28a81b729d1f22663b0161cf6102cdbf5b87a2e6 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 b8418a6c2d372414abcf041e517afd1c24d1f98b..fd25e180ffcdd65981248e903ef286040c0a4937 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 123801054cd14b55afeea3cfc8f6ea4b5c0377f2..0372f2f10fa082ce426ea6ee8af5f74a85fed6fb 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 52d858e17d39c2503c365264eb630688e1b95c2e..68cd9901bc3db41c1dff5be7f46dafcadddcef15 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 43742f45c07cdfc060b3b5dca380e49e23720e19..e388986796ed8b8c0644cac805b5569c7ac0394f 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 ced1744780138553dd8896ac154465477a0b4662..1f5f471654fce08fdbb25d16308e971ea8fdda50 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 b0e2476964fec016610b1a14e5ac39584dca25bd..431d58596364bb6774068c60a57adaa39136a5f8 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": [