Commit c055a916 authored by 程新智's avatar 程新智 👽

initjd

parent 592341de
Pipeline #150 canceled with stages
No preview for this file type
<script>
export default {
onLaunch: function() {
uni.hideTabBar()
}
}
</script>
<style lang='scss'>
@import 'common/css/iconfont.css';
@import "common/uview-ui/index.scss";
/*每个页面公共css */
.content {
width: 100%;
height: 100vh;
box-sizing: border-box;
}
uni-page-body {
width: 100%;
height: 100%;
background: #f9f9f9;
}
</style>
This diff is collapsed.
<template>
<view class="u-checkbox-group u-clearfix">
<slot></slot>
</view>
</template>
<script>
import Emitter from "../js/emitter.js";
/**
* checkboxGroup 开关选择器父组件Group
* @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
* @tutorial https://www.uviewui.com/components/checkbox.html
* @property {String Number} max 最多能选中多少个checkbox(默认999)
* @property {String Number} size 组件整体的大小,单位rpx(默认40)
* @property {Boolean} disabled 是否禁用所有checkbox(默认false)
* @property {String Number} icon-size 图标大小,单位rpx(默认20)
* @property {Boolean} label-disabled 是否禁止点击文本操作checkbox(默认false)
* @property {String} width 宽度,需带单位
* @property {String} width 宽度,需带单位
* @property {String} shape 外观形状,shape-方形,circle-圆形(默认circle)
* @property {Boolean} wrap 是否每个checkbox都换行(默认false)
* @property {String} active-color 选中时的颜色,应用到所有子Checkbox组件(默认#2979ff)
* @event {Function} change 任一个checkbox状态发生变化时触发,回调为一个对象
* @example <u-checkbox-group></u-checkbox-group>
*/
export default {
name: "u-checkbox-group",
mixins: [Emitter],
props: {
// 最多能选中多少个checkbox
max: {
type: [Number, String],
default: 999,
},
// 所有选中项的 name
// value: {
// default: Array,
// default() {
// return []
// }
// },
// 是否禁用所有复选框
disabled: {
type: Boolean,
default: false,
},
// 在表单内提交时的标识符
name: {
type: [Boolean, String],
default: "",
},
// 是否禁止点击提示语选中复选框
labelDisabled: {
type: Boolean,
default: false,
},
// 形状,square为方形,circle为原型
shape: {
type: String,
default: "square",
},
// 选中状态下的颜色
activeColor: {
type: String,
default: "#2979ff",
},
// 组件的整体大小
size: {
type: [String, Number],
default: 34,
},
// 每个checkbox占u-checkbox-group的宽度
width: {
type: String,
default: "auto",
},
// 是否每个checkbox都换行
wrap: {
type: Boolean,
default: false,
},
// 图标的大小,单位rpx
iconSize: {
type: [String, Number],
default: 20,
},
//zy封装 当前索引 用于动态表单
currentIndex: {
type: Number,
default: "",
},
},
data() {
return {};
},
created() {
// 如果将children定义在data中,在微信小程序会造成循环引用而报错
this.children = [];
},
methods: {
emitEvent() {
let values = [];
this.children.map((val) => {
if (val.value) values.push(val.name);
});
this.currentIndex!=='' ? this.$emit("change", { currentIndex: this.currentIndex, values }) : this.$emit("change", values);
// 发出事件,用于在表单组件中嵌入checkbox的情况,进行验证
// 由于头条小程序执行迟钝,故需要用几十毫秒的延时
setTimeout(() => {
// 将当前的值发送到 u-form-item 进行校验
this.dispatch("u-form-item", "on-form-change", values);
}, 60);
},
},
};
</script>
<style lang="scss" scoped>
@import "../css/components.scss";
.u-checkbox-group {
/* #ifndef MP || APP-NVUE */
display: inline-flex;
flex-wrap: wrap;
/* #endif */
}
</style>
<template>
<view class="u-checkbox" :style="[checkboxStyle]">
<view class="u-checkbox__icon-wrap" @tap="toggle" :class="[iconClass]" :style="[iconStyle]">
<!-- <u-icon class="u-checkbox__icon-wrap__icon" name="checkbox-mark" :size="checkboxIconSize" :color="iconColor"/> -->
<text class="saasIcon" :style="{fontSize:'20rpx'}">&#xe650;</text>
</view>
<view class="u-checkbox__label" @tap="onClickLabel" :style="{
fontSize: $f.addUnit(labelSize)
}">
<slot />
</view>
</view>
</template>
<script>
/**
* checkbox 复选框
* @description 该组件需要搭配checkboxGroup组件使用,以便用户进行操作时,获得当前复选框组的选中情况。
* @tutorial https://www.uviewui.com/components/checkbox.html
* @property {String Number} icon-size 图标大小,单位rpx(默认20)
* @property {String Number} label-size label字体大小,单位rpx(默认28)
* @property {String Number} name checkbox组件的标示符
* @property {String} shape 形状,见官网说明(默认circle)
* @property {Boolean} disabled 是否禁用
* @property {Boolean} label-disabled 是否禁止点击文本操作checkbox
* @property {String} active-color 选中时的颜色,如设置CheckboxGroup的active-color将失效
* @event {Function} change 某个checkbox状态发生变化时触发,回调为一个对象
* @example <u-checkbox v-model="checked" :disabled="false">天涯</u-checkbox>
*/
export default {
name: "u-checkbox",
props: {
// checkbox的名称
name: {
type: [String, Number],
default: ''
},
// 形状,square为方形,circle为原型
shape: {
type: String,
default: ''
},
// 是否为选中状态
value: {
type: Boolean,
default: false
},
// 是否禁用
disabled: {
type: [String, Boolean],
default: ''
},
// 是否禁止点击提示语选中复选框
labelDisabled: {
type: [String, Boolean],
default: ''
},
// 选中状态下的颜色,如设置此值,将会覆盖checkboxGroup的activeColor值
activeColor: {
type: String,
default: ''
},
// 图标的大小,单位rpx
iconSize: {
type: [String, Number],
default: '20rpx'
},
// label的字体大小,rpx单位
labelSize: {
type: [String, Number],
default: ''
},
// 组件的整体大小
size: {
type: [String, Number],
default: ''
},
},
data() {
return {
parentDisabled: false,
newParams: {},
};
},
created() {
// 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环应用
this.parent = this.$f.$parent.call(this, 'u-checkbox-group');
// 如果存在u-checkbox-group,将本组件的this塞进父组件的children中
this.parent && this.parent.children.push(this);
},
computed: {
// 是否禁用,如果父组件u-checkbox-group禁用的话,将会忽略子组件的配置
isDisabled() {
return this.disabled !== '' ? this.disabled : this.parent ? this.parent.disabled : false;
},
// 是否禁用label点击
isLabelDisabled() {
return this.labelDisabled !== '' ? this.labelDisabled : this.parent ? this.parent.labelDisabled : false;
},
// 组件尺寸,对应size的值,默认值为34rpx
checkboxSize() {
return this.size ? this.size : (this.parent ? this.parent.size : 34);
},
// 组件的勾选图标的尺寸,默认20
checkboxIconSize() {
return this.iconSize ? this.iconSize : (this.parent ? this.parent.iconSize : 20);
},
// 组件选中激活时的颜色
elActiveColor() {
return this.activeColor ? this.activeColor : (this.parent ? this.parent.activeColor : 'primary');
},
// 组件的形状
elShape() {
return this.shape ? this.shape : (this.parent ? this.parent.shape : 'square');
},
iconStyle() {
let style = {};
// 既要判断是否手动禁用,还要判断用户v-model绑定的值,如果绑定为false,那么也无法选中
if (this.elActiveColor && this.value && !this.isDisabled) {
style.borderColor = this.elActiveColor;
style.backgroundColor = this.elActiveColor;
}
style.width = this.$f.addUnit(this.checkboxSize);
style.height = this.$f.addUnit(this.checkboxSize);
return style;
},
// checkbox内部的勾选图标,如果选中状态,为白色,否则为透明色即可
iconColor() {
return this.value ? '#ffffff' : 'transparent';
},
iconClass() {
let classes = [];
classes.push('u-checkbox__icon-wrap--' + this.elShape);
if (this.value == true) classes.push('u-checkbox__icon-wrap--checked');
if (this.isDisabled) classes.push('u-checkbox__icon-wrap--disabled');
if (this.value && this.isDisabled) classes.push('u-checkbox__icon-wrap--disabled--checked');
// 支付宝小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
return classes.join(' ');
},
checkboxStyle() {
let style = {};
if(this.parent && this.parent.width) {
style.width = this.parent.width;
// #ifdef MP
// 各家小程序因为它们特殊的编译结构,使用float布局
style.float = 'left';
// #endif
// #ifndef MP
// H5和APP使用flex布局
style.flex = `0 0 ${this.parent.width}`;
// #endif
}
if(this.parent && this.parent.wrap) {
style.width = '100%';
// #ifndef MP
// H5和APP使用flex布局,将宽度设置100%,即可自动换行
style.flex = '0 0 100%';
// #endif
}
return style;
}
},
methods: {
onClickLabel() {
if (!this.isLabelDisabled && !this.isDisabled) {
this.setValue();
}
},
toggle() {
if (!this.isDisabled) {
this.setValue();
}
},
emitEvent() {
this.$emit('change', {
value: !this.value,
name: this.name
})
// 执行父组件u-checkbox-group的事件方法
// 等待下一个周期再执行,因为this.$emit('input')作用于父组件,再反馈到子组件内部,需要时间
setTimeout(() => {
if(this.parent && this.parent.emitEvent) this.parent.emitEvent();
}, 80);
},
// 设置input的值,这里通过input事件,设置通过v-model绑定的组件的值
setValue() {
// 判断是否超过了可选的最大数量
let checkedNum = 0;
if(this.parent && this.parent.children) {
// 只要父组件的某一个子元素的value为true,就加1(已有的选中数量)
this.parent.children.map(val => {
if (val.value) checkedNum++;
})
}
// 如果原来为选中状态,那么可以取消
if (this.value == true) {
this.emitEvent();
this.$emit('input', !this.value);
} else {
// 如果超出最多可选项,提示
if(this.parent && checkedNum >= this.parent.max) {
return this.$f.toast(`最多可选${this.parent.max}项`);
}
// 如果原来为未选中状态,需要选中的数量少于父组件中设置的max值,才可以选中
this.emitEvent();
this.$emit('input', !this.value);
}
}
}
};
</script>
<style lang="scss" scoped>
@import "../css/components.scss";
.u-checkbox {
/* #ifndef APP-NVUE */
display: inline-flex;
/* #endif */
align-items: center;
overflow: hidden;
user-select: none;
line-height: 1.8;
&__icon-wrap {
color: $u-content-color;
flex: none;
display: -webkit-flex;
@include vue-flex;
align-items: center;
justify-content: center;
box-sizing: border-box;
width: 42rpx;
height: 42rpx;
color: transparent;
text-align: center;
transition-property: color, border-color, background-color;
font-size: 20px;
border: 1px solid #c8c9cc;
transition-duration: 0.2s;
/* #ifdef MP-TOUTIAO */
// 头条小程序兼容性问题,需要设置行高为0,否则图标偏下
&__icon {
line-height: 0;
}
/* #endif */
&--circle {
border-radius: 100%;
}
&--square {
border-radius: 6rpx;
}
&--checked {
color: #fff;
background-color: $u-type-primary;
border-color: $u-type-primary;
}
&--disabled {
background-color: #ebedf0;
border-color: #c8c9cc;
}
&--disabled--checked {
color: #c8c9cc !important;
}
}
&__label {
word-wrap: break-word;
margin-left: 10rpx;
margin-right: 24rpx;
color: $u-content-color;
font-size: 30rpx;
&--disabled {
color: #c8c9cc;
}
}
}
</style>
This diff is collapsed.
<template>
<view class="u-radio-group u-clearfix">
<slot></slot>
</view>
</template>
<script>
import Emitter from "../js/emitter.js";
/**
* radioRroup 单选框父组件
* @description 单选框用于有一个选择,用户只能选择其中一个的场景。搭配u-radio使用
* @tutorial https://www.uviewui.com/components/radio.html
* @property {Boolean} disabled 是否禁用所有radio(默认false)
* @property {String Number} size 组件整体的大小,单位rpx(默认40)
* @property {String} active-color 选中时的颜色,应用到所有子Radio组件(默认#2979ff)
* @property {String Number} icon-size 图标大小,单位rpx(默认20)
* @property {String} shape 外观形状,shape-方形,circle-圆形(默认circle)
* @property {Boolean} label-disabled 是否禁止点击文本操作checkbox(默认false)
* @property {String} width 宽度,需带单位
* @property {Boolean} wrap 是否每个radio都换行(默认false)
* @event {Function} change 任一个radio状态发生变化时触发
* @example <u-radio-group v-model="value"></u-radio-group>
*/
export default {
name: "u-radio-group",
mixins: [Emitter],
props: {
// 是否禁用所有单选框
disabled: {
type: Boolean,
default: false,
},
// 匹配某一个radio组件,如果某个radio的name值等于此值,那么这个radio就被会选中
value: {
type: [String, Number],
default: "",
},
// 选中状态下的颜色
activeColor: {
type: String,
default: "#2979ff",
},
// 组件的整体大小
size: {
type: [String, Number],
default: 34,
},
// 是否禁止点击提示语选中复选框
labelDisabled: {
type: Boolean,
default: false,
},
// 形状,square为方形,circle为原型
shape: {
type: String,
default: "circle",
},
// 图标的大小,单位rpx
iconSize: {
type: [String, Number],
default: 20,
},
// 每个checkbox占u-checkbox-group的宽度
width: {
type: [String, Number],
default: "auto",
},
// 是否每个checkbox都换行
wrap: {
type: Boolean,
default: false,
},
//zy封装 当前索引 用于动态表单
currentIndex: {
type: Number,
default: "",
},
},
created() {
// 如果将children定义在data中,在微信小程序会造成循环引用而报错
this.children = [];
},
watch: {
// 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件
parentData() {
if (this.children.length) {
this.children.map((child) => {
// 判断子组件(u-radio)如果有updateParentData方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
typeof child.updateParentData == "function" && child.updateParentData();
});
}
},
},
computed: {
// 这里computed的变量,都是子组件u-radio需要用到的,由于头条小程序的兼容性差异,子组件无法实时监听父组件参数的变化
// 所以需要手动通知子组件,这里返回一个parentData变量,供watch监听,在其中去通知每一个子组件重新从父组件(u-radio-group)
// 拉取父组件新的变化后的参数
parentData() {
return [this.value, this.disabled, this.activeColor, this.size, this.labelDisabled, this.shape, this.iconSize, this.width, this.wrap];
},
},
methods: {
// 该方法有子组件radio调用,当一个radio被选中的时候,给父组件设置value值(props传递的value)
setValue(val) {
// 通过子组件传递过来的val值(此被选中的子组件内部已将parentValue设置等于val的值),将其他
// u-radio设置未选中的状态
this.children.map((child) => {
if (child.parentData.value != val) child.parentData.value = "";
});
// 通过emit事件,设置父组件通过v-model双向绑定的值
this.$emit("input", val);
this.currentIndex!=='' ? this.$emit("change", { currentIndex: this.currentIndex, val }) : this.$emit("change", val);
// 等待下一个周期再执行,因为this.$emit('input')作用于父组件,再反馈到子组件内部,需要时间
// 由于头条小程序执行迟钝,故需要用几十毫秒的延时
setTimeout(() => {
// 将当前的值发送到 u-form-item 进行校验
this.dispatch("u-form-item", "on-form-change", val);
}, 60);
},
},
};
</script>
<style lang="scss" scoped>
@import "../css/components.scss";
.u-radio-group {
/* #ifndef MP || APP-NVUE */
display: inline-flex;
flex-wrap: wrap;
/* #endif */
}
</style>
<template>
<view class="u-radio" :style="[radioStyle]">
<view class="u-radio__icon-wrap" @tap="toggle" :class="[iconClass]" :style="[iconStyle]">
<text class="saasIcon" :style="{fontSize:'20rpx'}"> &#xe650;</text>
</view>
<view class="u-radio__label" @tap="onClickLabel" :style="{
fontSize: $f.addUnit(labelSize)
}">
<slot />
</view>
</view>
</template>
<script>
/**
* radio 单选框
* @description 单选框用于有一个选择,用户只能选择其中一个的场景。搭配u-radio-group使用
* @tutorial https://www.uviewui.com/components/radio.html
* @property {String Number} icon-size 图标大小,单位rpx(默认24)
* @property {String Number} label-size label字体大小,单位rpx(默认28)
* @property {String Number} name radio组件的标示符
* @property {String} shape 形状,见上方说明(默认circle)
* @property {Boolean} disabled 是否禁用(默认false)
* @property {Boolean} label-disabled 点击文本是否可以操作radio(默认true)
* @property {String} active-color 选中时的颜色,如设置parent的active-color将失效
* @event {Function} change 某个radio状态发生变化时触发(选中状态)
* @example <u-radio :label-disabled="false">门掩黄昏,无计留春住</u-radio>
*/
export default {
name: "u-radio",
props: {
// radio的名称
name: {
type: [String, Number],
default: ''
},
// 形状,square为方形,circle为原型
shape: {
type: String,
default: ''
},
// 是否禁用
disabled: {
type: [String, Boolean],
default: ''
},
// 是否禁止点击提示语选中复选框
labelDisabled: {
type: [String, Boolean],
default: ''
},
// 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
activeColor: {
type: String,
default: ''
},
// 图标的大小,单位rpx
iconSize: {
type: [String, Number],
default: ''
},
// label的字体大小,rpx单位
labelSize: {
type: [String, Number],
default: ''
},
},
data() {
return {
// 父组件的默认值,因为头条小程序不支持在computed中使用this.parent.shape的形式
// 故只能使用如此方法
parentData: {
iconSize: null,
labelDisabled: null,
disabled: null,
shape: null,
activeColor: null,
size: null,
width: null,
height: null,
value: null,
wrap: null
}
};
},
created() {
this.parent = false;
// 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环引用
this.updateParentData();
this.parent.children.push(this);
},
computed: {
// 是否禁用,如果父组件u-raios-group禁用的话,将会忽略子组件的配置
elDisabled() {
return this.disabled !== '' ? this.disabled : this.parentData.disabled !== null ? this.parentData.disabled : false;
},
// 是否禁用label点击
elLabelDisabled() {
return this.labelDisabled !== '' ? this.labelDisabled : this.parentData.labelDisabled !== null ? this.parentData.labelDisabled : false;
},
// 组件尺寸,对应size的值,默认值为34rpx
elSize() {
return this.size ? this.size : (this.parentData.size ? this.parentData.size : 34);
},
// 组件的勾选图标的尺寸,默认20
elIconSize() {
return this.iconSize ? this.iconSize : (this.parentData.iconSize ? this.parentData.iconSize : 20);
},
// 组件选中激活时的颜色
elActiveColor() {
return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : 'primary');
},
// 组件的形状
elShape() {
return this.shape ? this.shape : (this.parentData.shape ? this.parentData.shape : 'circle');
},
// 设置radio的状态,要求radio的name等于parent的value时才为选中状态
iconStyle() {
let style = {};
if (this.elActiveColor && this.parentData.value == this.name && !this.elDisabled) {
style.borderColor = this.elActiveColor;
style.backgroundColor = this.elActiveColor;
}
style.width = this.$f.addUnit(this.elSize);
style.height = this.$f.addUnit(this.elSize);
return style;
},
iconColor() {
return this.name == this.parentData.value ? '#ffffff' : 'transparent';
},
iconClass() {
let classes = [];
classes.push('u-radio__icon-wrap--' + this.elShape);
if (this.name == this.parentData.value) classes.push('u-radio__icon-wrap--checked');
if (this.elDisabled) classes.push('u-radio__icon-wrap--disabled');
if (this.name == this.parentData.value && this.elDisabled) classes.push(
'u-radio__icon-wrap--disabled--checked');
// 支付宝小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
return classes.join(' ');
},
radioStyle() {
let style = {};
if (this.parentData.width) {
style.width = this.$f.addUnit(this.parentData.width);
// #ifdef MP
// 各家小程序因为它们特殊的编译结构,使用float布局
style.float = 'left';
// #endif
// #ifndef MP
// H5和APP使用flex布局
style.flex = `0 0 ${this.$f.addUnit(this.parentData.width)}`;
// #endif
}
if (this.parentData.wrap) {
style.width = '100%';
// #ifndef MP
// H5和APP使用flex布局,将宽度设置100%,即可自动换行
style.flex = '0 0 100%';
// #endif
}
return style;
}
},
methods: {
getParentData(parentName = '') {
// 避免在created中去定义parent变量
if(!this.parent) this.parent = false;
// 这里的本质原理是,通过获取父组件实例(也即u-radio-group的this)
// 将父组件this中对应的参数,赋值给本组件(u-radio的this)的parentData对象中对应的属性
// 之所以需要这么做,是因为所有端中,头条小程序不支持通过this.parent.xxx去监听父组件参数的变化
this.parent = this.$f.$parent.call(this, parentName);
if(this.parent) {
// 历遍parentData中的属性,将parent中的同名属性赋值给parentData
Object.keys(this.parentData).map(key => {
this.parentData[key] = this.parent[key];
});
}
},
updateParentData() {
this.getParentData('u-radio-group');
},
onClickLabel() {
if (!this.elLabelDisabled && !this.elDisabled) {
this.setRadioCheckedStatus();
}
},
toggle() {
if (!this.elDisabled) {
this.setRadioCheckedStatus();
}
},
emitEvent() {
// u-radio的name不等于父组件的v-model的值时(意味着未选中),才发出事件,避免多次点击触发事件
if(this.parentData.value != this.name) this.$emit('change', this.name);
},
// 改变组件选中状态
// 这里的改变的依据是,更改本组件的parentData.value值为本组件的name值,同时通过父组件遍历所有u-radio实例
// 将本组件外的其他u-radio的parentData.value都设置为空(由computed计算后,都被取消选中状态),因而只剩下一个为选中状态
setRadioCheckedStatus() {
this.emitEvent();
if(this.parent) {
this.parent.setValue(this.name);
this.parentData.value = this.name;
}
}
}
};
</script>
<style lang="scss" scoped>
@import "../css/components.scss";
.u-radio {
/* #ifndef APP-NVUE */
display: inline-flex;
/* #endif */
align-items: center;
overflow: hidden;
user-select: none;
line-height: 1.8;
&__icon-wrap {
color: $u-content-color;
@include vue-flex;
flex: none;
align-items: center;
justify-content: center;
box-sizing: border-box;
width: 42rpx;
height: 42rpx;
color: transparent;
text-align: center;
transition-property: color, border-color, background-color;
font-size: 20px;
border: 1px solid #c8c9cc;
transition-duration: 0.2s;
/* #ifdef MP-TOUTIAO */
// 头条小程序兼容性问题,需要设置行高为0,否则图标偏下
&__icon {
line-height: 0;
}
/* #endif */
&--circle {
border-radius: 100%;
}
&--square {
border-radius: 3px;
}
&--checked {
color: #fff;
background-color: #2979ff;
border-color: #2979ff;
}
&--disabled {
background-color: #ebedf0;
border-color: #c8c9cc;
}
&--disabled--checked {
color: #c8c9cc !important;
}
}
&__label {
word-wrap: break-word;
margin-left: 10rpx;
margin-right: 24rpx;
color: $u-content-color;
font-size: 30rpx;
&--disabled {
color: #c8c9cc;
}
}
}
</style>
This diff is collapsed.
// 定义混入指令,用于在非nvue环境下的flex定义,因为nvue没有display属性,会报错
@mixin vue-flex($direction: row) {
/* #ifndef APP-NVUE */
display: flex;
flex-direction: $direction;
/* #endif */
}
@font-face {
font-family: "iconfont";
/* Project id 2729410 */
src: url("//at.alicdn.com/t/font_2729410_7iehgf1epc.woff2?t=1628411186356") format("woff2"), url("//at.alicdn.com/t/font_2729410_7iehgf1epc.woff?t=1628411186356") format("woff"), url("//at.alicdn.com/t/font_2729410_7iehgf1epc.ttf?t=1628411186356") format("truetype");
}
.saasIcon {
font-family: "iconfont" !important;
font-style: normal;
-webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px;
-moz-osx-font-smoothing: grayscale;
}
// 此文件为uView的主题变量,这些变量目前只能通过uni.scss引入才有效,另外由于
// uni.scss中引入的样式会同时混入到全局样式文件和单独每一个页面的样式中,造成微信程序包太大,
// 故uni.scss只建议放scss变量名相关样式,其他的样式可以通过main.js或者App.vue引入
$u-main-color: #303133;
$u-content-color: #606266;
$u-tips-color: #909399;
$u-light-color: #c0c4cc;
$u-border-color: #e4e7ed;
$u-bg-color: #f3f4f6;
$u-type-primary: #2979ff;
$u-type-primary-light: #ecf5ff;
$u-type-primary-disabled: #a0cfff;
$u-type-primary-dark: #2b85e4;
$u-type-warning: #ff9900;
$u-type-warning-disabled: #fcbd71;
$u-type-warning-dark: #f29100;
$u-type-warning-light: #fdf6ec;
$u-type-success: #19be6b;
$u-type-success-disabled: #71d5a1;
$u-type-success-dark: #18b566;
$u-type-success-light: #dbf1e1;
$u-type-error: #fa3534;
$u-type-error-disabled: #fab6b6;
$u-type-error-dark: #dd6161;
$u-type-error-light: #fef0f0;
$u-type-info: #909399;
$u-type-info-disabled: #c8c9cc;
$u-type-info-dark: #82848a;
$u-type-info-light: #f4f4f5;
$u-form-item-height: 70rpx;
$u-form-item-border-color: #dcdfe6;
\ No newline at end of file
## 导入即用 全端支持
### 有问题 + wx : zy597172583 标注来意 可评论 看到及时回复
1.使用方式
```javascript
<template>
<filter-popup :data="filterData" :form.sync="filterForm" v-model="popup.filter" title="全部筛选" height="1104rpx" @finsh="subFinsh"></filter-popup>
</template>
<script>
import FilterPopup from "@/components/filter-popup/filter-popup";
export default {
components: {
FilterPopup,
},
data() {
return {
//筛选表单数据
filterData: [
{
children: false,//是否有子项
title: "意向度",
key: "intention_type", //键名 接收对象名字
keyValue: "value", //获取的值是哪个
isRadio: true, //是否单选 否则多选
data: [
{
title: "一般意向",
id: 1,
value: 1,
},
{
title: "中意向度",
id: 2,
value: 2,
},
{
title: "高意向度",
id: 3,
value: 3,
},
],
},
{
children: false,//是否有子项
title: "手机号码",
key: "is_bind_phone", //键名 接收对象名字
keyValue: "value", //获取的值是哪个
isRadio: true, //是否单选 否则多选
data: [
{
title: "未绑定",
value: 0,
},
{
title: "已绑定",
value: 1,
},
],
},
{
children: false,//是否有子项
title: "企微好友",
key: "is_work_customer", //键名 接收对象名字
keyValue: "value", //获取的值是哪个
isRadio: true, //是否单选 否则多选
data: [
{
title: "未添加",
value: 0,
},
{
title: "已添加",
value: 1,
},
],
},
{
children: true,//是否有子项
isRadio: false, //是否单选
title: "标签内容",
key: "label", //键名 接收对象名字
keyValue: "id", //获取的值是哪个
data: [
{
title: "客户重要程度",
id: 22,
children: [
{
title: "一般意向2",
id: 32,
value: 1,
},
{
title: "一般意向3",
id: 12,
value: 1,
},
],
},
{
title: "客户重要程度2",
id: 122,
children: [
{
title: "一般意向2",
id: 43,
value: 1,
},
{
title: "一般意向3",
id: 23,
value: 1,
},
],
},
],
},
], //筛选数据
filterForm: {}, //选中的表单
};
},
}
```
2.组件props
| 参数名 | 类型 | 介绍 |
| ---------- | ------- | ------------------------------------------------- |
| form | Object | .sync双向绑定的表单值 , 可传入显示初始哪些被选中 |
| data | Array | 动态渲染选项的数据数组 |
| title | String | 标题 |
| height | String | 弹出层高度 单位 rpx px upx 百分比 vw等 |
| themeColor | String | 组件主体颜色 默认:\#0066ff |
| mask | Boolean | 是否显示弹出遮盖层 |
3.data 参数
| 参数名 | 类型 | 是否必填 | 介绍 |
| -------- | ------- | -------- | ------------------------------------------------------------ |
| children | Boolean | 是 | 是否有子项 |
| data | Array | 是 | 渲染出来的选项数据 |
| isRadio | Boolean | 是 | 是否单选 单个选项指定,单选还是多选 |
| title | String | 是 | 标签内容标题 |
| key | String | 是 | 接收对象名字 会作为@finsh返回对象的键名 |
| keyValue | String | 是 | 获取的值是哪个 自定义指定获取哪个键值 value还是id或者自己定义的 |
4.事件
| 事件名 | 返回参数 | 简介 |
| ------ | -------- | ----------------------------------------- |
| finsh | Object | 点击确定时触发 返回参数为选中值的对象数组 |
| close | 无 | 组件点击关闭时触发 |
![image-20210730095456900](https://yzhsaas-cdn.qietongvip.com/asd.png)
/**
* 递归使用 call 方式this指向
* @param componentName // 需要找的组件的名称
* @param eventName // 事件名称
* @param params // 需要传递的参数
*/
function broadcast(componentName, eventName, params) {
// 循环子节点找到名称一样的子节点 否则 递归 当前子节点
this.$children.map(child=>{
if (componentName===child.$options.name) {
child.$emit.apply(child,[eventName].concat(params))
}else {
broadcast.apply(child,[componentName,eventName].concat(params))
}
})
}
export default {
methods: {
/**
* 派发 (向上查找) (一个)
* @param componentName // 需要找的组件的名称
* @param eventName // 事件名称
* @param params // 需要传递的参数
*/
dispatch(componentName, eventName, params) {
let parent = this.$parent || this.$root;//$parent 找到最近的父节点 $root 根节点
let name = parent.$options.name; // 获取当前组件实例的name
// 如果当前有节点 && 当前没名称 且 当前名称等于需要传进来的名称的时候就去查找当前的节点
// 循环出当前名称的一样的组件实例
while (parent && (!name||name!==componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.name;
}
}
// 有节点表示当前找到了name一样的实例
if (parent) {
parent.$emit.apply(parent,[eventName].concat(params))
}
},
/**
* 广播 (向下查找) (广播多个)
* @param componentName // 需要找的组件的名称
* @param eventName // 事件名称
* @param params // 需要传递的参数
*/
broadcast(componentName, eventName, params) {
broadcast.call(this,componentName, eventName, params)
}
}
}
/*
* @Author: your name
* @Date: 2021-07-16 14:09:22
* @LastEditTime: 2021-08-08 16:34:04
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \saas\components\activeForm\js\verification.js
*/
// import Vrules from "./vregular.js"; //正则验证
let verification = {};
verification.install = function(Vue) {
//校验
Vue.prototype.$vervify = function(formData) {
formData.forEach((item) => {
if (item.rules.verify) {
switch (item.type) {
case "checkbox":
if (item.rules.value.length == 0) {
uni.showToast({
title: item.rules.errMess || "请选择" + item.label,
duration: 2000,
icon: "none",
});
throw Error(); //终止函数
}
break;
case "phone":
if (!item.rules.value) {
uni.showToast({
title: "手机号不能为空",
duration: 2000,
icon: "none",
});
throw Error(); //终止函数
}
if (!/^\s{0}$|^1\d{10}$/.test(item.rules.value)) {
uni.showToast({
title: "手机格式错误",
duration: 2000,
icon: "none",
});
throw Error(); //终止函数
}
break;
default:
if (!item.rules.value) {
uni.showToast({
title: item.rules.errMess || item.label + "不能为空",
duration: 2000,
icon: "none",
});
throw Error(); //终止函数
}
break;
}
}
});
};
// 提交序列化的表单
Vue.prototype.$submitForm = function(formData) {
console.log("formData :>> ", formData);
let submitData = {};
for (let i = 0; i < formData.length; i++) {
submitData[formData[i].rules.name] = formData[i].rules.value;
}
return submitData;
};
//自定义方法
Vue.prototype.$f = {
zIndex: {
toast: 10090,
noNetwork: 10080,
// popup包含popup,actionsheet,keyboard,picker的值
popup: 10075,
mask: 10070,
navbar: 980,
topTips: 975,
sticky: 970,
indexListSticky: 965,
},
$parent(name = undefined) {
let parent = this.$parent;
// 通过while历遍,这里主要是为了H5需要多层解析的问题
while (parent) {
// 父组件
if (parent.$options && parent.$options.name !== name) {
// 如果组件的name不相等,继续上一级寻找
parent = parent.$parent;
} else {
return parent;
}
}
return false;
},
addUnit(value = "auto", unit = "rpx") {
/**
* 验证十进制数字
*/
function number(value) {
return /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value);
}
value = String(value);
// 用uView内置验证规则中的number判断是否为数值
return number(value) ? `${value}${unit}` : value;
},
// 判断arr是否为一个数组,返回一个bool值
isArray(arr) {
return Object.prototype.toString.call(arr) === "[object Array]";
},
deepClone(obj) {
// 对常见的“非”值,直接返回原来值
if ([null, undefined, NaN, false].includes(obj)) return obj;
if (typeof obj !== "object" && typeof obj !== "function") {
//原始类型直接返回
return obj;
}
var o = this.isArray(obj) ? [] : {};
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
o[i] = typeof obj[i] === "object" ? this.deepClone(obj[i]) : obj[i];
}
}
return o;
},
toast(title, duration = 1500, isSuccess) {
isSuccess
?
(uni.showToast({
title: title,
icon: "success",
duration: duration,
})) :
(uni.showToast({
title: title,
icon: "none",
duration: duration,
}))
},
};
};
export default verification;
\ No newline at end of file
var Vregular = {
// 验证自然数
naturalNumber: /^(([0-9]*[1-9][0-9]*)|(0+))$/,
// 0到20位的英文字符和数字
enNum0to20: /^[a-z0-9A-Z]{0,20}$/,
// 2到100位的中英文字符和空格
cnEnSpace2to100: /^[a-zA-Z\u4E00-\u9FA5\s*]{2,100}$/,
// 数字和换行符
numLinefeed: /^[0-9\n*]+$/,
// 255位以内的字符
char0to255: /^.{0,255}$/,
// 英文
english: /^.[A-Za-z]+$/,
// 座机
telephone: /^\d{3}-\d{7,8}|\d{4}-\d{7,8}$/,
// 证件号码
IDNumber: /^[a-z0-9A-Z]{0,50}$/,
// 身份证号码,包括15位和18位的
IDCard: /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{7}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)/,
// QQ号码
qq: /^[1-9]\d{4,11}$/,
//邮箱
email:/^\s{0}$|^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/,
//电话号码
phone:/^\s{0}$|^1\d{10}$/,
// 验证6位数字
num6:/^\s{0}$|^[0-9]{6}$/,
// 支付宝账号
AlipayAccount:/^\s{0}$|^(?:\w+\.?)*\w+@(?:\w+\.)+\w+|^1\d{10}$/,
//姓名,2-20个汉字,中间允许包含一个“.”
realName:/^\s{0}$|^[\u4E00-\u9FA5]+[]{0,1}[\u4E00-\u9FA5]+$/,
//验证用户名,4到16位(字母,数字,下划线,第一位必须是字母)
userName:/^\s{0}$|^[a-zA-Z][a-zA-Z0-9_]{3,15}$/,
// 银行卡号码
bankCard:/^\s{0}$|^(\d{15}|\d{16}|\d{19})$/,
// 网址, 仅支持http和https开头的
URL: /^(http|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-.,@?^=%&:/~+#]*[\w\-@?^=%&/~+#])?$/,
//正整数
positiveInteger:/^\s{0}$|^-?(([1-9]\d*)|(0))$/,
//数字类型
numberType:/^-?[0-9]+(\.\d+)?$/,
// 不为空
noEmpty:/\S/,
//pwd:/\/ 至少8-16个字符,至少1个大写字母,1个小写字母和1个数字,其他可以是任意字符:
pwd:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,20}$/
}
var Vrules={
phone:{pattern: Vregular.phone, errMess: '请输入正确的手机号码'},
number:{pattern: Vregular.numberType, errMess: '请输入正确的数字'},
telephone: {pattern: Vregular.telephone, errMess: "请输入正确的座机号码",},
email: {pattern: Vregular.email, errMess: '请输入正确的邮箱'},
idcard: {pattern: Vregular.IDCard, errMess: '请输入正确的证件号码'},
bankCard: {pattern: Vregular.bankCard, errMess: '请输入正确的银行卡号码'},
qq: {pattern: Vregular.qq, errMess: '请输入正确的qq号码'},
num6:{pattern: Vregular.num6, errMess: '请输入正确的6位数字'},
AlipayAccount:{pattern: Vregular.AlipayAccount, errMess: '请输入正确的支付宝账号'},
realName:{pattern: Vregular.realName, errMess: '请输入正确的真实姓名'},
userName:{pattern: Vregular.userName, errMess: '请输入正确的用户名'},
URL:{pattern: Vregular.URL, errMess: '请输入正确的url'},
positiveInteger:{pattern: Vregular.positiveInteger, errMess: '请输入正确的正整数'},
english:{pattern: Vregular.english, errMess: '请输入正确的英文字母'},
idNumber:{pattern: Vregular.IDNumber, errMess: '请输入正确的证件号'},
req:{pattern: Vregular.noEmpty, errMess: '必填项'},
same:{pattern:"",errMess: '两次输入不一致'},
pwd:{pattern:Vregular.pwd,errMess: '密码格式不正确'}
}
export default Vrules
\ No newline at end of file
<template>
<view class="car-number">
<view class="new-energy">新能源</view>
<view class="wrap" @tap="focusHandler">
<view
:class="[
'cell',
{ last: index === length - 1},
{ 'no-border': index === length - 1 || index === length - 2 },
{ active: index === current },
]"
v-for="(val, index) in fill"
:key="index"
@tap.stop="focusHandler(index)"
>
<view class="val">{{val}}</view>
<view class="border"></view>
</view>
</view>
<key-board
v-if="focus"
:type="kType"
@on-delete="keyDeleteHandler"
@on-input="keyInputHandler"
@on-hide="keyHideHandler"
></key-board>
</view>
</template>
<script>
import KeyBoard from '../codecook-keyboard/codecook-keyboard.vue';
export default {
name: 'CarNumber',
components: {
KeyBoard
},
props: {
value: {
type: String,
default: '',
},
length: {
type: Number,
default: 8
}
},
data() {
return {
focus: false,
current: 0,
fill: new Array(this.length).fill(''),
}
},
computed: {
kType() {
return this.current === 0 ? 'provinces' : 'areas';
},
},
watch: {
fill(val) {
this.$emit('input', val.join(''));
this.$emit('change', val);
},
},
methods: {
focusHandler(index = 0) {
this.focus = true;
this.current = index;
console.log(this.current);
},
keyDeleteHandler() {
this.$set(this.fill, this.current, '');
if (this.current <= 0) {
return;
}
this.current -= 1;
},
keyInputHandler(key) {
this.$set(this.fill, this.current, key);
if (this.current >= this.length - 1) {
return;
}
this.current += 1;
},
keyHideHandler() {
this.focus = false;
},
},
beforeMount() {
if (this.value) {
this.value.split('').forEach((key, index) => {
if (index >= this.length) {
return;
}
this.$set(this.fill, index, key);
});
this.current = Math.min(this.value.length, this.length - 1);
}
},
mounted() {
},
}
</script>
<style scoped lang="less">
.car-number {
position: relative;
width: 100%;
.wrap {
width: 100%;
height: 100%;
display: flex;
justify-content: space-between;
border: 1rpx solid #E6E6E6;
box-sizing: border-box;
border-radius: 8rpx;
box-shadow: 0rpx 6rpx 6rpx 0rpx rgba(128, 128, 128, 0.1);
padding: 15rpx 0;
}
.new-energy {
font-size: 24rpx;
color: #333232;
margin-bottom: 13rpx;
display: flex;
flex-direction: row-reverse;
padding-right: 5rpx;
}
.cell {
box-sizing: border-box;
padding: 14rpx 0;
flex: 1;
color: #666666;
font-size: 34rpx;
border-right: 1rpx solid #CCCCCC;
text-align: center;
border-bottom: 1rpx solid transparent;
box-sizing: border-box;
padding: 0 10rpx;
display: flex;
flex-direction: column;
position: relative;
height: 70rpx;
.val {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.border {
flex-shrink: 0;
flex-grow: 0;
height: 2rpx;
background: transparent;
width: 100%;
}
&.active {
.border {
background: #FE8525;
}
}
&.no-border {
border-right: none;
}
&.last:after {
content: '';
width: 100%;
border: 2px solid #00FF00;
border-radius: 8rpx;
margin: -18rpx 0;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
box-sizing: border-box;
}
}
}
</style>
<template>
<view class="car-keyboard">
<view class="status-bar">
<view class="close" @click="hideHandler">
关闭
</view>
</view>
<view class="keys-container">
<view class="row" v-for="(row, index) in keys" :key="index">
<view
:class="[
'key',
{ last: j === row.length - 1 },
{ 'is-delete': deleteKeys.includes(key) },
]"
v-for="(key, j) in row"
:key="key"
@click="keyTapHandler(key)"
>
<view class="txt" v-if="!deleteKeys.includes(key)">
{{key}}
</view>
<view class="delete" v-else></view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'KeyBoard',
components: {
},
props: {
value: {
type: Boolean,
default: false,
},
type: {
type: String,
default: 'provinces',
validator: (value) => {
return ['provinces', 'areas'].indexOf(value) !== -1
}
},
},
data() {
return {
deleteKeys: ['-', '='], // 避免2个删除按钮key冲突
provinces: [
[ "京", "津", "沪", "渝", "川", "新", "藏", "宁", "桂", "贵" ],
[ "云", "黑", "吉", "辽", "晋", "冀", "青", "鲁", "豫", "苏" ],
[ "皖", "浙", "闽", "赣", "湘", "鄂", "粤", "琼", "甘", "陕" ],
[ "蒙", "港", "澳", "台", "使", "领", "警", "学", "=" ],
],
areas: [
[ "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" ],
[ "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P" ],
[ "A", "S", "D", "F", "G", "H", "J", "K", "L" ],
[ "Z", "X", "C", "V", "B", "N", "M", "-" ],
],
}
},
watch: {
},
computed: {
keys() {
return this[this.type];
},
},
methods: {
keyTapHandler(key) {
if (this.deleteKeys.includes(key)) {
this.$emit('on-delete');
return;
}
this.$emit('on-input', key);
},
hideHandler() {
this.$emit('on-hide');
}
},
beforeMount() {
},
mounted() {
},
}
</script>
<style scoped lang="less">
.car-keyboard {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
background-color: #F5F5F5;
}
.status-bar {
height: 80rpx;
background: #DFE8E7;
color: #323330;
display: flex;
flex-direction: row-reverse;
}
.close {
font-size: 30rpx;
height: 100%;
padding: 0 20rpx;
display: flex;
align-items: center;
}
.keys-container {
padding: 23rpx 13rpx 30rpx 13rpx;
}
.row {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin-bottom: 14rpx;
}
.key {
width: 60rpx;
height: 72rpx;
background: #FFFFFF;
border: 1rpx solid #E6E6E6;
box-sizing: border-box;
border-radius: 4rpx;
color: #323330;
font-size: 36rpx;
display: flex;
align-items: center;
justify-content: center;
margin-right: 14rpx;
.delete {
width: 66rpx;
height: 40rpx;
background: url(../../static/codecook-keyboard/icon_delete.png) no-repeat;
background-size: 100% 100%;
}
&.is-delete {
width: 134rpx;
}
&.last {
margin-right: 0;
}
}
</style>
This diff is collapsed.
MIT License
Copyright (c) 2020 www.uviewui.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
\ No newline at end of file
<p align="center">
<img alt="logo" src="https://uviewui.com/common/logo.png" width="120" height="120" style="margin-bottom: 10px;">
</p>
<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uView</h3>
<h3 align="center">多平台快速开发的UI框架</h3>
## 说明
uView UI,是[uni-app](https://uniapp.dcloud.io/)生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水
## 特性
- 兼容安卓,iOS,微信小程序,H5,QQ小程序,百度小程序,支付宝小程序,头条小程序
- 60+精选组件,功能丰富,多端兼容,让您快速集成,开箱即用
- 众多贴心的JS利器,让您飞镖在手,召之即来,百步穿杨
- 众多的常用页面和布局,让您专注逻辑,事半功倍
- 详尽的文档支持,现代化的演示效果
- 按需引入,精简打包体积
## 安装
```bash
# npm方式安装,插件市场导入无需执行此命令
npm i uview-ui
```
## 快速上手
1. `main.js`引入uView库
```js
// main.js
import uView from 'uview-ui';
Vue.use(uView);
```
2. `App.vue`引入基础样式(注意style标签需声明scss属性支持)
```css
/* App.vue */
<style lang="scss">
@import "uview-ui/index.scss";
</style>
```
3. `uni.scss`引入全局scss变量文件
```css
/* uni.scss */
@import "uview-ui/theme.scss";
```
4. `pages.json`配置easycom规则(按需引入)
```js
// pages.json
{
"easycom": {
// npm安装的方式不需要前面的"@/",下载安装的方式需要"@/"
// npm安装方式
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
// 下载安装方式
// "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
},
// 此为本身已有的内容
"pages": [
// ......
]
}
```
请通过[快速上手](https://www.uviewui.com/components/quickstart.html)了解更详细的内容
## 使用方法
配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。
```html
<template>
<u-button text="按钮"></u-button>
</template>
```
请通过[快速上手](https://www.uviewui.com/components/quickstart.html)了解更详细的内容
## 链接
- [官方文档](https://www.uviewui.com/)
- [更新日志](https://www.www.uviewui.com/components/changelog.html)
- [升级指南](https://www.uviewui.com/components/changelog.html)
- [关于我们](https://www.uviewui.com/cooperation/about.html)
## 预览
您可以通过**微信**扫码,查看最佳的演示效果。
<br>
<br>
<img src="https://uviewui.com/common/weixin_mini_qrcode.png" width="220" height="220" >
## 捐赠uView的研发
uView文档和源码全部开源免费,如果您认为uView帮到了您的开发工作,您可以捐赠uView的研发工作,捐赠无门槛,哪怕是一杯可乐也好(相信这比打赏主播更有意义)。
<img src="https://uviewui.com/common/alipay.png" width="220" ><img style="margin-left: 100px;" src="https://uviewui.com/common/wechat.png" width="220" >
## 版权信息
uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uView应用到您的产品中。
This diff is collapsed.
<template>
<uvForm
ref="uForm"
:model="model"
:rules="rules"
:errorType="errorType"
:borderBottom="borderBottom"
:labelPosition="labelPosition"
:labelWidth="labelWidth"
:labelAlign="labelAlign"
:labelStyle="labelStyle"
:customStyle="customStyle"
>
<slot />
</uvForm>
</template>
<script>
/**
* 此组件存在的理由是,在nvue下,u-form被uni-app官方占用了,u-form在nvue中相当于form组件
* 所以在nvue下,取名为u--form,内部其实还是u-form.vue,只不过做一层中转
*/
import uvForm from '../u-form/u-form.vue';
import props from '../u-form/props.js'
export default {
// #ifdef MP-WEIXIN
name: 'u-form',
// #endif
// #ifndef MP-WEIXIN
name: 'u--form',
// #endif
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvForm
},
created() {
this.children = []
},
methods: {
// 手动设置校验的规则,如果规则中有函数的话,微信小程序中会过滤掉,所以只能手动调用设置规则
setRules(rules) {
this.$refs.uForm.setRules(rules)
},
validate() {
/**
* 在微信小程序中,通过this.$parent拿到的父组件是u--form,而不是其内嵌的u-form
* 导致在u-form组件中,拿不到对应的children数组,从而校验无效,所以这里每次调用u-form组件中的
* 对应方法的时候,在小程序中都先将u--form的children赋值给u-form中的children
*/
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.validate()
},
validateField(value, callback) {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.validateField(value, callback)
},
resetFields() {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.resetFields()
},
clearValidate(props) {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.clearValidate(props)
},
setMpData() {
this.$refs.uForm.children = this.children
}
},
}
</script>
<template>
<uvImage
:src="src"
:mode="mode"
:width="width"
:height="height"
:shape="shape"
:radius="radius"
:lazyLoad="lazyLoad"
:showMenuByLongpress="showMenuByLongpress"
:loadingIcon="loadingIcon"
:errorIcon="errorIcon"
:showLoading="showLoading"
:showError="showError"
:fade="fade"
:webp="webp"
:duration="duration"
:bgColor="bgColor"
:customStyle="customStyle"
@click="$emit('click')"
@error="$emit('error')"
@load="$emit('load')"
>
<template v-slot:loading>
<slot name="loading"></slot>
</template>
<template v-slot:error>
<slot name="error"></slot>
</template>
</uvImage>
</template>
<script>
/**
* 此组件存在的理由是,在nvue下,u-image被uni-app官方占用了,u-image在nvue中相当于image组件
* 所以在nvue下,取名为u--image,内部其实还是u-iamge.vue,只不过做一层中转
*/
import uvImage from '../u-image/u-image.vue';
import props from '../u-image/props.js';
export default {
name: 'u--image',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvImage
},
}
</script>
\ No newline at end of file
<template>
<uvInput
:value="value"
:type="type"
:fixed="fixed"
:disabled="disabled"
:disabledColor="disabledColor"
:clearable="clearable"
:password="password"
:maxlength="maxlength"
:placeholder="placeholder"
:placeholderClass="placeholderClass"
:placeholderStyle="placeholderStyle"
:showWordLimit="showWordLimit"
:confirmType="confirmType"
:confirmHold="confirmHold"
:holdKeyboard="holdKeyboard"
:focus="focus"
:autoBlur="autoBlur"
:disableDefaultPadding="disableDefaultPadding"
:cursor="cursor"
:cursorSpacing="cursorSpacing"
:selectionStart="selectionStart"
:selectionEnd="selectionEnd"
:adjustPosition="adjustPosition"
:inputAlign="inputAlign"
:fontSize="fontSize"
:color="color"
:prefixIcon="prefixIcon"
:suffixIcon="suffixIcon"
:suffixIconStyle="suffixIconStyle"
:prefixIconStyle="prefixIconStyle"
:border="border"
:readonly="readonly"
:shape="shape"
:customStyle="customStyle"
:formatter="formatter"
@focus="$emit('focus')"
@blur="$emit('blur')"
@keyboardheightchange="$emit('keyboardheightchange')"
@change="e => $emit('change', e)"
@input="e => $emit('input', e)"
@confirm="e => $emit('confirm', e)"
@clear="$emit('clear')"
@click="$emit('click')"
>
<!-- #ifdef MP -->
<slot name="prefix"></slot>
<slot name="suffix"></slot>
<!-- #endif -->
<!-- #ifndef MP -->
<slot name="prefix" slot="prefix"></slot>
<slot name="suffix" slot="suffix"></slot>
<!-- #endif -->
</uvInput>
</template>
<script>
/**
* 此组件存在的理由是,在nvue下,u-input被uni-app官方占用了,u-input在nvue中相当于input组件
* 所以在nvue下,取名为u--input,内部其实还是u-input.vue,只不过做一层中转
*/
import uvInput from '../u-input/u-input.vue';
import props from '../u-input/props.js'
export default {
name: 'u--input',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvInput
},
}
</script>
\ No newline at end of file
<template>
<uvText
:type="type"
:show="show"
:text="text"
:prefixIcon="prefixIcon"
:suffixIcon="suffixIcon"
:mode="mode"
:href="href"
:format="format"
:call="call"
:openType="openType"
:bold="bold"
:block="block"
:lines="lines"
:color="color"
:decoration="decoration"
:size="size"
:iconStyle="iconStyle"
:margin="margin"
:lineHeight="lineHeight"
:align="align"
:wordWrap="wordWrap"
:customStyle="customStyle"
@click="$emit('click')"
></uvText>
</template>
<script>
/**
* 此组件存在的理由是,在nvue下,u-text被uni-app官方占用了,u-text在nvue中相当于input组件
* 所以在nvue下,取名为u--input,内部其实还是u-text.vue,只不过做一层中转
* 不使用v-bind="$attrs",而是分开独立写传参,是因为微信小程序不支持此写法
*/
import uvText from "../u-text/u-text.vue";
import props from "../u-text/props.js";
export default {
name: "u--text",
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvText,
},
};
</script>
<template>
<uvTextarea
:value="value"
:placeholder="placeholder"
:height="height"
:confirmType="confirmType"
:disabled="disabled"
:count="count"
:focus="focus"
:autoHeight="autoHeight"
:fixed="fixed"
:cursorSpacing="cursorSpacing"
:cursor="cursor"
:showConfirmBar="showConfirmBar"
:selectionStart="selectionStart"
:selectionEnd="selectionEnd"
:adjustPosition="adjustPosition"
:disableDefaultPadding="disableDefaultPadding"
:holdKeyboard="holdKeyboard"
:maxlength="maxlength"
:border="border"
:customStyle="customStyle"
:formatter="formatter"
@focus="e => $emit('focus')"
@blur="e => $emit('blur')"
@linechange="e => $emit('linechange', e)"
@confirm="e => $emit('confirm')"
@input="e => $emit('input', e)"
@keyboardheightchange="e => $emit('keyboardheightchange')"
></uvTextarea>
</template>
<script>
/**
* 此组件存在的理由是,在nvue下,u--textarea被uni-app官方占用了,u-textarea在nvue中相当于textarea组件
* 所以在nvue下,取名为u--textarea,内部其实还是u-textarea.vue,只不过做一层中转
*/
import uvTextarea from '../u-textarea/u-textarea.vue';
import props from '../u-textarea/props.js'
export default {
name: 'u--textarea',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvTextarea
},
}
</script>
export default {
props: {
// 操作菜单是否展示 (默认false)
show: {
type: Boolean,
default: uni.$u.props.actionSheet.show
},
// 标题
title: {
type: String,
default: uni.$u.props.actionSheet.title
},
// 选项上方的描述信息
description: {
type: String,
default: uni.$u.props.actionSheet.description
},
// 数据
actions: {
type: Array,
default: uni.$u.props.actionSheet.actions
},
// 取消按钮的文字,不为空时显示按钮
cancelText: {
type: String,
default: uni.$u.props.actionSheet.cancelText
},
// 点击某个菜单项时是否关闭弹窗
closeOnClickAction: {
type: Boolean,
default: uni.$u.props.actionSheet.closeOnClickAction
},
// 处理底部安全区(默认true)
safeAreaInsetBottom: {
type: Boolean,
default: uni.$u.props.actionSheet.safeAreaInsetBottom
},
// 小程序的打开方式
openType: {
type: String,
default: uni.$u.props.actionSheet.openType
},
// 点击遮罩是否允许关闭 (默认true)
closeOnClickOverlay: {
type: Boolean,
default: uni.$u.props.actionSheet.closeOnClickOverlay
},
// 圆角值
round: {
type: [Boolean, String, Number],
default: uni.$u.props.actionSheet.round
}
}
}
<template>
<u-popup
:show="show"
mode="bottom"
@close="closeHandler"
:safeAreaInsetBottom="safeAreaInsetBottom"
:round="round"
>
<view class="u-action-sheet">
<view
class="u-action-sheet__header"
v-if="title"
>
<text class="u-action-sheet__header__title u-line-1">{{title}}</text>
<view
class="u-action-sheet__header__icon-wrap"
@tap.stop="close"
>
<u-icon
name="close"
size="17"
color="#c8c9cc"
bold
></u-icon>
</view>
</view>
<text
class="u-action-sheet__description"
:style="[{
marginTop: `${title && description ? 0 : '18px'}`
}]"
v-if="description"
>{{description}}</text>
<slot>
<u-line v-if="description"></u-line>
<view class="u-action-sheet__item-wrap">
<template v-for="(item, index) in actions">
<!-- #ifdef MP -->
<button
:key="index"
class="u-reset-button"
:openType="item.openType"
@getuserinfo="onGetUserInfo"
@contact="onContact"
@getphonenumber="onGetPhoneNumber"
@error="onError"
@launchapp="onLaunchApp"
@opensetting="onOpenSetting"
:lang="lang"
:session-from="sessionFrom"
:send-message-title="sendMessageTitle"
:send-message-path="sendMessagePath"
:send-message-img="sendMessageImg"
:show-message-card="showMessageCard"
:app-parameter="appParameter"
@tap="selectHandler(index)"
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
>
<!-- #endif -->
<view
class="u-action-sheet__item-wrap__item"
@tap.stop="selectHandler(index)"
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
:hover-stay-time="150"
>
<template v-if="!item.loading">
<text
class="u-action-sheet__item-wrap__item__name"
:style="[itemStyle(index)]"
>{{ item.name }}</text>
<text
v-if="item.subname"
class="u-action-sheet__item-wrap__item__subname"
>{{ item.subname }}</text>
</template>
<u-loading-icon
v-else
custom-class="van-action-sheet__loading"
size="18"
mode="circle"
/>
</view>
<!-- #ifdef MP -->
</button>
<!-- #endif -->
<u-line v-if="index !== actions.length - 1"></u-line>
</template>
</view>
</slot>
<u-gap
bgColor="#eaeaec"
height="6"
v-if="cancelText"
></u-gap>
<view hover-class="u-action-sheet--hover">
<text
@touchmove.stop.prevent
:hover-stay-time="150"
v-if="cancelText"
class="u-action-sheet__cancel-text"
@tap="cancel"
>{{cancelText}}</text>
</view>
</view>
</u-popup>
</template>
<script>
import openType from '../../libs/mixin/openType'
import button from '../../libs/mixin/button'
import props from './props.js';
/**
* ActionSheet 操作菜单
* @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
* @tutorial https://www.uviewui.com/components/actionSheet.html
*
* @property {Boolean} show 操作菜单是否展示 (默认 false )
* @property {String} title 操作菜单标题
* @property {String} description 选项上方的描述信息
* @property {Array<Object>} actions 按钮的文字数组,见官方文档示例
* @property {String} cancelText 取消按钮的提示文字,不为空时显示按钮
* @property {Boolean} closeOnClickAction 点击某个菜单项时是否关闭弹窗 (默认 true )
* @property {Boolean} safeAreaInsetBottom 处理底部安全区 (默认 true )
* @property {String} openType 小程序的打开方式 (contact | launchApp | getUserInfo | openSetting |getPhoneNumber |error )
* @property {Boolean} closeOnClickOverlay 点击遮罩是否允许关闭 (默认 true )
* @property {Number|String} round 圆角值,默认无圆角 (默认 0 )
* @property {String} lang 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文
* @property {String} sessionFrom 会话来源,openType="contact"时有效
* @property {String} sendMessageTitle 会话内消息卡片标题,openType="contact"时有效
* @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径,openType="contact"时有效
* @property {String} sendMessageImg 会话内消息卡片图片,openType="contact"时有效
* @property {Boolean} showMessageCard 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效 (默认 false )
* @property {String} appParameter 打开 APP 时,向 APP 传递的参数,openType=launchApp 时有效
*
* @event {Function} select 点击ActionSheet列表项时触发
* @event {Function} close 点击取消按钮时触发
* @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,回调的 detail 数据与 wx.getUserInfo 返回的一致,openType="getUserInfo"时有效
* @event {Function} contact 客服消息回调,openType="contact"时有效
* @event {Function} getphonenumber 获取用户手机号回调,openType="getPhoneNumber"时有效
* @event {Function} error 当使用开放能力时,发生错误的回调,openType="error"时有效
* @event {Function} launchapp 打开 APP 成功的回调,openType="launchApp"时有效
* @event {Function} opensetting 在打开授权设置页后回调,openType="openSetting"时有效
* @example <u-action-sheet :actions="list" :title="title" :show="show"></u-action-sheet>
*/
export default {
name: "u-action-sheet",
// 一些props参数和methods方法,通过mixin混入,因为其他文件也会用到
mixins: [openType, button, uni.$u.mixin, props],
data() {
return {
}
},
computed: {
// 操作项目的样式
itemStyle() {
return (index) => {
let style = {};
if (this.actions[index].color) style.color = this.actions[index].color
if (this.actions[index].fontSize) style.fontSize = uni.$u.addUnit(this.actions[index].fontSize)
// 选项被禁用的样式
if (this.actions[index].disabled) style.color = '#c0c4cc'
return style;
}
},
},
methods: {
closeHandler() {
// 允许点击遮罩关闭时,才发出close事件
if(this.closeOnClickOverlay) {
this.$emit('close')
}
},
// 点击取消按钮
cancel() {
this.$emit('close')
},
selectHandler(index) {
const item = this.actions[index]
if (item && !item.disabled && !item.loading) {
this.$emit('select', item)
if (this.closeOnClickAction) {
this.$emit('close')
}
}
},
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-action-sheet-reset-button-width:100% !default;
$u-action-sheet-title-font-size: 16px !default;
$u-action-sheet-title-padding: 12px 30px !default;
$u-action-sheet-title-color: $u-main-color !default;
$u-action-sheet-header-icon-wrap-right:15px !default;
$u-action-sheet-header-icon-wrap-top:15px !default;
$u-action-sheet-description-font-size:13px !default;
$u-action-sheet-description-color:14px !default;
$u-action-sheet-description-margin: 18px 15px !default;
$u-action-sheet-item-wrap-item-padding:15px !default;
$u-action-sheet-item-wrap-name-font-size:16px !default;
$u-action-sheet-item-wrap-subname-font-size:13px !default;
$u-action-sheet-item-wrap-subname-color: #c0c4cc !default;
$u-action-sheet-item-wrap-subname-margin-top:10px !default;
$u-action-sheet-cancel-text-font-size:16px !default;
$u-action-sheet-cancel-text-color:$u-content-color !default;
$u-action-sheet-cancel-text-font-size:15px !default;
$u-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default;
.u-reset-button {
width: $u-action-sheet-reset-button-width;
}
.u-action-sheet {
text-align: center;
&__header {
position: relative;
padding: $u-action-sheet-title-padding;
&__title {
font-size: $u-action-sheet-title-font-size;
color: $u-action-sheet-title-color;
font-weight: bold;
text-align: center;
}
&__icon-wrap {
position: absolute;
right: $u-action-sheet-header-icon-wrap-right;
top: $u-action-sheet-header-icon-wrap-top;
}
}
&__description {
font-size: $u-action-sheet-description-font-size;
color: $u-tips-color;
margin: $u-action-sheet-description-margin;
text-align: center;
}
&__item-wrap {
&__item {
padding: $u-action-sheet-item-wrap-item-padding;
@include flex;
align-items: center;
justify-content: center;
flex-direction: column;
&__name {
font-size: $u-action-sheet-item-wrap-name-font-size;
color: $u-main-color;
text-align: center;
}
&__subname {
font-size: $u-action-sheet-item-wrap-subname-font-size;
color: $u-action-sheet-item-wrap-subname-color;
margin-top: $u-action-sheet-item-wrap-subname-margin-top;
text-align: center;
}
}
}
&__cancel-text {
font-size: $u-action-sheet-cancel-text-font-size;
color: $u-action-sheet-cancel-text-color;
text-align: center;
padding: $u-action-sheet-cancel-text-font-size;
}
&--hover {
background-color: $u-action-sheet-cancel-text-hover-background-color;
}
}
</style>
export default {
props: {
// 图片地址,Array<String>|Array<Object>形式
urls: {
type: Array,
default: uni.$u.props.album.urls
},
// 指定从数组的对象元素中读取哪个属性作为图片地址
keyName: {
type: String,
default: uni.$u.props.album.keyName
},
// 单图时,图片长边的长度
singleSize: {
type: [String, Number],
default: uni.$u.props.album.singleSize
},
// 多图时,图片边长
multipleSize: {
type: [String, Number],
default: uni.$u.props.album.multipleSize
},
// 多图时,图片水平和垂直之间的间隔
space: {
type: [String, Number],
default: uni.$u.props.album.space
},
// 单图时,图片缩放裁剪的模式
singleMode: {
type: String,
default: uni.$u.props.album.singleMode
},
// 多图时,图片缩放裁剪的模式
multipleMode: {
type: String,
default: uni.$u.props.album.multipleMode
},
// 最多展示的图片数量,超出时最后一个位置将会显示剩余图片数量
maxCount: {
type: [String, Number],
default: uni.$u.props.album.maxCount
},
// 是否可以预览图片
previewFullImage: {
type: Boolean,
default: uni.$u.props.album.previewFullImage
},
// 每行展示图片数量,如设置,singleSize和multipleSize将会无效
rowCount: {
type: [String, Number],
default: uni.$u.props.album.rowCount
},
// 超出maxCount时是否显示查看更多的提示
showMore: {
type: Boolean,
default: uni.$u.props.album.showMore
}
}
}
<template>
<view class="u-album">
<view
class="u-album__row"
ref="u-album__row"
v-for="(arr, index) in showUrls"
:forComputedUse="albumWidth"
:key="index"
>
<view
class="u-album__row__wrapper"
v-for="(item, index1) in arr"
:key="index1"
:style="[imageStyle(index + 1, index1 + 1)]"
@tap="previewFullImage ? onPreviewTap(getSrc(item)) : ''"
>
<image
:src="getSrc(item)"
:mode="
urls.length === 1
? imageHeight > 0
? singleMode
: 'widthFix'
: multipleMode
"
:style="[
{
width: imageWidth,
height: imageHeight
}
]"
></image>
<view
v-if="
showMore &&
urls.length > rowCount * showUrls.length &&
index === showUrls.length - 1 &&
index1 === showUrls[showUrls.length - 1].length - 1
"
class="u-album__row__wrapper__text"
>
<u--text
:text="`+${urls.length - maxCount}`"
color="#fff"
:size="multipleSize * 0.3"
align="center"
customStyle="justify-content: center"
></u--text>
</view>
</view>
</view>
</view>
</template>
<script>
import props from './props.js'
// #ifdef APP-NVUE
// 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度
const dom = uni.requireNativePlugin('dom')
// #endif
/**
* Album 相册
* @description 本组件提供一个类似相册的功能,让开发者开发起来更加得心应手。减少重复的模板代码
* @tutorial https://www.uviewui.com/components/album.html
*
* @property {Array} urls 图片地址列表 Array<String>|Array<Object>形式
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
* @property {String | Number} singleSize 单图时,图片长边的长度 (默认 180 )
* @property {String | Number} multipleSize 多图时,图片边长 (默认 70 )
* @property {String | Number} space 多图时,图片水平和垂直之间的间隔 (默认 6 )
* @property {String} singleMode 单图时,图片缩放裁剪的模式 (默认 'scaleToFill' )
* @property {String} multipleMode 多图时,图片缩放裁剪的模式 (默认 'aspectFill' )
* @property {String | Number} maxCount 取消按钮的提示文字 (默认 9 )
* @property {Boolean} previewFullImage 是否可以预览图片 (默认 true )
* @property {String | Number} rowCount 每行展示图片数量,如设置,singleSize和multipleSize将会无效 (默认 3 )
* @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 (默认 true )
*
* @event {Function} albumWidth 某些特殊的情况下,需要让文字与相册的宽度相等,这里事件的形式对外发送 (回调参数 width )
* @example <u-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></u-album>
*/
export default {
name: 'u-album',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
// 单图的宽度
singleWidth: 0,
// 单图的高度
singleHeight: 0,
// 单图时,如果无法获取图片的尺寸信息,让图片宽度默认为容器的一定百分比
singlePercent: 0.6
}
},
watch: {
urls: {
immediate: true,
handler(newVal) {
if (newVal.length === 1) {
this.getImageRect()
}
}
}
},
computed: {
imageStyle() {
return (index1, index2) => {
const { space, rowCount, multipleSize, urls } = this,
{ addUnit, addStyle } = uni.$u,
rowLen = this.showUrls.length,
allLen = this.urls.length
const style = {
marginRight: addUnit(space),
marginBottom: addUnit(space)
}
// 如果为最后一行,则每个图片都无需下边框
if (index1 === rowLen) style.marginBottom = 0
// 每行的最右边一张和总长度的最后一张无需右边框
if (
index2 === rowCount ||
(index1 === rowLen &&
index2 === this.showUrls[index1 - 1].length)
)
style.marginRight = 0
return style
}
},
// 将数组划分为二维数组
showUrls() {
const arr = []
this.urls.map((item, index) => {
// 限制最大展示数量
if (index + 1 <= this.maxCount) {
// 计算该元素为第几个素组内
const itemIndex = Math.floor(index / this.rowCount)
// 判断对应的索引是否存在
if (!arr[itemIndex]) {
arr[itemIndex] = []
}
arr[itemIndex].push(item)
}
})
return arr
},
imageWidth() {
return uni.$u.addUnit(
this.urls.length === 1 ? this.singleWidth : this.multipleSize
)
},
imageHeight() {
return uni.$u.addUnit(
this.urls.length === 1 ? this.singleHeight : this.multipleSize
)
},
// 此变量无实际用途,仅仅是为了利用computed特性,让其在urls长度等变化时,重新计算图片的宽度
// 因为用户在某些特殊的情况下,需要让文字与相册的宽度相等,所以这里事件的形式对外发送
albumWidth() {
let width = 0
if (this.urls.length === 1) {
width = this.singleWidth
} else {
width =
this.showUrls[0].length * this.multipleSize +
this.space * (this.showUrls[0].length - 1)
}
this.$emit('albumWidth', width)
return width
}
},
methods: {
// 预览图片
onPreviewTap(url) {
const urls = this.urls.map((item) => {
return this.getSrc(item)
})
uni.previewImage({
current: url,
urls
})
},
// 获取图片的路径
getSrc(item) {
return uni.$u.test.object(item)
? (this.keyName && item[this.keyName]) || item.src
: item
},
// 单图时,获取图片的尺寸
// 在小程序中,需要将网络图片的的域名添加到小程序的download域名才可能获取尺寸
// 在没有添加的情况下,让单图宽度默认为盒子的一定宽度(singlePercent)
getImageRect() {
const src = this.getSrc(this.urls[0])
uni.getImageInfo({
src,
success: (res) => {
// 判断图片横向还是竖向展示方式
const isHorizotal = res.width >= res.height
this.singleWidth = isHorizotal
? this.singleSize
: (res.width / res.height) * this.singleSize
this.singleHeight = !isHorizotal
? this.singleSize
: (res.height / res.width) * this.singleWidth
},
fail: () => {
this.getComponentWidth()
}
})
},
// 获取组件的宽度
async getComponentWidth() {
// 延时一定时间,以获取dom尺寸
await uni.$u.sleep(30)
// #ifndef APP-NVUE
this.$uGetRect('.u-album__row').then((size) => {
this.singleWidth = size.width * this.singlePercent
})
// #endif
// #ifdef APP-NVUE
// 这里ref="u-album__row"所在的标签为通过for循环出来,导致this.$refs['u-album__row']是一个数组
const ref = this.$refs['u-album__row'][0]
ref &&
dom.getComponentRect(ref, (res) => {
this.singleWidth = res.size.width * this.singlePercent
})
// #endif
}
}
}
</script>
<style lang="scss" scoped>
@import '../../libs/css/components.scss';
.u-album {
@include flex(column);
&__row {
@include flex(row);
flex-wrap: wrap;
&__wrapper {
position: relative;
&__text {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
@include flex(row);
justify-content: center;
align-items: center;
}
}
}
}
</style>
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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