Commit a9758b91 authored by wlxuqu's avatar wlxuqu

Merge branch 'yiruiwen' into dev

parents 36bc753b c1c3e009
...@@ -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.6", "versionName" : "1.5.8",
"versionCode" : "100", "versionCode" : "100",
"transformPx" : false, "transformPx" : false,
"app-plus" : { "app-plus" : {
...@@ -107,7 +107,7 @@ ...@@ -107,7 +107,7 @@
}, },
"mp-alipay" : { "mp-alipay" : {
"usingComponents" : true, "usingComponents" : true,
"component2": true "component2" : true
}, },
"mp-baidu" : { "mp-baidu" : {
"usingComponents" : true, "usingComponents" : true,
...@@ -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",
......
...@@ -14,6 +14,15 @@ ...@@ -14,6 +14,15 @@
data() { data() {
return { return {
iconList: [ iconList: [
{
name: 'level'
},
{
name: 'woman'
},
{
name: 'man'
},
{ {
name: 'arrow-left-double' name: 'arrow-left-double'
}, },
......
<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"></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') : 0 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;
......
...@@ -72,32 +72,32 @@ ...@@ -72,32 +72,32 @@
<script> <script>
import Emitter from '../../libs/util/emitter.js'; import Emitter from '../../libs/util/emitter.js';
/** /**
* input 输入框 * input 输入框
* @description 此组件为一个输入框,默认没有边框和样式,是专门为配合表单组件u-form而设计的,利用它可以快速实现表单验证,输入内容,下拉选择等功能。 * @description 此组件为一个输入框,默认没有边框和样式,是专门为配合表单组件u-form而设计的,利用它可以快速实现表单验证,输入内容,下拉选择等功能。
* @tutorial http://uviewui.com/components/input.html * @tutorial http://uviewui.com/components/input.html
* @property {String} type 模式选择,见官网说明 * @property {String} type 模式选择,见官网说明
* @property {Boolean} clearable 是否显示右侧的清除图标(默认true) * @property {Boolean} clearable 是否显示右侧的清除图标(默认true)
* @property {} v-model 用于双向绑定输入框的值 * @property {} v-model 用于双向绑定输入框的值
* @property {String} input-align 输入框文字的对齐方式(默认left) * @property {String} input-align 输入框文字的对齐方式(默认left)
* @property {String} placeholder placeholder显示值(默认 '请输入内容') * @property {String} placeholder placeholder显示值(默认 '请输入内容')
* @property {Boolean} disabled 是否禁用输入框(默认false) * @property {Boolean} disabled 是否禁用输入框(默认false)
* @property {String Number} maxlength 输入框的最大可输入长度(默认140) * @property {String Number} maxlength 输入框的最大可输入长度(默认140)
* @property {String Number} selection-start 光标起始位置,自动聚焦时有效,需与selection-end搭配使用(默认-1) * @property {String Number} selection-start 光标起始位置,自动聚焦时有效,需与selection-end搭配使用(默认-1)
* @property {String Number} maxlength 光标结束位置,自动聚焦时有效,需与selection-start搭配使用(默认-1) * @property {String Number} maxlength 光标结束位置,自动聚焦时有效,需与selection-start搭配使用(默认-1)
* @property {String Number} cursor-spacing 指定光标与键盘的距离,单位px(默认0) * @property {String Number} cursor-spacing 指定光标与键盘的距离,单位px(默认0)
* @property {String} placeholderStyle placeholder的样式,字符串形式,如"color: red;"(默认 "color: #c0c4cc;") * @property {String} placeholderStyle placeholder的样式,字符串形式,如"color: red;"(默认 "color: #c0c4cc;")
* @property {String} confirm-type 设置键盘右下角按钮的文字,仅在type为text时生效(默认done) * @property {String} confirm-type 设置键盘右下角按钮的文字,仅在type为text时生效(默认done)
* @property {Object} custom-style 自定义输入框的样式,对象形式 * @property {Object} custom-style 自定义输入框的样式,对象形式
* @property {Boolean} focus 是否自动获得焦点(默认false) * @property {Boolean} focus 是否自动获得焦点(默认false)
* @property {Boolean} fixed 如果type为textarea,且在一个"position:fixed"的区域,需要指明为true(默认false) * @property {Boolean} fixed 如果type为textarea,且在一个"position:fixed"的区域,需要指明为true(默认false)
* @property {Boolean} password-icon type为password时,是否显示右侧的密码查看图标(默认true) * @property {Boolean} password-icon type为password时,是否显示右侧的密码查看图标(默认true)
* @property {Boolean} border 是否显示边框(默认false) * @property {Boolean} border 是否显示边框(默认false)
* @property {String} border-color 输入框的边框颜色(默认#dcdfe6) * @property {String} border-color 输入框的边框颜色(默认#dcdfe6)
* @property {Boolean} auto-height 是否自动增高输入区域,type为textarea时有效(默认true) * @property {Boolean} auto-height 是否自动增高输入区域,type为textarea时有效(默认true)
* @property {String Number} height 高度,单位rpx(text类型时为70,textarea时为100) * @property {String Number} height 高度,单位rpx(text类型时为70,textarea时为100)
* @example <u-input v-model="value" :type="type" :border="border" /> * @example <u-input v-model="value" :type="type" :border="border" />
*/ */
export default { export default {
name: 'u-input', name: 'u-input',
mixins: [Emitter], mixins: [Emitter],
...@@ -201,6 +201,11 @@ export default { ...@@ -201,6 +201,11 @@ export default {
selectionEnd: { selectionEnd: {
type: [Number, String], type: [Number, String],
default: -1 default: -1
},
// 是否自动去除两端的空格
trim: {
type: Boolean,
default: true
} }
}, },
data() { data() {
...@@ -260,15 +265,18 @@ export default { ...@@ -260,15 +265,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',
......
/** /**
* html 解析器 * html 解析器
* @tutorial https://github.com/jin-yufeng/Parser * @tutorial https://github.com/jin-yufeng/Parser
* @version 20200719 * @version 20200728
* @author JinYufeng * @author JinYufeng
* @listens MIT * @listens MIT
*/ */
...@@ -102,9 +102,16 @@ MpHtmlParser.prototype.setText = function() { ...@@ -102,9 +102,16 @@ MpHtmlParser.prototype.setText = function() {
} }
if (!this.pre) { if (!this.pre) {
// 合并空白符 // 合并空白符
var tmp = []; var flag, tmp = [];
for (let i = text.length, c; c = text[--i];) for (let i = text.length, c; c = text[--i];)
if (!blankChar[c] || (!blankChar[tmp[0]] && (c = ' '))) tmp.unshift(c); if (!blankChar[c]) {
tmp.unshift(c);
if (!flag) flag = 1;
} else {
if (tmp[0] != ' ') tmp.unshift(' ');
if (c == '\n' && flag == void 0) flag = 0;
}
if (flag == 0) return;
text = tmp.join(''); text = tmp.join('');
} }
this.siblings().push({ this.siblings().push({
...@@ -119,6 +126,7 @@ MpHtmlParser.prototype.setNode = function() { ...@@ -119,6 +126,7 @@ MpHtmlParser.prototype.setNode = function() {
attrs: this.attrs attrs: this.attrs
}, },
close = cfg.selfClosingTags[node.name]; close = cfg.selfClosingTags[node.name];
if (this.options.nodes.length) node.type = 'node';
this.attrs = {}; this.attrs = {};
if (!cfg.ignoreTags[node.name]) { if (!cfg.ignoreTags[node.name]) {
// 处理属性 // 处理属性
...@@ -189,6 +197,7 @@ MpHtmlParser.prototype.setNode = function() { ...@@ -189,6 +197,7 @@ MpHtmlParser.prototype.setNode = function() {
attrs.height = void 0; attrs.height = void 0;
} }
} }
if (!attrs.controls && !attrs.autoplay) attrs.controls = 'T';
attrs.source = []; attrs.source = [];
if (attrs.src) { if (attrs.src) {
attrs.source.push(attrs.src); attrs.source.push(attrs.src);
...@@ -217,8 +226,7 @@ MpHtmlParser.prototype.setNode = function() { ...@@ -217,8 +226,7 @@ MpHtmlParser.prototype.setNode = function() {
if (info.length < 2) continue; if (info.length < 2) continue;
let key = info[0].trim().toLowerCase(), let key = info[0].trim().toLowerCase(),
value = info.slice(1).join(':').trim(); value = info.slice(1).join(':').trim();
if (value.includes('-webkit') || value.includes('-moz') || value.includes('-ms') || value.includes('-o') || value.includes( if (value[0] == '-' || value.includes('safe'))
'safe'))
style += `;${key}:${value}`; style += `;${key}:${value}`;
else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import')) else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import'))
styleObj[key] = value; styleObj[key] = value;
...@@ -359,13 +367,6 @@ MpHtmlParser.prototype.popNode = function(node) { ...@@ -359,13 +367,6 @@ MpHtmlParser.prototype.popNode = function(node) {
// 替换一些标签名 // 替换一些标签名
if (cfg.blockTags[node.name]) node.name = 'div'; if (cfg.blockTags[node.name]) node.name = 'div';
else if (!cfg.trustTags[node.name]) node.name = 'span'; else if (!cfg.trustTags[node.name]) node.name = 'span';
// 去除块标签前后空串
if (node.name == 'div' || node.name == 'p' || node.name[0] == 't') {
if (len > 1 && siblings[len - 2].text == ' ')
siblings.splice(--len - 1, 1);
if (childs.length && childs[childs.length - 1].text == ' ')
childs.pop();
}
// 处理列表 // 处理列表
if (node.c && (node.name == 'ul' || node.name == 'ol')) { if (node.c && (node.name == 'ul' || node.name == 'ol')) {
if ((node.attrs.style || '').includes('list-style:none')) { if ((node.attrs.style || '').includes('list-style:none')) {
......
/* 配置文件 */ /* 配置文件 */
// #ifdef MP-WEIXIN var cfg = {
const canIUse = wx.canIUse('editor'); // 高基础库标识,用于兼容
// #endif
module.exports = {
// 出错占位图 // 出错占位图
errorImg: null, errorImg: null,
// 过滤器函数 // 过滤器函数
...@@ -32,41 +29,15 @@ module.exports = { ...@@ -32,41 +29,15 @@ module.exports = {
blankChar: makeMap(' ,\xA0,\t,\r,\n,\f'), blankChar: makeMap(' ,\xA0,\t,\r,\n,\f'),
boolAttrs: makeMap('allowfullscreen,autoplay,autostart,controls,ignore,loop,muted'), boolAttrs: makeMap('allowfullscreen,autoplay,autostart,controls,ignore,loop,muted'),
// 块级标签,将被转为 div // 块级标签,将被转为 div
blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,section' + ( blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,pre,section'),
// #ifdef MP-WEIXIN
canIUse ? '' :
// #endif
',pre')),
// 将被移除的标签 // 将被移除的标签
ignoreTags: makeMap( ignoreTags: makeMap('area,base,canvas,frame,iframe,input,link,map,meta,param,script,source,style,svg,textarea,title,track,wbr'),
'area,base,canvas,frame,input,link,map,meta,param,script,source,style,svg,textarea,title,track,wbr'
// #ifdef MP-WEIXIN
+ (canIUse ? ',rp' : '')
// #endif
// #ifndef APP-PLUS
+ ',iframe'
// #endif
),
// 只能被 rich-text 显示的标签 // 只能被 rich-text 显示的标签
richOnlyTags: makeMap('a,colgroup,fieldset,legend,table' richOnlyTags: makeMap('a,colgroup,fieldset,legend,table'),
// #ifdef MP-WEIXIN
+ (canIUse ? ',bdi,bdo,caption,rt,ruby' : '')
// #endif
),
// 自闭合的标签 // 自闭合的标签
selfClosingTags: makeMap( selfClosingTags: makeMap('area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),
'area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'
),
// 信任的标签 // 信任的标签
trustTags: makeMap( trustTags: makeMap('a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'),
'a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'
// #ifdef MP-WEIXIN
+ (canIUse ? ',bdi,bdo,caption,pre,rt,ruby' : '')
// #endif
// #ifdef APP-PLUS
+ ',embed,iframe'
// #endif
),
// 默认的标签样式 // 默认的标签样式
userAgentStyles: { userAgentStyles: {
address: 'font-style:italic', address: 'font-style:italic',
...@@ -91,3 +62,19 @@ function makeMap(str) { ...@@ -91,3 +62,19 @@ function makeMap(str) {
map[list[i]] = true; map[list[i]] = true;
return map; return map;
} }
// #ifdef MP-WEIXIN
if (wx.canIUse('editor')) {
cfg.blockTags.pre = void 0;
cfg.ignoreTags.rp = true;
Object.assign(cfg.richOnlyTags, makeMap('bdi,bdo,caption,rt,ruby'));
Object.assign(cfg.trustTags, makeMap('bdi,bdo,caption,pre,rt,ruby'));
}
// #endif
// #ifdef APP-PLUS
cfg.ignoreTags.iframe = void 0;
Object.assign(cfg.trustTags, makeMap('embed,iframe'));
// #endif
module.exports = cfg;
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
<block v-for="(n, i) in nodes" v-bind:key="i"> <block v-for="(n, i) in nodes" v-bind:key="i">
<!--图片--> <!--图片-->
<view v-if="n.name=='img'" :class="'_img '+n.attrs.class" :style="n.attrs.style" :data-attrs="n.attrs" @tap="imgtap"> <view v-if="n.name=='img'" :class="'_img '+n.attrs.class" :style="n.attrs.style" :data-attrs="n.attrs" @tap="imgtap">
<rich-text v-if="controls[i]!=0" :nodes="[{attrs:{src:loading&&(controls[i]||0)<2?loading:(lazyLoad&&!controls[i]?placeholder:(controls[i]==3?errorImg:n.attrs.src||'')),alt:n.attrs.alt||'',width:n.attrs.width||'',style:'-webkit-touch-callout:none;max-width:100%;display:block'+(n.attrs.height?';height:'+n.attrs.height:'')},name:'img'}]" /> <rich-text v-if="ctrl[i]!=0" :nodes="[{attrs:{src:loading&&(ctrl[i]||0)<2?loading:(lazyLoad&&!ctrl[i]?placeholder:(ctrl[i]==3?errorImg:n.attrs.src||'')),alt:n.attrs.alt||'',width:n.attrs.width||'',style:'-webkit-touch-callout:none;max-width:100%;display:block'+(n.attrs.height?';height:'+n.attrs.height:'')},name:'img'}]" />
<image class="_image" :src="lazyLoad&&!controls[i]?placeholder:n.attrs.src" :lazy-load="lazyLoad" <image class="_image" :src="lazyLoad&&!ctrl[i]?placeholder:n.attrs.src" :lazy-load="lazyLoad"
:show-menu-by-longpress="!n.attrs.ignore" :data-i="i" :data-index="n.attrs.i" data-source="img" @load="loadImg" :show-menu-by-longpress="!n.attrs.ignore" :data-i="i" :data-index="n.attrs.i" data-source="img" @load="loadImg"
@error="error" /> @error="error" />
</view> </view>
...@@ -14,15 +14,15 @@ ...@@ -14,15 +14,15 @@
<text v-else-if="n.name=='br'">\n</text> <text v-else-if="n.name=='br'">\n</text>
<!--#endif--> <!--#endif-->
<!--视频--> <!--视频-->
<view v-else-if="((n.lazyLoad&&!n.attrs.autoplay)||(n.name=='video'&&!loadVideo))&&controls[i]==undefined" :id="n.attrs.id" :class="'_video '+(n.attrs.class||'')" <view v-else-if="((n.lazyLoad&&!n.attrs.autoplay)||(n.name=='video'&&!loadVideo))&&ctrl[i]==undefined" :id="n.attrs.id" :class="'_video '+(n.attrs.class||'')"
:style="n.attrs.style" :data-i="i" @tap="_loadVideo" /> :style="n.attrs.style" :data-i="i" @tap="_loadVideo" />
<video v-else-if="n.name=='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay||controls[i]==0" <video v-else-if="n.name=='video'" :id="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :autoplay="n.attrs.autoplay||ctrl[i]==0"
:controls="!n.attrs.autoplay||n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :poster="n.attrs.poster" :src="n.attrs.source[controls[i]||0]" :controls="n.attrs.controls" :loop="n.attrs.loop" :muted="n.attrs.muted" :poster="n.attrs.poster" :src="n.attrs.source[ctrl[i]||0]"
:unit-id="n.attrs['unit-id']" :data-id="n.attrs.id" :data-i="i" data-source="video" @error="error" @play="play" /> :unit-id="n.attrs['unit-id']" :data-id="n.attrs.id" :data-i="i" data-source="video" @error="error" @play="play" />
<!--音频--> <!--音频-->
<audio v-else-if="n.name=='audio'" :ref="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author" <audio v-else-if="n.name=='audio'" :ref="n.attrs.id" :class="n.attrs.class" :style="n.attrs.style" :author="n.attrs.author"
:autoplay="n.attrs.autoplay" :controls="!n.attrs.autoplay||n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster" :autoplay="n.attrs.autoplay" :controls="n.attrs.controls" :loop="n.attrs.loop" :name="n.attrs.name" :poster="n.attrs.poster"
:src="n.attrs.source[controls[i]||0]" :data-i="i" :data-id="n.attrs.id" data-source="audio" :src="n.attrs.source[ctrl[i]||0]" :data-i="i" :data-id="n.attrs.id" data-source="audio"
@error.native="error" @play.native="play" /> @error.native="error" @play.native="play" />
<!--链接--> <!--链接-->
<view v-else-if="n.name=='a'" :id="n.attrs.id" :class="'_a '+(n.attrs.class||'')" hover-class="_hover" :style="n.attrs.style" <view v-else-if="n.name=='a'" :id="n.attrs.id" :class="'_a '+(n.attrs.class||'')" hover-class="_hover" :style="n.attrs.style"
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
<!--广告--> <!--广告-->
<!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :unit-id="n.attrs['unit-id']" :appid="n.attrs.appid" :apid="n.attrs.apid" :type="n.attrs.type" :adpid="n.attrs.adpid" data-source="ad" @error="error" />--> <!--<ad v-else-if="n.name=='ad'" :class="n.attrs.class" :style="n.attrs.style" :unit-id="n.attrs['unit-id']" :appid="n.attrs.appid" :apid="n.attrs.apid" :type="n.attrs.type" :adpid="n.attrs.adpid" data-source="ad" @error="error" />-->
<!--列表--> <!--列表-->
<view v-else-if="n.name=='li'" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:flex'"> <view v-else-if="n.name=='li'" :id="n.attrs.id" :class="n.attrs.class" :style="(n.attrs.style||'')+';display:flex;flex-direction:row'">
<view v-if="n.type=='ol'" class="_ol-bef">{{n.num}}</view> <view v-if="n.type=='ol'" class="_ol-bef">{{n.num}}</view>
<view v-else class="_ul-bef"> <view v-else class="_ul-bef">
<view v-if="n.floor%3==0" class="_ul-p1"></view> <view v-if="n.floor%3==0" class="_ul-p1"></view>
...@@ -80,7 +80,7 @@ ...@@ -80,7 +80,7 @@
name: 'trees', name: 'trees',
data() { data() {
return { return {
controls: [], ctrl: [],
placeholder: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="300" height="225"/>', placeholder: 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="300" height="225"/>',
errorImg, errorImg,
loadVideo: typeof plus == 'undefined', loadVideo: typeof plus == 'undefined',
...@@ -124,7 +124,7 @@ ...@@ -124,7 +124,7 @@
if (res.intersectionRatio) { if (res.intersectionRatio) {
for (var j = this.nodes.length; j--;) for (var j = this.nodes.length; j--;)
if (this.nodes[j].name == 'img') if (this.nodes[j].name == 'img')
this.$set(this.controls, j, 1); this.$set(this.ctrl, j, 1);
this.observer.disconnect(); this.observer.disconnect();
} }
}) })
...@@ -184,23 +184,23 @@ ...@@ -184,23 +184,23 @@
}, },
loadImg(e) { loadImg(e) {
var i = e.currentTarget.dataset.i; var i = e.currentTarget.dataset.i;
if (this.lazyLoad && !this.controls[i]) { if (this.lazyLoad && !this.ctrl[i]) {
// #ifdef QUICKAPP-WEBVIEW // #ifdef QUICKAPP-WEBVIEW
this.$set(this.controls, i, 0); this.$set(this.ctrl, i, 0);
this.$nextTick(function() { this.$nextTick(function() {
// #endif // #endif
// #ifndef APP-PLUS // #ifndef APP-PLUS
this.$set(this.controls, i, 1); this.$set(this.ctrl, i, 1);
// #endif // #endif
// #ifdef QUICKAPP-WEBVIEW // #ifdef QUICKAPP-WEBVIEW
}) })
// #endif // #endif
} else if (this.loading && this.controls[i] != 2) { } else if (this.loading && this.ctrl[i] != 2) {
// #ifdef QUICKAPP-WEBVIEW // #ifdef QUICKAPP-WEBVIEW
this.$set(this.controls, i, 0); this.$set(this.ctrl, i, 0);
this.$nextTick(function() { this.$nextTick(function() {
// #endif // #endif
this.$set(this.controls, i, 2); this.$set(this.ctrl, i, 2);
// #ifdef QUICKAPP-WEBVIEW // #ifdef QUICKAPP-WEBVIEW
}) })
// #endif // #endif
...@@ -258,14 +258,14 @@ ...@@ -258,14 +258,14 @@
i = target.dataset.i; i = target.dataset.i;
if (source == 'video' || source == 'audio') { if (source == 'video' || source == 'audio') {
// 加载其他 source // 加载其他 source
var index = this.controls[i] ? this.controls[i].i + 1 : 1; var index = this.ctrl[i] ? this.ctrl[i].i + 1 : 1;
if (index < this.nodes[i].attrs.source.length) if (index < this.nodes[i].attrs.source.length)
this.$set(this.controls, i, index); this.$set(this.ctrl, i, index);
if (e.detail.__args__) if (e.detail.__args__)
e.detail = e.detail.__args__[0]; e.detail = e.detail.__args__[0];
} else if (errorImg && source == 'img') { } else if (errorImg && source == 'img') {
this.top.imgList.setItem(target.dataset.index, errorImg); this.top.imgList.setItem(target.dataset.index, errorImg);
this.$set(this.controls, i, 3); this.$set(this.ctrl, i, 3);
} }
this.top && this.top.$emit('error', { this.top && this.top.$emit('error', {
source, source,
...@@ -274,7 +274,7 @@ ...@@ -274,7 +274,7 @@
}); });
}, },
_loadVideo(e) { _loadVideo(e) {
this.$set(this.controls, e.target.dataset.i, 0); this.$set(this.ctrl, e.target.dataset.i, 0);
} }
} }
} }
...@@ -407,12 +407,13 @@ ...@@ -407,12 +407,13 @@
} }
._ul-bef { ._ul-bef {
display: block;
margin: 0 12px 0 23px; margin: 0 12px 0 23px;
line-height: normal; line-height: normal;
} }
._ol-bef, ._ol-bef,
._ul_bef { ._ul-bef {
flex: none; flex: none;
user-select: none; user-select: none;
} }
......
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
* @event {Function} imgtap 图片点击事件 * @event {Function} imgtap 图片点击事件
* @event {Function} linkpress 链接点击事件 * @event {Function} linkpress 链接点击事件
* @author JinYufeng * @author JinYufeng
* @version 20200719 * @version 20200728
* @listens MIT * @listens MIT
*/ */
export default { export default {
......
...@@ -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;
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
// 形状,square为方形,circle为原型 // 形状,square为方形,circle为原型
shape: { shape: {
type: String, type: String,
default: 'square' default: 'circle'
}, },
// 图标的大小,单位rpx // 图标的大小,单位rpx
iconSize: { iconSize: {
......
...@@ -119,7 +119,7 @@ ...@@ -119,7 +119,7 @@
}, },
iconClass() { iconClass() {
let classes = []; let classes = [];
classes.push('u-radio__icon-wrap--' + this.shape); classes.push('u-radio__icon-wrap--' + this.elShape);
if (this.name == this.parent.value) classes.push('u-radio__icon-wrap--checked'); if (this.name == this.parent.value) classes.push('u-radio__icon-wrap--checked');
if (this.elDisabled) classes.push('u-radio__icon-wrap--disabled'); if (this.elDisabled) classes.push('u-radio__icon-wrap--disabled');
if (this.name == this.parent.value && this.elDisabled) classes.push( if (this.name == this.parent.value && this.elDisabled) classes.push(
......
...@@ -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);
} }
} }
}; };
......
...@@ -8,14 +8,14 @@ ...@@ -8,14 +8,14 @@
}" :class="{ }" :class="{
'u-section--line': showLine 'u-section--line': showLine
}"> }">
<view class="u-section__title__icon-wrap u-flex" :style="[lineStyle]"> <view class="u-section__title__icon-wrap u-flex" :style="[lineStyle]" v-if="showLine">
<u-icon top="0" name="column-line" :size="fontSize * 1.25" bold :color="lineColor ? lineColor : color"></u-icon> <u-icon top="0" name="column-line" :size="fontSize * 1.25" bold :color="lineColor ? lineColor : color"></u-icon>
</view> </view>
<text class="u-flex u-section__title__text">{{title}}</text> <text class="u-flex u-section__title__text">{{title}}</text>
</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>
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
}, },
fontSize: { fontSize: {
type: [Number, String], type: [Number, String],
default: 32 default: 28
}, },
// 主标题是否加粗 // 主标题是否加粗
bold: { bold: {
......
...@@ -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>
......
<template> <template>
<view class="u-switch" :class="[value == true ? 'u-switch--on' : '', disabled ? 'u-switch--disabled' : '']" @tap="onClick" <view class="u-switch" :class="[value == true ? 'u-switch--on' : '', disabled ? 'u-switch--disabled' : '']" @tap="onClick"
:style="[switchStyle]"> :style="[switchStyle]">
<view class="u-switch__node node-class"> <view class="u-switch__node node-class" :style="{
width: $u.addUnit(this.size),
height: $u.addUnit(this.size)
}">
<u-loading :show="loading" class="u-switch__loading" :size="size * 0.6" :color="loadingColor" /> <u-loading :show="loading" class="u-switch__loading" :size="size * 0.6" :color="loadingColor" />
</view> </view>
</view> </view>
...@@ -128,8 +131,6 @@ ...@@ -128,8 +131,6 @@
left: 0; left: 0;
border-radius: 100%; border-radius: 100%;
z-index: 1; z-index: 1;
width: 1em;
height: 1em;
background-color: #fff; background-color: #fff;
background-color: #fff; background-color: #fff;
box-shadow: 0 3px 1px 0 rgba(0, 0, 0, 0.05), 0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 3px 3px 0 rgba(0, 0, 0, 0.05); box-shadow: 0 3px 1px 0 rgba(0, 0, 0, 0.05), 0 2px 2px 0 rgba(0, 0, 0, 0.1), 0 3px 3px 0 rgba(0, 0, 0, 0.05);
......
...@@ -127,7 +127,7 @@ ...@@ -127,7 +127,7 @@
}, },
created() { created() {
// 是否隐藏原生tabbar // 是否隐藏原生tabbar
if(this.borderTop) uni.hideTabBar(); if(this.hideTabBar) uni.hideTabBar();
// 获取引入了u-tabbar页面的路由地址,该地址没有路径前面的"/" // 获取引入了u-tabbar页面的路由地址,该地址没有路径前面的"/"
let pages = getCurrentPages(); let pages = getCurrentPages();
// 页面栈中的最后一个即为项为当前页面,route属性为页面路径 // 页面栈中的最后一个即为项为当前页面,route属性为页面路径
...@@ -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-28 // 此版本发布于2020-08-04
let version = '1.5.6'; 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.6", "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