Commit c1c3e009 authored by wlxuqu's avatar wlxuqu

1.【新增】readMore组件新增index参数和close,open事件

2.【新增】新增man,woman,level三个图标
3.【新增】新增"注意事项"专题,记录一些踩坑知识点,让同学们少走弯路,详见[注意事项](https://uviewui.com/components/feature.html)
4.【新增】alertTips组件新增icon、title-style、desc-style、icon-style参数
5.【新增】新增节流和防抖方法,通过this.$u.debounce()和this.$u.throttle()调用,详见[节流防抖](https://uviewui.com/js/debounce.html)
6.【新增】button组件新增节流功能,以及配置间隔时间的throttle-time参数
7.【新增】field和input组件新增trim参数,默认为true,可以去除输入内容两端的空格
8.【优化】优化form-item组件的label设置为空内容时,依然显示左边的占位的问题
9.【优化】优化lazy-load组件修改图片路径后,无法再次加载的问题
10.【优化】优化navbar,upload,tabbar等组件由于各小程序props参数类型为Function,组件内执行父组件方法时this上下文丢失的问题
11.【优化】优化numberbox组件无法阻止事件冒泡的问题
12.【优化】优化timeFormat组件由于使用es7的padStart方法,导致在电脑版微信小程序无法识别的问题
13.【调整】调整this.$u.sys和this.$u.os,通过this.$u.sys()和this.$u.os()调用,详见[升级指南](https://uviewui.com/components/changeGuide.html)
14.【修复】修复无法通过手动设置popup的v-model为false来关闭popup的问题
15.【修复】修复骨架屏组件在微信小程序平台的组件中使用无效的问题。
parent 582557e5
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
uView UI,是[uni-app](https://uniapp.dcloud.io/)生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水 uView UI,是[uni-app](https://uniapp.dcloud.io/)生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水
### **欢迎加群交流反馈:249718512** ### **欢迎加群交流反馈:1129077272**
## 特性 ## 特性
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"name" : "uView", "name" : "uView",
"appid" : "__UNI__60F4B81", "appid" : "__UNI__60F4B81",
"description" : "多平台快速开发的UI框架", "description" : "多平台快速开发的UI框架",
"versionName" : "1.5.7", "versionName" : "1.5.8",
"versionCode" : "100", "versionCode" : "100",
"transformPx" : false, "transformPx" : false,
"app-plus" : { "app-plus" : {
...@@ -126,6 +126,7 @@ ...@@ -126,6 +126,7 @@
"treeShaking" : { "treeShaking" : {
"enable" : true "enable" : true
} }
} },
"title" : "uView UI"
} }
} }
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
"easycom": { "easycom": {
"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue" "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
}, },
"condition": { //模式配置,仅开发期间生效 // "condition": { //模式配置,仅开发期间生效
"current": 0, //当前激活的模式(list 的索引项) // "current": 0, //当前激活的模式(list 的索引项)
"list": [{ // "list": [{
"name": "test", //模式名称 // "name": "test", //模式名称
"path": "pages/componentsA/avatar/index", //启动页面,必选 // "path": "pages/componentsC/test/index", //启动页面,必选
"query": "id=1&name=2" //启动参数,在页面的onLoad函数里面得到 // "query": "id=1&name=2" //启动参数,在页面的onLoad函数里面得到
}] // }]
}, // },
"pages": [ "pages": [
// 演示-组件 // 演示-组件
{ {
...@@ -328,6 +328,13 @@ ...@@ -328,6 +328,13 @@
{ {
"root": "pages/library", "root": "pages/library",
"pages": [ "pages": [
// debounce-节流防抖
{
"path": "debounce/index",
"style": {
"navigationBarTitleText": "throttle | debounce-节流防抖"
}
},
// deepClone-对象深度克隆 // deepClone-对象深度克隆
{ {
"path": "deepClone/index", "path": "deepClone/index",
......
<template> <template>
<view class=""> <view class="">
<u-navbar title-color="#fff" back-icon-color="#ffffff" :is-fixed="isFixed" :is-back="isBack" :background="background" :back-text-style="{color: '#fff'}" :title="title" :back-icon-name="backIconName" :back-text="backText"> <u-navbar title-color="#fff" back-icon-color="#ffffff"
:is-fixed="isFixed" :is-back="isBack"
:background="background"
:back-text-style="{color: '#fff'}" :title="title"
:back-icon-name="backIconName" :back-text="backText"
>
<view class="slot-wrap" v-if="useSlot"> <view class="slot-wrap" v-if="useSlot">
<view class="search-wrap" v-if="search"> <view class="search-wrap" v-if="search">
<!-- 如果使用u-search组件,必须要给v-model绑定一个变量 --> <!-- 如果使用u-search组件,必须要给v-model绑定一个变量 -->
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<view class="u-demo-wrap"> <view class="u-demo-wrap">
<view class="u-demo-title">演示效果</view> <view class="u-demo-title">演示效果</view>
<view class="u-demo-area"> <view class="u-demo-area">
<u-read-more :toggle="toggle" :show-height="showHeight" ref="uReadMore"> <u-read-more @open="open" @close="close" :toggle="toggle" :show-height="showHeight" ref="uReadMore">
<!-- u-parse组件在微信小程序渲染慢,支付宝小程序rich-text不支持nodes属性 --> <!-- u-parse组件在微信小程序渲染慢,支付宝小程序rich-text不支持nodes属性 -->
<!-- #ifdef MP-ALIPAY --> <!-- #ifdef MP-ALIPAY -->
<u-parse :html="content"></u-parse> <u-parse :html="content"></u-parse>
...@@ -48,6 +48,12 @@ ...@@ -48,6 +48,12 @@
}, },
toggleChange(index) { toggleChange(index) {
this.toggle = index == 0 ? true : false; this.toggle = index == 0 ? true : false;
},
open() {
// console.log('open');
},
close() {
// console.log('close');
} }
} }
} }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<view class="u-demo-wrap"> <view class="u-demo-wrap">
<view class="u-demo-title">演示效果</view> <view class="u-demo-title">演示效果</view>
<view class="u-demo-area"> <view class="u-demo-area">
<u-section :title="title" :right="right" :bold="bold" :color="color" :show-line="false"></u-section> <u-section :title="title" :right="right" :bold="bold" :color="color" :show-line="showLine"></u-section>
</view> </view>
</view> </view>
<view class="u-config-wrap"> <view class="u-config-wrap">
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
<view class="u-item-title">更换主标题</view> <view class="u-item-title">更换主标题</view>
<u-subsection vibrateShort :current="1" :list="['是', '否']" @change="titleChange"></u-subsection> <u-subsection vibrateShort :current="1" :list="['是', '否']" @change="titleChange"></u-subsection>
</view> </view>
<view class="u-config-item">
<view class="u-item-title">竖条状态</view>
<u-subsection vibrateShort :list="['显示', '隐藏']" @change="showLineChange"></u-subsection>
</view>
<view class="u-config-item"> <view class="u-config-item">
<view class="u-item-title">是否显示右边部分</view> <view class="u-item-title">是否显示右边部分</view>
<u-subsection vibrateShort :list="['是', '否']" @change="rightChange"></u-subsection> <u-subsection vibrateShort :list="['是', '否']" @change="rightChange"></u-subsection>
...@@ -37,7 +41,8 @@ ...@@ -37,7 +41,8 @@
title: '红豆生南国', title: '红豆生南国',
bold: true, bold: true,
right: true, right: true,
color: this.$u.color['mainColor'] color: this.$u.color['mainColor'],
showLine: true
} }
}, },
methods: { methods: {
...@@ -53,6 +58,9 @@ ...@@ -53,6 +58,9 @@
}, },
colorChange(index) { colorChange(index) {
this.color = index == 0 ? this.$u.color['mainColor'] : this.$u.color['primary']; this.color = index == 0 ? this.$u.color['mainColor'] : this.$u.color['primary'];
},
showLineChange(index) {
this.showLine = !index;
} }
} }
} }
......
<template> <template>
<view> <view style="padding-top: 200px;">
<u-popup v-model="show" @close="close"> <u-button @click="show = true" :custom-style="{
<view>出淤泥而不染,濯清涟而不妖</view> color: 'red',
</u-popup> borderColor: 'blue'
<u-button @click="show = true">打开</u-button> }">打开</u-button>
</view> </view>
</template> </template>
...@@ -11,13 +11,29 @@ ...@@ -11,13 +11,29 @@
export default { export default {
data() { data() {
return { return {
show: false show: true,
list: [{
name: '待收货'
}, {
name: '待付款'
}, {
name: '待评价'
}],
current: 0
} }
}, },
onLoad() {
// setTimeout(() => {
// this.show = false;
// }, 2000)
},
methods: { methods: {
close() { close() {
console.log('close'); //console.log('close');
},
change(index) {
this.current = index;
} }
} }
} }
</script> </script>
\ No newline at end of file
...@@ -22,6 +22,11 @@ export default [ ...@@ -22,6 +22,11 @@ export default [
{ {
groupName: '工具库', groupName: '工具库',
list: [ list: [
{
path: 'debounce',
icon: 'debounce',
title: 'throttle | debounce 节流防抖',
},
{ {
path: 'deepMerge', path: 'deepMerge',
icon: 'deepMerge', icon: 'deepMerge',
......
<template>
<view class="u-demo">
<view class="u-demo-wrap">
<view class="u-demo-title">演示效果</view>
<view class="u-demo-area">
<view class="no-mode-here">
选择节流或者防抖模式,点击按钮,将会执行回调并显示在下方:
</view>
<view class="u-demo-result-line" v-if="result.length">
<view v-for="(item, index) in result" :key="index">{{(index >= 1) ? '-' : ''}}回调</view>
</view>
</view>
</view>
<view class="u-config-wrap">
<view class="u-button" hover-class="u-button--hover" hover-stay-time="150" @tap="btnClick">
点击触发
</view>
<view class="u-config-title u-border-bottom">
参数配置
</view>
<view class="u-config-item">
<view class="u-item-title">模式</view>
<u-subsection vibrateShort :list="['节流', '防抖']" @change="modeChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">时间间隔</view>
<u-subsection vibrateShort current="1" :list="['500ms', '1000ms', '2000ms']" @change="timeoutChange"></u-subsection>
</view>
<view class="u-config-item">
<view class="u-item-title">执行时机</view>
<u-subsection vibrateShort :list="['开始处', '结束处']" @change="immediateChange"></u-subsection>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
result: [],
timeout: 1000,
immediate: true,
mode: 'throttle'
}
},
methods: {
modeChange(index) {
this.mode = index ? 'debouncd' : 'throttle';
},
timeoutChange(index) {
this.timeout = [500, 1000, 2000][index];
},
immediateChange(index) {
this.immediate = !index;
},
getResult() {
if(this.result.length >= 6) this.result = [];
this.result.push(0);
},
btnClick() {
if(this.mode == 'throttle') {
this.$u.throttle(this.getResult, this.timeout, this.immediate);
} else {
this.$u.debounce(this.getResult, this.timeout, this.immediate);
}
}
}
}
</script>
<style lang="scss" scoped>
.u-button {
margin-top: 50rpx;
margin-bottom: 50rpx;
display: flex;
justify-content: center;
align-items: center;
height: 80rpx;
border-radius: 6rpx;
border: 1px solid $u-type-primary;
color: $u-type-primary;
}
.u-button--hover {
color: #fff;
background-color: $u-type-primary;
}
.u-demo-result-line {
display: flex;
justify-content: center;
}
</style>
...@@ -8,13 +8,13 @@ ...@@ -8,13 +8,13 @@
borderColor: borderColor borderColor: borderColor
}"> }">
<view class="u-icon-wrap"> <view class="u-icon-wrap">
<u-icon v-if="showIcon" :name="$u.type2icon(type)" :size="description ? 40 : 32" class="u-icon" :color="type"></u-icon> <u-icon v-if="showIcon" :name="uIcon" :size="description ? 40 : 32" class="u-icon" :color="uIconType" :custom-style="iconStyle"></u-icon>
</view> </view>
<view class="u-alert-content" @tap.stop="click"> <view class="u-alert-content" @tap.stop="click">
<view class="u-alert-title" :style="{fontWeight: description ? 500 : 'normal'}"> <view class="u-alert-title" :style="[uTitleStyle]">
{{title}} {{title}}
</view> </view>
<view v-if="description" class="u-alert-desc"> <view v-if="description" class="u-alert-desc" :style="[descStyle]">
{{description}} {{description}}
</view> </view>
</view> </view>
...@@ -38,6 +38,10 @@ ...@@ -38,6 +38,10 @@
* @property {String} title 显示的标题文字 * @property {String} title 显示的标题文字
* @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选 * @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选
* @property {String} type 关闭按钮(默认为叉号icon图标) * @property {String} type 关闭按钮(默认为叉号icon图标)
* @property {String} icon 图标名称
* @property {Object} icon-style 图标的样式,对象形式
* @property {Object} title-style 标题的样式,对象形式
* @property {Object} desc-style 描述的样式,对象形式
* @property {String} close-able 用文字替代关闭图标,close-able为true时有效 * @property {String} close-able 用文字替代关闭图标,close-able为true时有效
* @property {Boolean} show-icon 是否显示左边的辅助图标 * @property {Boolean} show-icon 是否显示左边的辅助图标
* @property {Boolean} show 显示或隐藏组件 * @property {Boolean} show 显示或隐藏组件
...@@ -96,12 +100,55 @@ ...@@ -96,12 +100,55 @@
show: { show: {
type: Boolean, type: Boolean,
default: true default: true
} },
// 左边显示的icon
icon: {
type: String,
default: ''
},
// icon的样式
iconStyle: {
type: Object,
default() {
return {}
}
},
// 标题的样式
titleStyle: {
type: Object,
default() {
return {}
}
},
// 描述文字的样式
descStyle: {
type: Object,
default() {
return {}
}
},
}, },
data() { data() {
return { return {
} }
}, },
computed: {
uTitleStyle() {
let style = {};
// 如果有描述文字的话,标题进行加粗
style.fontWeight = this.description ? 500 : 'normal';
// 将用户传入样式对象和style合并,传入的优先级比style高,同属性会被覆盖
return this.$u.deepMerge(style, this.titleStyle);
},
uIcon() {
// 如果有设置icon名称就使用,否则根据type主题,推定一个默认的图标
return this.icon ? this.icon : this.$u.type2icon(type);
},
uIconType() {
// 如果有设置图标的样式,优先使用,没有的话,则用type的样式
return Object.keys(this.iconStyle).length ? '' : this.type;
}
},
methods: { methods: {
// 点击内容 // 点击内容
click() { click() {
...@@ -173,16 +220,6 @@ ...@@ -173,16 +220,6 @@
visibility: hidden; visibility: hidden;
} }
@keyframes myfirst {
from {
height: 100%;
}
to {
height: 0
}
}
.u-icon { .u-icon {
margin-right: 16rpx; margin-right: 16rpx;
} }
......
...@@ -205,6 +205,11 @@ export default { ...@@ -205,6 +205,11 @@ export default {
dataName: { dataName: {
type: String, type: String,
default: '' default: ''
},
// 节流,一定时间内只能触发一次
throttleTime: {
type: [String, Number],
default: 1000
} }
}, },
computed: { computed: {
...@@ -236,17 +241,20 @@ export default { ...@@ -236,17 +241,20 @@ export default {
methods: { methods: {
// 按钮点击 // 按钮点击
click(e) { click(e) {
// 如果按钮时disabled和loading状态,不触发水波纹效果 // 进行节流控制,每this.throttle毫秒内,只在开始处执行
if (this.loading === true || this.disabled === true) return; this.$u.throttle(() => {
// 是否开启水波纹效果 // 如果按钮时disabled和loading状态,不触发水波纹效果
if (this.ripple) { if (this.loading === true || this.disabled === true) return;
// 每次点击时,移除上一次的类,再次添加,才能触发动画效果 // 是否开启水波纹效果
this.waveActive = false; if (this.ripple) {
this.$nextTick(function() { // 每次点击时,移除上一次的类,再次添加,才能触发动画效果
this.getWaveQuery(e); this.waveActive = false;
}); this.$nextTick(function() {
} this.getWaveQuery(e);
this.$emit('click', e); });
}
this.$emit('click', e);
}, this.throttleTime);
}, },
// 查询按钮的节点信息 // 查询按钮的节点信息
getWaveQuery(e) { getWaveQuery(e) {
......
...@@ -183,6 +183,11 @@ export default { ...@@ -183,6 +183,11 @@ export default {
type: Boolean, type: Boolean,
default: true default: true
}, },
// 是否自动去除两端的空格
trim: {
type: Boolean,
default: true
}
}, },
data() { data() {
return { return {
...@@ -241,7 +246,10 @@ export default { ...@@ -241,7 +246,10 @@ export default {
}, },
methods: { methods: {
onInput(event) { onInput(event) {
this.$emit('input', event.target.value); let value = event.detail.value;
// 判断是否去除空格
if(this.trim) value = this.$u.trim(value);
this.$emit('input', value);
}, },
onFocus(event) { onFocus(event) {
this.focused = true; this.focused = true;
......
...@@ -3,11 +3,11 @@ ...@@ -3,11 +3,11 @@
<view class="u-form-item__body" :style="{ <view class="u-form-item__body" :style="{
flexDirection: elLabelPosition == 'left' ? 'row' : 'column' flexDirection: elLabelPosition == 'left' ? 'row' : 'column'
}"> }">
<view class="u-form-item--left" :style="{ <!-- 微信小程序中,将一个参数设置空字符串,结果会变成字符串"true" -->
<view class="u-form-item--left" v-if="label !== '' && label !== 'true'" :style="{
width: elLabelPosition == 'left' ? $u.addUnit(elLabelWidth) : '100%', width: elLabelPosition == 'left' ? $u.addUnit(elLabelWidth) : '100%',
flex: `0 0 ${elLabelPosition == 'left' ? $u.addUnit(elLabelWidth) : '100%'}`, flex: `0 0 ${elLabelPosition == 'left' ? $u.addUnit(elLabelWidth) : '100%'}`,
marginBottom: elLabelPosition == 'left' ? 0 : '10rpx', marginBottom: elLabelPosition == 'left' ? 0 : '10rpx',
}"> }">
<!-- 为了块对齐 --> <!-- 为了块对齐 -->
<view class="u-form-item--left__content"> <view class="u-form-item--left__content">
...@@ -182,8 +182,8 @@ export default { ...@@ -182,8 +182,8 @@ export default {
}, },
// label的宽度 // label的宽度
elLabelWidth() { elLabelWidth() {
// label默认宽度为90,优先使用本组件的值,如果没有,则用u-form的值 // label默认宽度为90,优先使用本组件的值,如果没有(如果设置为0,也算是配置了值,依然起效),则用u-form的值
return this.labelWidth ? this.labelWidth : (this.parent ? this.parent.labelWidth : 90); return (this.labelWidth != 0 || this.labelWidth != '') ? this.labelWidth : (this.parent ? this.parent.labelWidth : 90);
}, },
// label的样式 // label的样式
elLabelStyle() { elLabelStyle() {
......
...@@ -143,7 +143,7 @@ export default { ...@@ -143,7 +143,7 @@ export default {
// 用于解决某些情况下,让图标垂直居中的用途 // 用于解决某些情况下,让图标垂直居中的用途
top: { top: {
type: [String, Number], type: [String, Number],
default: '' default: 0
} }
}, },
computed: { computed: {
...@@ -167,8 +167,8 @@ export default { ...@@ -167,8 +167,8 @@ export default {
style = { style = {
fontSize: this.size == 'inherit' ? 'inherit' : this.$u.addUnit(this.size), fontSize: this.size == 'inherit' ? 'inherit' : this.$u.addUnit(this.size),
fontWeight: this.bold ? 'bold' : 'normal', fontWeight: this.bold ? 'bold' : 'normal',
// 安卓和iOS各需要设置一个到顶部的距离,才能更好的垂直居中 // 某些特殊情况需要设置一个到顶部的距离,才能更好的垂直居中
top: this.top === '' ? (this.$u.os == 'ios' ? '2rpx' : '4rpx') : this.$u.addUnit(this.top) top: this.$u.addUnit(this.top)
}; };
// 非主题色值时,才当作颜色值 // 非主题色值时,才当作颜色值
if (this.color && !this.$u.config.type.includes(this.color)) style.color = this.color; if (this.color && !this.$u.config.type.includes(this.color)) style.color = this.color;
......
...@@ -200,6 +200,11 @@ export default { ...@@ -200,6 +200,11 @@ export default {
selectionEnd: { selectionEnd: {
type: [Number, String], type: [Number, String],
default: -1 default: -1
},
// 是否自动去除两端的空格
trim: {
type: Boolean,
default: true
} }
}, },
data() { data() {
...@@ -259,15 +264,18 @@ export default { ...@@ -259,15 +264,18 @@ export default {
* @param event * @param event
*/ */
handleInput(event) { handleInput(event) {
let value = event.detail.value;
// 判断是否去除空格
if(this.trim) value = this.$u.trim(value);
// 当前model 赋值 // 当前model 赋值
this.defaultValue = event.detail.value; this.defaultValue = value;
// vue 原生的方法 return 出去 // vue 原生的方法 return 出去
this.$emit('input', event.detail.value); this.$emit('input', value);
// 过一个生命周期再发送事件给u-form-item,否则this.$emit('input')更新了父组件的值,但是微信小程序上 // 过一个生命周期再发送事件给u-form-item,否则this.$emit('input')更新了父组件的值,但是微信小程序上
// 尚未更新到u-form-item,导致获取的值为空,从而校验混论 // 尚未更新到u-form-item,导致获取的值为空,从而校验混论
this.$nextTick(() => { this.$nextTick(() => {
// 将当前的值发送到 u-form-item 进行校验 // 将当前的值发送到 u-form-item 进行校验
this.dispatch('u-form-item', 'on-form-change', event.detail.value); this.dispatch('u-form-item', 'on-form-change', value);
}); });
}, },
/** /**
......
...@@ -114,7 +114,7 @@ ...@@ -114,7 +114,7 @@
}, },
// 计算图片的高度,可能为auto,带%,或者直接数值 // 计算图片的高度,可能为auto,带%,或者直接数值
imgHeight() { imgHeight() {
return this.height == 'auto' ? 'auto' : String(this.height).indexOf('%') != -1 ? this.height : this.height + 'rpx'; return this.$u.addUnit(this.height);
} }
}, },
created() { created() {
...@@ -133,9 +133,18 @@ ...@@ -133,9 +133,18 @@
this.time = this.duration; this.time = this.duration;
this.opacity = 1; this.opacity = 1;
}, 30) }, 30)
},
// 图片路径发生变化时,需要重新标记一些变量,否则会一直卡在某一个状态,比如isError
image(n) {
this.init();
} }
}, },
methods: { methods: {
// 用于重新初始化
init() {
this.isError = false;
this.loadStatus = '';
},
// 点击图片触发的事件,loadlazy-还是懒加载中状态,loading-图片正在加载,loaded-图片加加载完成 // 点击图片触发的事件,loadlazy-还是懒加载中状态,loading-图片正在加载,loaded-图片加加载完成
clickImg() { clickImg() {
let whichImg = ''; let whichImg = '';
......
<template>
<view class="u-loading-page">
</view>
</template>
<script>
export default {
props: {
},
data() {
return {
}
},
methods: {
}
}
</script>
<style lang="scss" scoped>
</style>
...@@ -221,7 +221,9 @@ ...@@ -221,7 +221,9 @@
goBack() { goBack() {
// 如果自定义了点击返回按钮的函数,则执行,否则执行返回逻辑 // 如果自定义了点击返回按钮的函数,则执行,否则执行返回逻辑
if (typeof this.customBack === 'function') { if (typeof this.customBack === 'function') {
this.customBack(); // 在微信,支付宝等环境(H5正常),会导致父组件定义的customBack()函数体中的this变成子组件的this
// 通过bind()方法,绑定父组件的this,让this.customBack()的this为父组件的上下文
this.customBack.bind(this.$u.$parent.call(this))();
} else { } else {
uni.navigateBack(); uni.navigateBack();
} }
......
<template> <template>
<view class="u-numberbox"> <view class="u-numberbox">
<view class="u-icon-minus" @touchstart.stop="btnTouchStart('minus')" @touchend.stop="clearTimer" :class="{ 'u-icon-disabled': disabled || inputVal <= min }" <view class="u-icon-minus" @touchstart.stop.prevent="btnTouchStart('minus')" @touchend.stop.prevent="clearTimer" :class="{ 'u-icon-disabled': disabled || inputVal <= min }"
:style="{ :style="{
background: bgColor, background: bgColor,
height: inputHeight + 'rpx', height: inputHeight + 'rpx',
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
height: inputHeight + 'rpx', height: inputHeight + 'rpx',
width: inputWidth + 'rpx' width: inputWidth + 'rpx'
}" /> }" />
<view class="u-icon-plus" @touchstart.stop="btnTouchStart('plus')" @touchend.stop="clearTimer" :class="{ 'u-icon-disabled': disabled || inputVal >= max }" <view class="u-icon-plus" @touchstart.stop.prevent="btnTouchStart('plus')" @touchend.stop.prevent="clearTimer" :class="{ 'u-icon-disabled': disabled || inputVal >= max }"
:style="{ :style="{
background: bgColor, background: bgColor,
height: inputHeight + 'rpx', height: inputHeight + 'rpx',
......
...@@ -284,6 +284,9 @@ export default { ...@@ -284,6 +284,9 @@ export default {
this.close(); this.close();
}, },
close() { close() {
// 标记关闭是内部发生的,否则修改了value值,导致watch中对value检测,导致再执行一遍close
// 造成@close事件触发两次
this.closeFromInner = true;
this.change('showDrawer', 'visibleSync', false); this.change('showDrawer', 'visibleSync', false);
}, },
// 中部弹出时,需要.u-drawer-content将居中内容,此元素会铺满屏幕,点击需要关闭弹窗 // 中部弹出时,需要.u-drawer-content将居中内容,此元素会铺满屏幕,点击需要关闭弹窗
...@@ -300,9 +303,6 @@ export default { ...@@ -300,9 +303,6 @@ export default {
change(param1, param2, status) { change(param1, param2, status) {
// 如果this.popup为false,意味着为picker,actionsheet等组件调用了popup组件 // 如果this.popup为false,意味着为picker,actionsheet等组件调用了popup组件
if (this.popup == true) { if (this.popup == true) {
// 标记关闭是内部发生的,否则修改了value值,导致watch中对value检测,导致再执行一遍close
// 造成@close事件触发两次
this.closeFromInner = true;
this.$emit('input', status); this.$emit('input', status);
} }
this[param1] = status; this[param1] = status;
......
...@@ -84,6 +84,11 @@ ...@@ -84,6 +84,11 @@
textIndent: { textIndent: {
type: String, type: String,
default: '2em' default: '2em'
},
// open和close事件时,将此参数返回在回调参数中
index: {
type: [Number, String],
default: ''
} }
}, },
watch: { watch: {
...@@ -128,6 +133,8 @@ ...@@ -128,6 +133,8 @@
this.showMore = !this.showMore; this.showMore = !this.showMore;
// 如果toggle为false,隐藏"收起"部分的内容 // 如果toggle为false,隐藏"收起"部分的内容
if (this.toggle == false) this.isLongContent = false; if (this.toggle == false) this.isLongContent = false;
// 发出打开或者收齐的事件
this.$emit(this.showMore ? 'open' : 'close', this.index);
} }
} }
}; };
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
</view> </view>
<view class="u-section__right-info" v-if="right" :style="{ <view class="u-section__right-info" v-if="right" :style="{
color: subColor color: subColor
}" @tap="rightClick"> }" @tap="rightClick">
{{subTitle}} {{subTitle}}
<view class="u-section__right-info__icon-arrow u-flex"> <view class="u-section__right-info__icon-arrow u-flex">
<u-icon name="arrow-right" size="24" :color="subColor"></u-icon> <u-icon name="arrow-right" size="24" :color="subColor"></u-icon>
......
...@@ -94,8 +94,16 @@ ...@@ -94,8 +94,16 @@
methods: { methods: {
// 查询各节点的信息 // 查询各节点的信息
selecterQueryInfo() { selecterQueryInfo() {
// 获取整个父组件容器的高度,当做骨架屏的高度 // 获取整个父组件容器的高度,当做骨架屏的高度
uni.createSelectorQuery().selectAll('.u-skeleton').boundingClientRect().exec((res) => { // 在微信小程序中,如果把骨架屏放入组件中使用的话,需要调in(this)上下文为父组件才有效
let query = '';
// #ifdef MP-WEIXIN
query = uni.createSelectorQuery().in(this.$parent);
// #endif
// #ifndef MP-WEIXIN
query = uni.createSelectorQuery()
// #endif
query.selectAll('.u-skeleton').boundingClientRect().exec((res) => {
this.windowHeight = res[0][0].height; this.windowHeight = res[0][0].height;
this.windowWinth = res[0][0].width; this.windowWinth = res[0][0].width;
this.top = res[0][0].bottom - res[0][0].height; this.top = res[0][0].bottom - res[0][0].height;
...@@ -110,19 +118,43 @@ ...@@ -110,19 +118,43 @@
}, },
// 矩形元素列表 // 矩形元素列表
getRectEls() { getRectEls() {
uni.createSelectorQuery().selectAll('.u-skeleton-rect').boundingClientRect().exec((res) => { let query = '';
// 在微信小程序中,如果把骨架屏放入组件中使用的话,需要调in(this)上下文为父组件才有效
// #ifdef MP-WEIXIN
query = uni.createSelectorQuery().in(this.$parent);
// #endif
// #ifndef MP-WEIXIN
query = uni.createSelectorQuery()
// #endif
query.selectAll('.u-skeleton-rect').boundingClientRect().exec((res) => {
this.RectNodes = res[0]; this.RectNodes = res[0];
}); });
}, },
// 圆角元素列表 // 圆角元素列表
getFilletEls() { getFilletEls() {
uni.createSelectorQuery().selectAll('.u-skeleton-fillet').boundingClientRect().exec((res) => { let query = '';
// 在微信小程序中,如果把骨架屏放入组件中使用的话,需要调in(this)上下文为父组件才有效
// #ifdef MP-WEIXIN
query = uni.createSelectorQuery().in(this.$parent);
// #endif
// #ifndef MP-WEIXIN
query = uni.createSelectorQuery()
// #endif
query.selectAll('.u-skeleton-fillet').boundingClientRect().exec((res) => {
this.filletNodes = res[0]; this.filletNodes = res[0];
}); });
}, },
// 圆形元素列表 // 圆形元素列表
getCircleEls() { getCircleEls() {
uni.createSelectorQuery().selectAll('.u-skeleton-circle').boundingClientRect().exec((res) => { let query = '';
// 在微信小程序中,如果把骨架屏放入组件中使用的话,需要调in(this)上下文为父组件才有效
// #ifdef MP-WEIXIN
query = uni.createSelectorQuery().in(this.$parent);
// #endif
// #ifndef MP-WEIXIN
query = uni.createSelectorQuery()
// #endif
query.selectAll('.u-skeleton-circle').boundingClientRect().exec((res) => {
this.circleNodes = res[0]; this.circleNodes = res[0];
}); });
} }
......
...@@ -141,6 +141,9 @@ ...@@ -141,6 +141,9 @@
const observer = this[observerName]; const observer = this[observerName];
observer && observer.disconnect(); observer && observer.disconnect();
}, },
},
beforeDestroy() {
this.disconnectObserver('contentObserver');
} }
}; };
</script> </script>
......
...@@ -174,7 +174,9 @@ ...@@ -174,7 +174,9 @@
async clickHandler(index) { async clickHandler(index) {
if(this.beforeSwitch && typeof(this.beforeSwitch) === 'function') { if(this.beforeSwitch && typeof(this.beforeSwitch) === 'function') {
// 执行回调,同时传入索引当作参数 // 执行回调,同时传入索引当作参数
let beforeSwitch = this.beforeSwitch(index); // 在微信,支付宝等环境(H5正常),会导致父组件定义的customBack()函数体中的this变成子组件的this
// 通过bind()方法,绑定父组件的this,让this.customBack()的this为父组件的上下文
let beforeSwitch = this.beforeSwitch.bind(this.$u.$parent.call(this))(index);
// 判断是否返回了promise // 判断是否返回了promise
if (!!beforeSwitch && typeof beforeSwitch.then === 'function') { if (!!beforeSwitch && typeof beforeSwitch.then === 'function') {
await beforeSwitch.then(res => { await beforeSwitch.then(res => {
......
...@@ -359,11 +359,6 @@ export default { ...@@ -359,11 +359,6 @@ export default {
this.$emit('on-uploaded', this.lists); this.$emit('on-uploaded', this.lists);
return; return;
} }
// 检查上传地址
if (!this.action) {
this.showToast('请配置上传地址', true);
return;
}
// 检查是否是已上传或者正在上传中 // 检查是否是已上传或者正在上传中
if (this.lists[index].progress == 100) { if (this.lists[index].progress == 100) {
if (this.autoUpload == false) this.uploadFile(index + 1); if (this.autoUpload == false) this.uploadFile(index + 1);
...@@ -372,7 +367,12 @@ export default { ...@@ -372,7 +367,12 @@ export default {
// 执行before-upload钩子 // 执行before-upload钩子
if(this.beforeUpload && typeof(this.beforeUpload) === 'function') { if(this.beforeUpload && typeof(this.beforeUpload) === 'function') {
// 执行回调,同时传入索引和文件列表当作参数 // 执行回调,同时传入索引和文件列表当作参数
let beforeResponse = this.beforeUpload(index, this.lists); // 在微信,支付宝等环境(H5正常),会导致父组件定义的customBack()函数体中的this变成子组件的this
// 通过bind()方法,绑定父组件的this,让this.customBack()的this为父组件的上下文
// 因为upload组件可能会被嵌套在其他组件内,比如u-form,这时this.$parent其实为u-form的this,
// 非页面的this,所以这里需要往上历遍,一直寻找到最顶端的$parent,这里用了this.$u.$parent.call(this)
// 明白意思即可,无需纠结this.$u.$parent.call(this)的细节
let beforeResponse = this.beforeUpload.bind(this.$u.$parent.call(this))(index, this.lists);
// 判断是否返回了promise // 判断是否返回了promise
if (!!beforeResponse && typeof beforeResponse.then === 'function') { if (!!beforeResponse && typeof beforeResponse.then === 'function') {
await beforeResponse.then(res => { await beforeResponse.then(res => {
...@@ -386,6 +386,11 @@ export default { ...@@ -386,6 +386,11 @@ export default {
return this.uploadFile(index + 1); return this.uploadFile(index + 1);
} }
} }
// 检查上传地址
if (!this.action) {
this.showToast('请配置上传地址', true);
return;
}
this.lists[index].error = false; this.lists[index].error = false;
this.uploading = true; this.uploading = true;
// 创建上传对象 // 创建上传对象
...@@ -398,7 +403,7 @@ export default { ...@@ -398,7 +403,7 @@ export default {
success: res => { success: res => {
// 判断是否json字符串,将其转为json格式 // 判断是否json字符串,将其转为json格式
let data = this.toJson && this.$u.test.jsonString(res.data) ? JSON.parse(res.data) : res.data; let data = this.toJson && this.$u.test.jsonString(res.data) ? JSON.parse(res.data) : res.data;
if (![200, 201].includes(res.statusCode)) { if (![200, 201, 204].includes(res.statusCode)) {
this.uploadError(index, data); this.uploadError(index, data);
} else { } else {
// 上传成功 // 上传成功
......
This diff is collapsed.
...@@ -60,6 +60,14 @@ import toast from './libs/function/toast.js' ...@@ -60,6 +60,14 @@ import toast from './libs/function/toast.js'
import getParent from './libs/function/getParent.js' import getParent from './libs/function/getParent.js'
// 获取整个父组件 // 获取整个父组件
import $parent from './libs/function/$parent.js' import $parent from './libs/function/$parent.js'
// 获取sys()和os()工具方法
// 获取设备信息,挂载到$u的sys()(system的缩写)属性中,
// 同时把安卓和ios平台的名称"ios"和"android"挂到$u.os()中,方便取用
import {sys, os} from './libs/function/sys.js'
// 防抖方法
import debounce from './libs/function/debounce.js'
// 节流方法
import throttle from './libs/function/throttle.js'
// 配置信息 // 配置信息
...@@ -76,6 +84,8 @@ const $u = { ...@@ -76,6 +84,8 @@ const $u = {
colorGradient: colorGradient.colorGradient, colorGradient: colorGradient.colorGradient,
guid, guid,
color, color,
sys,
os,
type2icon, type2icon,
randomArray, randomArray,
wranning, wranning,
...@@ -97,7 +107,9 @@ const $u = { ...@@ -97,7 +107,9 @@ const $u = {
http, http,
toast, toast,
config, // uView配置信息相关,比如版本号 config, // uView配置信息相关,比如版本号
zIndex zIndex,
debounce,
throttle,
} }
const install = Vue => { const install = Vue => {
...@@ -117,10 +129,6 @@ const install = Vue => { ...@@ -117,10 +129,6 @@ const install = Vue => {
Vue.filter('timeFrom', (timestamp, format) => { Vue.filter('timeFrom', (timestamp, format) => {
return timeFrom(timestamp, format) return timeFrom(timestamp, format)
}) })
// 获取设备信息,挂载到$u的sys(system的缩写)属性中,
// 同时把安卓和ios平台的名称"ios"和"android"挂到$u.os中,方便取用
$u.sys = uni.getSystemInfoSync();
$u.os = $u.sys.platform;
Vue.prototype.$u = $u Vue.prototype.$u = $u
} }
......
// 此版本发布于2020-07-29 // 此版本发布于2020-08-04
let version = '1.5.7'; let version = '1.5.8';
export default { export default {
v: version, v: version,
......
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
image { image {
display: inline-block; display: inline-block;
// 解决图片加载时可能会瞬间变形的问题
will-change: transform;
} }
// 在weex,也即nvue中,所有元素默认为border-box // 在weex,也即nvue中,所有元素默认为border-box
......
// 获取父组件的参数,因为支付宝小程序不支持provide/inject的写法 // 获取父组件的参数,因为支付宝小程序不支持provide/inject的写法
// this.$parent在非H5中,可以准确获取到父组件,但是在H5中,需要多次this.$parent.$parent.xxx // this.$parent在非H5中,可以准确获取到父组件,但是在H5中,需要多次this.$parent.$parent.xxx
export default function $parent(name, keys) { // 这里默认值等于undefined有它的含义,因为最顶层元素(组件)的$parent就是undefined,意味着不传name
// 值(默认为undefined),就是查找最顶层的$parent
export default function $parent(name = undefined) {
let parent = this.$parent; let parent = this.$parent;
// 通过while历遍,这里主要是为了H5需要多层解析的问题 // 通过while历遍,这里主要是为了H5需要多层解析的问题
while (parent) { while (parent) {
// 父组件 // 父组件
if (parent.$options.name !== name) { if (parent.$options && parent.$options.name !== name) {
// 如果组件的name不相等,继续上一级寻找 // 如果组件的name不相等,继续上一级寻找
parent = parent.$parent; parent = parent.$parent;
} else { } else {
......
let timeout = null;
/**
* 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
function debounce(func, wait = 500, immediate = false) {
// 清除定时器
if (timeout !== null) clearTimeout(timeout);
// 立即执行,此类情况一般用不到
if (immediate) {
var callNow = !timeout;
timeout = setTimeout(function() {
timeout = null;
}, wait);
if (callNow) typeof func === 'function' && func();
} else {
// 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
timeout = setTimeout(function() {
typeof func === 'function' && func();
}, wait);
}
}
export default debounce
export function os() {
return uni.getSystemInfoSync().platform;
};
export function sys() {
return uni.getSystemInfoSync();
}
let timer, flag;
/**
* 节流原理:在一定时间内,只能触发一次
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
function throttle(func, wait = 500, immediate = true) {
if (immediate) {
if (!flag) {
flag = true;
// 如果是立即执行,则在wait毫秒内开始时执行
typeof func === 'function' && func();
timer = setTimeout(() => {
flag = false;
}, wait);
}
} else {
if (!flag) {
flag = true
// 如果是非立即执行,则在wait毫秒内的结束处执行
timer = setTimeout(() => {
flag = false
typeof func === 'function' && func();
}, wait);
}
}
};
export default throttle
// padStart 的 polyfill,因为某些机型或情况,还无法支持es7的padStart,比如电脑版的微信小程序
// 所以这里做一个兼容polyfill的兼容处理
if (!String.prototype.padStart){
String.prototype.padStart =
// 为了方便表示这里 fillString 用了ES6 的默认参数,不影响理解
function(maxLength, fillString = ' ') {
if (Object.prototype.toString.call(fillString) !== "[object String]") throw new TypeError('fillString must be String')
let str = this
// 返回 String(str) 这里是为了使返回的值是字符串字面量,在控制台中更符合直觉
if (str.length >= maxLength) return String(str)
let fillLength = maxLength - str.length,
times = Math.ceil(fillLength / fillString.length)
while (times >>= 1) {
fillString += fillString
if (times === 1) {
fillString += fillString
}
}
return fillString.slice(0, fillLength) + str;
}
}
function timeFormat(timestamp = null, fmt = 'yyyy-mm-dd') { function timeFormat(timestamp = null, fmt = 'yyyy-mm-dd') {
// 其他更多是格式化有如下: // 其他更多是格式化有如下:
// yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 // yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合
...@@ -20,6 +43,7 @@ function timeFormat(timestamp = null, fmt = 'yyyy-mm-dd') { ...@@ -20,6 +43,7 @@ function timeFormat(timestamp = null, fmt = 'yyyy-mm-dd') {
for (let k in opt) { for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt); ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) { if (ret) {
console.log(k, ret, opt[k]);
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0"))) fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
}; };
}; };
......
{ {
"name": "uview-ui", "name": "uview-ui",
"version": "1.5.7", "version": "1.5.8",
"description": "uView UI,是uni-app生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水", "description": "uView UI,是uni-app生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水",
"main": "index.js", "main": "index.js",
"keywords": ["uview", "uView", "uni-app", "uni-app ui", "uniapp", "uviewui", "uview ui", "uviewUI", "uViewui", "uViewUI", "uView UI", "uni ui", "uni UI", "uniapp ui", "ui", "UI框架", "uniapp ui框架", "uniapp UI"], "keywords": ["uview", "uView", "uni-app", "uni-app ui", "uniapp", "uviewui", "uview ui", "uviewUI", "uViewui", "uViewUI", "uView UI", "uni ui", "uni UI", "uniapp ui", "ui", "UI框架", "uniapp ui框架", "uniapp UI"],
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment