chore(build): 调整个别组件的位置,减少对主包尺寸的影响

This commit is contained in:
2026-01-16 12:00:21 +08:00
parent 08880a15df
commit 5b9bef9214
33 changed files with 1588 additions and 1106 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,234 @@
<template>
<view class="code-box">
<view class="flex-box">
<input :value="inputValue" type="number" :focus="autoFocus" :maxlength="maxlength" class="hide-input" @input="getVal" />
<block v-for="(item, index) in ranges" :key="index">
<view :class="['item', { active: codeIndex === item, middle: type === 'middle', bottom: type === 'bottom', box: type === 'box' }]">
<view class="line" v-if="type !== 'middle'"></view>
<view v-if="type === 'middle' && codeIndex <= item" class="bottom-line"></view>
<block v-if="isPwd && codeArr.length >= item"><text class="dot"></text></block>
<block v-else>
<text class="number">{{ codeArr[index] ? codeArr[index] : '' }}</text>
</block>
</view>
</block>
</view>
</view>
</template>
<script>
// 支持使用 v-model
// 支持使用refs
export default {
name: 'mypOneInput',
props: {
// 支持外部提供支持使用v-model
// 支持通过value来做清空
value: {
type: String,
default: ''
},
// 4/6
maxlength: {
type: Number,
default: 4
},
autoFocus: {
type: Boolean,
default: false
},
isPwd: {
type: Boolean,
default: false
},
// middle-middle line, bottom-bottom line, box-square box
type: {
type: String,
default: 'bottom'
}
},
watch: {
maxlength: {
immediate: true,
handler: function(newV) {
if (newV === 6) {
this.ranges = [1, 2, 3, 4, 5, 6];
} else {
this.ranges = [1, 2, 3, 4];
}
}
},
value: {
immediate: true,
handler: function(newV) {
if (newV !== this.inputValue) {
this.inputValue = newV;
this.toMakeAndCheck(newV);
}
}
}
},
data() {
return {
inputValue: '',
codeIndex: 1,
codeArr: [],
ranges: [1, 2, 3, 4]
};
},
methods: {
getVal(e) {
const val = e.detail.value;
this.inputValue = val;
this.$emit('input', val);
this.toMakeAndCheck(val);
},
toMakeAndCheck(val) {
const arr = val.split('');
this.codeIndex = arr.length + 1;
this.codeArr = arr;
if (this.codeIndex > Number(this.maxlength)) {
this.$emit('finish', this.codeArr.join(''));
}
},
// refs 时不再提供 v-model 支持
// 支持使用refs来设置value
// 没有提供数据保护与检测,自己在外面对数据进行检测保护
set(val) {
this.inputValue = val;
this.toMakeAndCheck(val);
},
// 支持使用refs来清空
clear() {
this.inputValue = '';
this.codeArr = [];
this.codeIndex = 1;
}
}
};
</script>
<style scoped>
@keyframes twinkling {
0% {
opacity: 0.2;
}
50% {
opacity: 0.5;
}
100% {
opacity: 0.2;
}
}
.code-box {
text-align: center;
}
.flex-box {
display: flex;
justify-content: center;
flex-wrap: wrap;
position: relative;
}
.flex-box .hide-input {
position: absolute;
top: 0;
left: -100%;
width: 200%;
height: 100%;
text-align: left;
z-index: 9;
opacity: 1;
}
.flex-box .item {
position: relative;
flex: 1;
margin-right: 18rpx;
font-size: 70rpx;
font-weight: bold;
color: #333333;
line-height: 100rpx;
}
.flex-box .item::before {
content: '';
padding-top: 100%;
display: block;
}
.flex-box .item:last-child {
margin-right: 0;
}
.flex-box .middle {
border: none;
}
.flex-box .box {
box-sizing: border-box;
border: 2rpx solid #cccccc;
border-width: 2rpx 0 2rpx 2rpx;
margin-right: 0;
}
.flex-box .box:first-of-type {
border-top-left-radius: 8rpx;
border-bottom-left-radius: 8rpx;
}
.flex-box .box:last-child {
border-right: 2rpx solid #cccccc;
border-top-right-radius: 8rpx;
border-bottom-right-radius: 8rpx;
}
.flex-box .bottom {
box-sizing: border-box;
border-bottom: 2rpx solid #ddd;
}
.flex-box .active {
border-color: #ddd;
}
.flex-box .active .line {
display: block;
}
.flex-box .line {
display: none;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 2rpx;
height: 40rpx;
background: #333333;
animation: twinkling 1s infinite ease;
}
.flex-box .dot,
.flex-box .number {
line-height: 40rpx;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
.flex-box .bottom-line {
height: 8rpx;
background: #000000;
width: 80%;
position: absolute;
border-radius: 4rpx;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>

View File

@@ -0,0 +1,332 @@
<template>
<view>
<view @touchmove.prevent.stop v-if="birthday" class="reward-popup">
<uni-popup ref="birthdayGift" type="center" :maskClick="false">
<view class="reward-wrap">
<view class="wrap" :style="{ backgroundImage: 'url(' + $util.img('public/uniapp/birthday_gift/birthday_gift_bg.png') + ')' }">
<view class="birthday-title-name" v-if="memberInfo">Dear {{ memberInfo.nickname }}</view>
<view class="birthday-title-desc" v-if="birthday.blessing_content">
{{ birthday.blessing_content }}
</view>
<view class="birthday-title-desc" v-else>感谢您一直以来的支持在您生日到来之际特为您送上最真诚的祝福</view>
<view class="birthday-title-hint">
<image :src="$util.img('public/uniapp/birthday_gift/birthday_gift_left.png')" mode="" class="birthday-img-all"/>
<view class="font-size-toolbar">生日贺礼</view>
<image :src="$util.img('public/uniapp/birthday_gift/birthday_gift_right.png')" mode="" class="birthday-img-all"/>
</view>
<scroll-view scroll-y="true" class="register-box">
<view class="reward-content">
<view class="content" v-if="birthday.point > 0">
<view class="info">
<text class="num">
{{ parseFloat(birthday.point) }}
<text class="type">积分</text>
</text>
<view class="desc">用于下单时抵现或兑换商品等</view>
</view>
<view class="tip" @click="closeRewardPopup('1')">立即查看</view>
</view>
<view class="content" v-if="birthday.balance_type == 0 && birthday.balance > 0">
<view class="info">
<text class="num">
{{ parseFloat(birthday.balance) }}
<text class="type">元红包</text>
</text>
<view class="desc">不可提现红包</view>
</view>
<view class="tip" @click="closeRewardPopup('2')">立即查看</view>
</view>
<view class="content" v-if="birthday.balance_type == 1 && birthday.balance_money > 0">
<view class="info">
<text class="num">
{{ parseFloat(birthday.balance_money) }}
<text class="type">元红包</text>
</text>
<view class="desc">可提现红包</view>
</view>
<view class="tip" @click="closeRewardPopup('2')">立即查看</view>
</view>
<block v-if="birthday.coupon_list.length > 0">
<block v-for="(item, index) in birthday.coupon_list" :key="index">
<view class="content">
<view class="info">
<block v-if="item.type == 'reward'">
<text class="num">
{{ parseFloat(item.money) }}
<text class="type">元优惠劵</text>
</text>
</block>
<block v-else-if="item.type == 'discount'">
<text class="num">
{{ item.discount }}
<text class="type"></text>
</text>
</block>
<view class="desc">用于下单时抵现或兑换商品等</view>
</view>
<view class="tip" @click="closeRewardPopup('3')">立即查看</view>
</view>
</block>
</block>
</view>
</scroll-view>
</view>
<view class="close-btn" @click="cancel()"><text class="iconfont icon-close btn"></text></view>
</view>
</uni-popup>
</view>
</view>
</template>
<script>
// 注册奖励弹出层
export default {
name: 'ns-birthday-gift',
data() {
return {
birthday: {
flag: false,
coupon_list: {}
}
};
},
computed: {
introduction() {
let bytesCount = 0;
if (this.birthday.blessing_content) {
for (let i = 0, n = this.birthday.blessing_content.length; i < n; i++) {
let c = this.birthday.blessing_content.charCodeAt(i);
if ((c >= 0x0001 && c <= 0x007e) || (0xff60 <= c && c <= 0xff9f)) {
bytesCount += 1;
} else {
bytesCount += 2;
}
}
}
return bytesCount;
}
},
created() {
if (!this.storeToken) return;
this.init();
},
methods: {
init() {
this.getBirthdayGift();
},
cancel() {
this.$refs.birthdayGift.close();
},
/**
* 获取生日礼配置
*/
getBirthdayGift() {
this.$api.sendRequest({
url: '/birthdaygift/api/Config/config',
success: res => {
if (res.code >= 0) {
if (res.data) {
this.birthday = res.data;
this.getReceiveGift();
}
}
}
});
},
// 领取
getReceiveGift() {
if (this.birthday.flag == true) {
this.$refs.birthdayGift.open();
this.$api.sendRequest({
url: '/birthdaygift/api/Config/receive',
data: {
id: this.birthday.id
},
success: res => {}
});
}
},
closeRewardPopup(type) {
if (type == 1) {
this.$util.redirectTo('/pages_tool/member/point_detail', {});
} else if (type == 2) {
this.$util.redirectTo('/pages_tool/member/balance_detail', {});
} else {
this.$util.redirectTo('/pages_tool/member/coupon', {});
}
}
}
};
</script>
<style scoped>
.register-box /deep/ .uni-scroll-view {
background: unset !important;
}
.register-box {
max-height: 300rpx;
overflow-y: scroll;
/* margin-top:350rpx; */
}
/deep/ .uni-popup__wrapper-box {
background-color: transparent !important;
}
/deep/ .birthday-title-hint uni-image {
width: 113rpx !important;
height: 24rpx !important;
}
</style>
<style lang="scss">
.reward-wrap {
width: 85vw;
height: auto;
.wrap {
width: 100%;
height: auto;
background-size: 100%;
background-repeat: no-repeat;
padding-bottom: 40rpx;
.birthday-title-name {
font-size: $font-size-toolbar;
font-weight: bold;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
padding-top: 350rpx;
text-align: center;
color: #fff;
line-height: 1;
}
.birthday-title-desc {
font-weight: 500;
margin: 30rpx 70rpx 20rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
text-align: center;
color: #fff;
}
.birthday-title-hint {
font-size: $font-size-toolbar;
font-weight: bold;
font-family: BDZongYi-A001;
display: flex;
align-items: center;
justify-content: center;
margin: 0 0 40rpx;
line-height: 1;
.birthday-img-all {
width: 100rpx;
height: 20rpx;
}
&>view {
margin: 0 20rpx;
color: #fff;
}
}
}
.reward-content {
margin: 0 40rpx;
}
.head {
color: #fff;
text-align: center;
line-height: 1;
margin: 20rpx 0;
}
& .content:last-child {
margin-bottom: 0;
}
.content {
display: flex;
align-items: center;
padding: 16rpx 26rpx;
background: #fff;
border-radius: 10rpx;
margin-bottom: 20rpx;
.info {
flex: 1;
}
.tip {
color: #fa5b14;
padding: 10rpx 0 10rpx 20rpx;
width: 60rpx;
line-height: 1.5;
letter-spacing: 2rpx;
border-left: 2rpx dashed #e5e5e5;
}
.num {
font-size: 48rpx;
color: #fa5b14;
font-weight: bolder;
line-height: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
max-width: 300rpx;
}
.type {
font-size: $font-size-base;
margin-left: 10rpx;
line-height: 1;
font-weight: normal;
color: #606266;
}
.desc {
margin-top: 8rpx;
color: $color-tip;
font-size: $font-size-tag;
line-height: 1;
}
}
.close-btn {
text-align: center;
margin-top: 40rpx;
.btn {
font-size: 40rpx;
color: #fff;
border: 4rpx solid #fff;
border-radius: 50%;
padding: 10rpx;
font-weight: bold;
width: 40rpx;
height: 40rpx;
margin: 0 auto;
line-height: 40rpx;
/* margin: 20rpx 140rpx;
border: none;
background: linear-gradient(90deg, #FF6A00, #FF3C00);
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center; */
}
}
}
</style>

View File

@@ -0,0 +1,345 @@
<template>
<view>
<view @touchmove.prevent.stop v-if="newgift" class="reward-popup">
<uni-popup ref="nsNewGift" type="center" :maskClick="false">
<view class="reward-wrap">
<view class="newgift-content" :style="{ backgroundImage: 'url(' + $util.img('public/uniapp/new_gift/holiday_polite-bg.png') + ')' }">
<view class="content-title-holiday">
<image :src="$util.img('public/uniapp/new_gift/holiday_polite_left.png')" mode="" class="birthday-img-all"/>
<view class="font-size-toolbar activity-name">{{ newgift.activity_name }}</view>
<image :src="$util.img('public/uniapp/new_gift/holiday_polite_right.png')" mode="" class="birthday-img-all"/>
</view>
<view class="content-title-name" v-if="memberInfo">Dear {{ memberInfo.nickname }}</view>
<view class="content-title-hint" v-if="newgift.remark">{{ newgift.remark }}</view>
<view class="content-title-hint" v-else>感谢您一直以来的支持为回馈会员商城{{ newgift.activity_name ? newgift.activity_name : 'xx' }}节日为您提供以下福利</view>
<scroll-view scroll-y="true" class="register-box">
<view :class="introduction > 38 ? 'reward-content' : 'reward-content-two'">
<view class="content" v-if="newgift.award_list.point > 0">
<view class="info">
<text class="num">
{{ newgift.award_list.point }}
<text class="type">积分</text>
</text>
<view class="desc">用于参与活动购买商品时抵扣</view>
</view>
<view class="tip" @click="closeRewardPopup('1')">立即查看</view>
</view>
<view class="content" v-if="newgift.award_list.balance_type == 0 && newgift.award_list.balance > 0">
<view class="info">
<text class="num">
{{ newgift.award_list.balance | int }}
<text class="type">元红包</text>
</text>
<view class="desc">不可提现红包</view>
</view>
<view class="tip" @click="closeRewardPopup('2')">立即查看</view>
</view>
<view class="content" v-if="newgift.award_list.balance_type == 1 && newgift.award_list.balance_money > 0">
<view class="info">
<text class="num">
{{ newgift.award_list.balance_money | int }}
<text class="type">元红包</text>
</text>
<view class="desc">可提现红包</view>
</view>
<view class="tip" @click="closeRewardPopup('2')">立即查看</view>
</view>
<block v-if="newgift.award_list.coupon_list.length > 0">
<block v-for="(item, index) in newgift.award_list.coupon_list" :key="index">
<view class="content">
<view class="info">
<text v-if="item.type == 'reward'" class="num">
{{ parseFloat(item.money) }}
<text class="type">元优惠劵</text>
</text>
<text v-else-if="item.type == 'discount'" class="num">
{{ item.discount | int }}
<text class="type"></text>
</text>
<view class="desc">用于下单时抵现或兑换商品等</view>
</view>
<view class="tip" @click="closeRewardPopup('3')">立即查看</view>
</view>
</block>
</block>
</view>
</scroll-view>
</view>
<view class="close-btn" @click="cancel()">
<text class="iconfont icon-close btn"></text>
</view>
</view>
</uni-popup>
</view>
</view>
</template>
<script>
export default {
data() {
return {
newgift: {
flag: false,
award_list: {
point: 0,
coupon_list: {}
},
remark: {}
},
bgHight: '940rpx !important',
bytesCount: null,
};
},
filters: {
int(val) {
var str = String(val);
var arr = str.split('.');
if (parseInt(arr[1]) > 0) {
return str;
} else {
return arr[0];
}
}
},
computed: {
introduction() {
let bytesCount = 0;
for (let i = 0, n = this.newgift.remark.length; i < n; i++) {
let c = this.newgift.remark.charCodeAt(i);
if ((c >= 0x0001 && c <= 0x007e) || (0xff60 <= c && c <= 0xff9f)) {
bytesCount += 1;
} else {
bytesCount += 2;
}
}
return bytesCount;
}
},
created() {
if (!this.storeToken) return;
this.init();
},
methods: {
init() {
this.getHolidayGift();
},
// 查询节日有礼设置
getHolidayGift() {
this.$api.sendRequest({
url: '/scenefestival/api/config/config',
success: res => {
if (res.data && res.data[0]) {
this.newgift = res.data[0];
if (this.newgift.award_list.award_type.length <= 1) {
this.bgHight = '800rpx !important';
}
this.getGift();
}
}
});
},
cancel() {
this.$refs.nsNewGift.close();
},
getGift() {
if (this.newgift.flag == true) {
this.$refs.nsNewGift.open();
this.$api.sendRequest({
url: '/scenefestival/api/config/receive',
data: {
festival_id: this.newgift.festival_id
},
success: res => {}
});
}
},
closeRewardPopup(type) {
if (type == 1) {
this.$util.redirectTo('/pages_tool/member/point_detail', {});
} else if (type == 2) {
this.$util.redirectTo('/pages_tool/member/balance_detail', {});
} else if (type == 3) {
this.$util.redirectTo('/pages_tool/member/coupon', {});
}
}
}
};
</script>
<style scoped>
/deep/ .newgift-content uni-image {
width: 113rpx !important;
height: 24rpx !important;
}
/deep/ .reward-popup .uni-popup__wrapper.uni-custom.center .uni-popup__wrapper-box {
max-height: unset !important;
overflow-y: unset;
}
.register-box /deep/ .uni-scroll-view {
background: unset !important;
}
.register-box {
max-height: 300rpx;
overflow-y: scroll;
/* margin-top: 610rpx; */
}
</style>
<style lang="scss">
.reward-wrap {
width: 85vw;
height: auto;
.newgift-content {
width: 100%;
height: auto;
background-size: 100%;
background-repeat: no-repeat;
padding-bottom: 40rpx;
}
.content-title-holiday {
font-size: $font-size-toolbar;
font-weight: bold;
font-family: BDZongYi-A001;
display: flex;
align-items: center;
justify-content: center;
// margin-bottom: 20rpx;
padding-top: 320rpx;
line-height: 1;
.birthday-img-all {
width: 100rpx;
height: 20rpx;
}
&>view {
margin: 0 20rpx;
color: #fff;
font-weight: bold;
}
}
.content-title-name {
font-size: $font-size-toolbar;
font-weight: bold;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
text-align: center;
color: #fff;
margin: 30rpx 0 40rpx;
line-height: 1;
}
.content-title-hint {
margin: 0 70rpx 40rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
text-align: center;
color: #fff;
}
.reward-content {
max-height: 300rpx;
margin: 0 56rpx;
}
.reward-content-two {
max-height: 360rpx;
margin: 0 56rpx;
}
.head {
color: #fff;
text-align: center;
line-height: 1;
margin: 20rpx 0;
}
& .content:last-child {
margin-bottom: 0;
}
.content {
display: flex;
align-items: center;
padding: 16rpx 26rpx;
background: #fff;
border-radius: 10rpx;
margin-bottom: 20rpx;
.info {
flex: 1;
}
.tip {
color: #fa5b14;
padding: 10rpx 0 10rpx 20rpx;
width: 60rpx;
line-height: 1.5;
letter-spacing: 2rpx;
border-left: 2rpx dashed #e5e5e5;
}
.num {
font-size: 48rpx;
color: #fa5b14;
font-weight: bolder;
line-height: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 300rpx;
}
.type {
font-size: $font-size-tag;
margin-left: 10rpx;
line-height: 1;
font-weight: normal;
color: #606266;
}
.desc {
margin-top: 8rpx;
color: $color-tip;
font-size: $font-size-tag;
line-height: 1;
}
}
.close-btn {
text-align: center;
margin-top: 20rpx;
z-index: 500;
.btn {
/* margin: 0 50rpx;
background: linear-gradient(90deg,#ff4100,#ff6a00) ;
border: none; */
color: #fff;
font-size: 40rpx;
// padding: 100px;
border: 4rpx solid #fff;
border-radius: 50%;
padding: 10rpx;
font-weight: bold;
width: 40rpx;
height: 40rpx;
margin: 0 auto;
line-height: 40rpx;
}
}
}
</style>

View File

@@ -0,0 +1,928 @@
<template>
<view class="form-wrap form-component">
<view v-for="(item, index) in formData" :key="index">
<!-- 文本输入框 -->
<view v-if="item.controller == 'Text'" class="order-wrap">
<view class="order-cell">
<view class="name">
<text class="tit">{{ item.value.title }}</text>
<text class="required">{{ item.value.required ? '*' : '' }}</text>
</view>
<view class="box">
<input
type="text"
:placeholder="item.value.placeholder"
placeholder-class="placeholder color-tip"
v-model="item.val"
/>
</view>
</view>
</view>
<!-- 多行文本输入框 -->
<view v-if="item.controller == 'Textarea'" class="order-wrap">
<view class="order-cell flex-box textarea">
<view class="name">
<text class="tit">{{ item.value.title }}</text>
<text class="required">{{ item.value.required ? '*' : '' }}</text>
</view>
<view class="box">
<textarea
:placeholder="item.value.placeholder"
placeholder-class="placeholder color-tip"
v-model="item.val"
></textarea>
</view>
</view>
</view>
<!-- 下拉选择器 -->
<view v-if="item.controller == 'Select'" class="order-wrap">
<picker
mode="selector"
:range="item.value.options"
@change="pickerChange($event, index)"
>
<view class="order-cell">
<view class="name">
<text class="tit">{{ item.value.title }}</text>
<text class="required">{{ item.value.required ? '*' : '' }}</text>
</view>
<view class="box">
<text v-if="item.val != ''">{{ item.val }}</text>
<text v-else class="color-tip">请选择</text>
</view>
<text class="iconfont icon-right"></text>
</view>
</picker>
</view>
<!-- 复选框 -->
<view v-if="item.controller == 'Checkbox'" class="order-wrap">
<view class="order-cell">
<view class="name">
<text class="tit">{{ item.value.title }}</text>
<text class="required">{{ item.value.required ? '*' : '' }}</text>
</view>
<view class="box check-group-box">
<checkbox-group @change="checkboxChange($event, index)">
<label v-for="(v, k) in item.option_lists" :key="k">
<checkbox :value="v.value" :checked="v.checked"></checkbox>
<view class="checkbox">
<text
:class="[
'iconfont',
!v.checked ? 'icon-fuxuankuang2' : '',
v.checked ? 'icon-fuxuankuang1 color-base-text' : ''
]"
></text>
{{ v.value }}
</view>
</label>
</checkbox-group>
</view>
</view>
</view>
<!-- 单选框 -->
<view v-if="item.controller == 'Radio'" class="order-wrap">
<view class="order-cell">
<view class="name">
<text class="tit">{{ item.value.title }}</text>
<text class="required">{{ item.value.required ? '*' : '' }}</text>
</view>
<view class="box radio-group-box">
<radio-group @change="radioChange($event, index)">
<label v-for="(v, k) in item.option_lists" :key="k">
<radio :value="v.value" :checked="item.val == v.value"></radio>
<view class="radio-box">
<text
:class="[
'iconfont',
item.val != v.value ? 'icon-yuan_checkbox' : '',
item.val == v.value ? 'icon-yuan_checked color-base-text' : ''
]"
></text>
{{ v.value }}
</view>
</label>
</radio-group>
</view>
</view>
</view>
<!-- 图片上传 -->
<view v-if="item.controller == 'Img'" class="order-wrap">
<view class="order-cell flex-box">
<view class="name">
<text class="tit">{{ item.value.title }}</text>
<text class="required">{{ item.value.required ? '*' : '' }}</text>
</view>
<view class="box img-boxs">
<view v-for="(v, k) in item.img_lists" :key="k" class="img-box" @tap="uploadImg(index)">
<image :src="$util.img(v)" mode="aspectFill"></image>
<text class="iconfont icon-guanbi" @tap.stop="delImg(k, index)"></text>
</view>
<view class="img-box" @tap="addImg(index)">
<text class="iconfont icon-add1"></text>
</view>
</view>
</view>
</view>
<!-- 日期选择器 -->
<view v-if="item.controller == 'Date'" class="order-wrap">
<view class="order-cell">
<view class="name">
<text class="tit">{{ item.value.title }}</text>
<text class="required">{{ item.value.required ? '*' : '' }}</text>
</view>
<view class="box box-flex">
<picker
mode="date"
:value="item.val"
@change="bindDateChange($event, index)"
>
<view :class="['uni-input', !item.val ? 'color-tip' : '']">
{{ item.val ? item.val : item.value.placeholder }}
</view>
</picker>
</view>
<text class="iconfont icon-right"></text>
</view>
</view>
<!-- 日期范围选择器 -->
<view v-if="item.controller == 'Datelimit'" class="order-wrap">
<view class="order-cell flex-box">
<view class="name">
<text class="tit">{{ item.value.title }}</text>
<text class="required">{{ item.value.required ? '*' : '' }}</text>
</view>
<view class="box date-boxs">
<view class="date-box">
<picker
mode="date"
:value="item.start_date"
@change="bindStartDateChange($event, index)"
>
<view class="picker-box">
<view :class="['uni-input', !item.start_date ? 'color-tip' : '']">
{{ item.start_date ? item.start_date : item.value.placeholder_start }}
</view>
</view>
</picker>
</view>
<view class="interval iconfont icon-jian"></view>
<view class="date-box">
<picker
mode="date"
:value="item.end_date"
@change="bindEndDateChange($event, index)"
>
<view class="picker-box">
<view :class="['uni-input', !item.end_date ? 'color-tip' : '']">
{{ item.end_date ? item.end_date : item.value.placeholder_end }}
</view>
</view>
</picker>
</view>
</view>
</view>
</view>
<!-- 时间选择器 -->
<view v-if="item.controller == 'Time'" class="order-wrap">
<view class="order-cell">
<view class="name">
<text class="tit">{{ item.value.title }}</text>
<text class="required">{{ item.value.required ? '*' : '' }}</text>
</view>
<view class="box box-flex">
<picker
mode="time"
:value="item.val"
@change="bindTimeChange($event, index)"
>
<view :class="['uni-input', !item.val ? 'color-tip' : '']">
{{ item.val ? item.val : item.value.placeholder }}
</view>
</picker>
</view>
<text class="iconfont icon-right"></text>
</view>
</view>
<!-- 时间范围选择器 -->
<view v-if="item.controller == 'Timelimit'" class="order-wrap">
<view class="order-cell flex-box">
<view class="name">
<text class="tit">{{ item.value.title }}</text>
<text class="required">{{ item.value.required ? '*' : '' }}</text>
</view>
<view class="box date-boxs">
<view class="date-box">
<picker
mode="time"
:value="item.start_time"
@change="bindStartTimeChange($event, index)"
>
<view class="picker-box">
<view :class="['uni-input', !item.start_time ? 'color-tip' : '']">
{{ item.start_time ? item.start_time : item.value.placeholder_start }}
</view>
</view>
</picker>
</view>
<view class="interval iconfont icon-jian"></view>
<view class="date-box">
<picker
mode="time"
:value="item.end_time"
@change="bindEndTimeChange($event, index)"
>
<view class="picker-box">
<view :class="['uni-input', !item.end_time ? 'color-tip' : '']">
{{ item.end_time ? item.end_time : item.value.placeholder_end }}
</view>
</view>
</picker>
</view>
</view>
</view>
</view>
<!-- 城市选择器 -->
<view v-if="item.controller == 'City'" class="order-wrap">
<view class="order-cell box-flex">
<view class="name">
<text class="tit">{{ item.value.title }}</text>
<text class="required">{{ item.value.required ? '*' : '' }}</text>
</view>
<view class="box">
<pick-regions
:defaultRegions="item.default_regions"
:selectArr="item.select_arr"
@getRegions="handleGetRegions($event, index)"
>
<view :class="['select-address', !item.val ? 'empty' : '', !item.val ? 'color-tip' : '']">
{{ item.val ? item.val : (item.select_arr == '2' ? '请选择省市' : '请选择省市区/县') }}
</view>
</pick-regions>
</view>
<text class="iconfont icon-right"></text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'ns-form',
props: {
data: {
type: Array,
default: () => ({})
},
customAttr: {
type: Object,
default: () => ({})
}
},
data() {
return {
formData: this.data
}
},
created() {
this.setFormData();
},
watch: {
data: {
handler() {
this.setFormData();
},
deep: true
}
},
methods: {
setFormData() {
this.formData = this.data;
this.formData.forEach((item) => {
// 初始化默认值
if (!item.val) {
item.val = item.value.default ? item.value.default : '';
}
// 处理选项列表
if (item.value.options) {
item.option_lists = [];
item.value.options.forEach((option, index) => {
let optionItem = {};
optionItem.value = option;
optionItem.checked = false;
if (item.controller == 'Radio') {
if ((!item.val && index == 0) || (item.val && item.val == option)) {
optionItem.checked = true;
item.val = option;
}
}
if (item.controller == 'Checkbox' && item.val) {
let valArray = item.val.split(',');
optionItem.checked = valArray.indexOf(option) != -1;
}
item.option_lists.push(optionItem);
});
}
// 处理图片列表
if (item.controller == 'Img') {
item.img_lists = item.val ? item.val.split(',') : [];
}
// 处理日期
if (item.controller == 'Date' && !item.val) {
if (item.value.is_show_default) {
if (item.value.is_current) {
item.val = this.getDate();
} else {
item.val = item.value.default;
}
} else {
item.val = '';
}
}
// 处理日期范围
if (item.controller == 'Datelimit') {
if (item.val) {
let dateArray = item.val.split(' - ');
item.start_date = dateArray[0];
item.end_date = dateArray[1];
} else {
item.val = '';
// 开始日期
if (item.value.is_show_default_start) {
if (item.value.is_current_start) {
item.start_date = this.getDate();
} else {
item.start_date = item.value.default_start;
}
} else {
item.start_date = '';
}
// 结束日期
if (item.value.is_show_default_end) {
if (item.value.is_current_end) {
item.end_date = this.getDate();
} else {
item.end_date = item.value.default_end;
}
} else {
item.end_date = '';
}
if (item.start_date && item.end_date) {
item.val = item.start_date + ' - ' + item.end_date;
}
}
}
// 处理时间
if (item.controller == 'Time' && !item.val) {
if (item.value.is_show_default) {
if (item.value.is_current) {
item.val = this.getTime();
} else {
item.val = item.value.default;
}
} else {
item.val = '';
}
}
// 处理时间范围
if (item.controller == 'Timelimit') {
if (item.val) {
let timeArray = item.val.split(' - ');
item.start_time = timeArray[0];
item.end_time = timeArray[1];
} else {
item.val = '';
// 开始时间
if (item.value.is_show_default_start) {
if (item.value.is_current_start) {
item.start_time = this.getTime();
} else {
item.start_time = item.value.default_start;
}
} else {
item.start_time = '';
}
// 结束时间
if (item.value.is_show_default_end) {
if (item.value.is_current_end) {
item.end_time = this.getTime();
} else {
item.end_time = item.value.default_end;
}
} else {
item.end_time = '';
}
if (item.start_time && item.end_time) {
item.val = item.start_time + ' - ' + item.end_time;
}
}
}
// 处理城市选择
if (item.controller == 'City') {
item.full_address = '';
item.select_arr = item.value.default_type == 1 ? '2' : '3';
if (item.val) {
item.default_regions = item.val.split('-');
} else {
item.default_regions = [];
}
}
});
},
// 表单验证
verify() {
for (let i = 0; i < this.formData.length; i++) {
let item = this.formData[i];
// 文本验证
if (item.controller == 'Text') {
if (item.value.required && !item.val) {
this.$util.showToast({ title: '请输入' + item.value.title });
return false;
}
if (item.name == 'ID_CARD' && !/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(item.val)) {
if (!item.value.required) {
this.$util.showToast({ title: '身份证输入不合法' });
return false;
}
if (item.val != '') {
this.$util.showToast({ title: '身份证输入不合法' });
return false;
}
}
if (item.name == 'MOBILE' && !this.$util.verifyMobile(item.val)) {
if (!item.value.required) {
this.$util.showToast({ title: '手机号输入不合法' });
return false;
}
if (item.val != '') {
this.$util.showToast({ title: '手机号输入不合法' });
return false;
}
}
}
// 多行文本验证
if (item.controller == 'Textarea' && item.value.required && !item.val) {
this.$util.showToast({ title: '请输入' + item.value.title });
return false;
}
// 下拉选择验证
if (item.controller == 'Select' && item.value.required && !item.val) {
this.$util.showToast({ title: '请选择' + item.value.title });
return false;
}
// 复选框验证
if (item.controller == 'Checkbox' && item.value.required && !item.val) {
this.$util.showToast({ title: '请至少选择一个' + item.value.title });
return false;
}
// 图片上传验证
if (item.controller == 'Img' && item.value.required && !item.val) {
this.$util.showToast({ title: '请至少上传一张' + item.value.title });
return false;
}
// 日期验证
if (item.controller == 'Date' && item.value.required && !item.val) {
this.$util.showToast({ title: '请选择' + item.value.title });
return false;
}
// 日期范围验证
if (item.controller == 'Datelimit') {
if (item.value.required && !item.val) {
this.$util.showToast({ title: '请选择' + item.value.title });
return false;
}
if (this.$util.timeTurnTimeStamp(item.start_date) > this.$util.timeTurnTimeStamp(item.end_date)) {
this.$util.showToast({ title: '结束日期不能小于开始日期' });
return false;
}
}
// 时间验证
if (item.controller == 'Time' && item.value.required && !item.val) {
this.$util.showToast({ title: '请选择' + item.value.title });
return false;
}
// 时间范围验证
if (item.controller == 'Timelimit') {
if (item.value.required && !item.val) {
this.$util.showToast({ title: '请选择' + item.value.title });
return false;
}
if (item.start_time >= item.end_time) {
this.$util.showToast({ title: '结束时间必须大于开始时间' });
return false;
}
}
// 城市选择验证
if (item.controller == 'City' && item.value.required && !item.val) {
this.$util.showToast({ title: '请选择' + item.value.title });
return false;
}
}
return this.formData;
},
// 下拉选择改变
pickerChange(event, index) {
this.formData[index].val = this.data[index].value.options[event.detail.value];
this.$forceUpdate();
},
// 复选框改变
checkboxChange(event, index) {
this.formData[index].val = event.detail.value.toString();
this.formData[index].option_lists.forEach((option) => {
option.checked = event.detail.value.indexOf(option.value) != -1;
});
this.$forceUpdate();
},
// 单选框改变
radioChange(event, index) {
this.formData[index].val = event.detail.value;
this.$forceUpdate();
},
// 上传图片
uploadImg(index) {
let self = this;
this.$util.upload(Number(this.formData[index].value.max_count), { path: 'evaluateimg' }, function(res) {
if (res.length > 0) {
res.forEach(function(img) {
if (self.formData[index].img_lists.length >= Number(self.formData[index].value.max_count)) {
self.$util.showToast({ title: '最多上传' + self.formData[index].value.max_count + '张图片' });
return false;
}
self.formData[index].img_lists.push(img);
});
self.formData[index].val = self.formData[index].img_lists.toString();
self.$forceUpdate();
}
});
},
// 添加图片
addImg(index) {
let self = this;
if (this.formData[index].img_lists.length >= Number(this.formData[index].value.max_count)) {
this.$util.showToast({ title: '最多上传' + this.formData[index].value.max_count + '张图片' });
return false;
}
this.$util.upload(Number(this.formData[index].value.max_count), { path: 'evaluateimg' }, function(res) {
if (res.length > 0) {
res.forEach(function(img) {
self.formData[index].img_lists.push(img);
});
self.formData[index].val = self.formData[index].img_lists.toString();
self.$forceUpdate();
}
});
},
// 删除图片
delImg(imgIndex, formIndex) {
this.formData[formIndex].img_lists.splice(imgIndex, 1);
this.formData[formIndex].val = this.formData[formIndex].img_lists.toString();
this.$forceUpdate();
},
// 获取当前日期
getDate() {
let date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
month = month > 9 ? month : '0' + month;
day = day > 9 ? day : '0' + day;
return `${year}-${month}-${day}`;
},
// 获取当前时间
getTime() {
let date = new Date();
let hours = date.getHours();
let minutes = date.getMinutes();
hours = hours > 9 ? hours : '0' + hours;
minutes = minutes > 9 ? minutes : '0' + minutes;
return `${hours}:${minutes}`;
},
// 日期改变
bindDateChange(event, index) {
this.formData[index].val = event.detail.value;
this.$forceUpdate();
},
// 开始日期改变
bindStartDateChange(event, index) {
this.$set(this.formData[index], 'start_date', event.detail.value);
this.$set(this.formData[index], 'val', this.formData[index].start_date + ' - ' + this.formData[index].end_date);
this.$forceUpdate();
},
// 结束日期改变
bindEndDateChange(event, index) {
this.$set(this.formData[index], 'end_date', event.detail.value);
this.$set(this.formData[index], 'val', this.formData[index].start_date + ' - ' + this.formData[index].end_date);
this.$forceUpdate();
},
// 时间改变
bindTimeChange(event, index) {
this.formData[index].val = event.detail.value;
this.$forceUpdate();
},
// 开始时间改变
bindStartTimeChange(event, index) {
this.formData[index].start_time = event.detail.value;
this.$forceUpdate();
},
// 结束时间改变
bindEndTimeChange(event, index) {
this.formData[index].end_time = event.detail.value;
this.formData[index].val = this.formData[index].start_time + ' - ' + this.formData[index].end_time;
this.$forceUpdate();
},
// 处理地区选择
handleGetRegions(regions, index) {
this.formData[index].val = '';
this.formData[index].val += regions[0] != undefined ? regions[0].label : '';
this.formData[index].val += regions[1] != undefined ? '-' + regions[1].label : '';
this.formData[index].val += regions[2] != undefined ? '-' + regions[2].label : '';
this.$forceUpdate();
}
}
}
</script>
<style lang="scss" scoped>
.order-wrap {
padding: 20rpx 0;
&:last-child {
margin-bottom: 0;
border-bottom: 0;
}
.order-cell {
align-items: center;
background: #fff;
position: relative;
&.textarea {
align-items: unset;
}
&.clear-flex {
display: block;
.box {
margin-top: 16rpx;
text-align: left;
}
}
&:last-child {
margin-bottom: 0;
border-bottom: solid 1px #eee;
}
&.align-top {
align-items: flex-start;
}
text {
font-size: 28rpx;
}
.name {
width: 160rpx;
margin-bottom: 10rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.tit {
text-align: left;
font-size: 32rpx;
color: #888;
text {
font-size: 28rpx;
}
}
.required {
color: red;
font-size: 28rpx;
margin-left: 4rpx;
width: 14rpx;
text-align: left;
display: inline-block;
}
}
.box {
flex: 1;
padding: 0 0rpx;
line-height: inherit;
text-align: left;
input {
font-size: 28rpx;
text-align: left;
height: 70rpx;
border: solid 2rpx #eee;
line-height: 70rpx;
padding: 0 16rpx;
}
textarea {
font-size: 28rpx;
width: 100%;
height: 88rpx;
line-height: 44rpx;
text-align: left;
}
checkbox-group {
display: flex;
flex-wrap: wrap;
}
radio-group {
display: flex;
flex-wrap: wrap;
}
label {
display: flex;
align-items: center;
line-height: 1;
margin-right: 30rpx;
}
&.img-boxs {
display: flex;
align-items: center;
flex-wrap: wrap;
.img-box {
margin: 10rpx 20rpx 10rpx 0;
display: flex;
justify-content: center;
align-items: center;
width: 100rpx;
height: 100rpx;
border: 1rpx solid #eee;
border-radius: 4rpx;
position: relative;
.icon-guanbi {
position: absolute;
top: -14rpx;
right: -14rpx;
display: inline-block;
width: 28rpx;
height: 28rpx;
line-height: 28rpx;
color: #909399;
}
.icon-add1 {
font-size: 40rpx;
}
image {
width: 100%;
height: 100%;
}
}
}
&.box-flex {
display: flex;
align-items: center;
justify-content: space-between;
}
&.date-boxs {
padding: 0 10rpx;
display: flex;
align-items: center;
.interval {
margin: 0 12rpx;
color: #000;
font-weight: 700;
}
.date-box {
.picker-box {
display: flex;
align-items: center;
justify-content: flex-end;
}
}
}
}
.radio-group-box {
radio {
display: none;
}
.radio-box {
display: flex;
align-items: center;
line-height: 1;
.iconfont {
font-size: 32rpx;
margin-right: 10rpx;
}
}
}
.check-group-box {
checkbox {
display: none;
}
.checkbox {
display: flex;
align-items: center;
line-height: 1;
.iconfont {
font-size: 32rpx;
margin-right: 10rpx;
}
}
}
.iconfont {
color: #909399;
font-size: 28rpx;
}
.box-flex {
picker {
display: block;
width: 100%;
}
}
.icon-right {
line-height: 1;
position: unset;
}
}
}
</style>

View File

@@ -0,0 +1,6 @@
export function getClientRect(selector, component) {
return new Promise((resolve, reject) => {
let query = component ? uni.createSelectorQuery().in(component) : uni.createSelectorQuery();
return query.select(selector).boundingClientRect(resolve).exec()
})
}

Binary file not shown.

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<!--
2013-9-30: Created.
-->
<svg>
<metadata>
Created by iconfont
</metadata>
<defs>
<font id="iconfont" horiz-adv-x="1024" >
<font-face
font-family="iconfont"
font-weight="500"
font-stretch="normal"
units-per-em="1024"
ascent="896"
descent="-128"
/>
<missing-glyph />
<glyph glyph-name="star" unicode="&#59107;" d="M544.256 812.032l117.248-237.568c5.12-10.752 15.36-17.92 27.136-19.456l262.144-37.888c29.696-4.096 41.472-40.448 19.968-61.44l-189.44-184.832c-8.704-8.192-12.288-19.968-10.24-31.744l44.544-261.12c5.12-29.184-25.6-51.712-52.224-37.888l-234.496 123.392c-10.24 5.632-23.04 5.632-33.28 0L261.12-59.904c-26.112-13.824-57.344 8.704-52.224 37.888l44.544 261.12c2.048 11.776-2.048 23.552-10.24 31.744L53.76 455.68C32.256 476.16 44.032 512.512 73.728 517.12l262.144 37.888c11.776 1.536 22.016 9.216 27.136 19.456l117.248 237.568C493.056 838.656 530.944 838.656 544.256 812.032z" horiz-adv-x="1024" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,22 @@
@font-face {
font-family: "iconfont";
src: url('./fonts/iconfont.eot?t=1574760464482'); /* IE9 */
src: url('./fonts/iconfont.eot?t=1574760464482#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAK8AAsAAAAABnAAAAJwAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCCcAp8gQgBNgIkAwgLBgAEIAWEbQcuG6wFyA4lTcHACOEZBUg8fL/2O3f3fTHEkoh28SSayCSxkkgQG6Uz3UvYITu9Qr5K0Vh6Ij6f+8CXKzVBHDvWa6d0lSfK57mc3gQ6kGt8oBz3ojUG9QLqxYEU6B4YRVYqecPYBS7hMYG6QWF0dlOycoGxxFoViFuxkALGuYAksXRVKNccTOJdSTV7zbSAt/D78Y8XxmRKOavq5CZZAOK+7u2svLVode0TggR0vIQc84BEXNQmjugJxumpJ/SNAvsqD77ui8K3i71aBPvrrNIm6IfSe5K58ltNZ3BbU40Blkf9OmKsIW/Un1qddc4dcSma3ArIX7PPXdlxK5l2zJ+aD6TXnQqmu330wqpeWkYN/OnNm/0trU+YvqNR4UN99f+x/tApIFTfR7u39X4gKPnb9pOX5RAQB6DYyc/zOKCD4OUp6KiiPeqnapbAp56NdegrdhLo5wKq+3UG/0fWcyDpCsuWJVVWO5oZO29bXR0FwJ4uV2ONvTeTCVW9I1wVAylyVeNkYudR0rCOsqoN1M1JPd7QDdMTqYZZXQChwwYybT6Q63BIJvYSJX1eUNYReqi7CrsLGyZDbJqIEUWQAPLroJhWKhjHQUyj8mwkrJJROKsI+XyENeIw5LI4xXQqUiA8xxZNtZBHCAMZrJTDFPAcksmUUIWVEkQTlogQVQSbzdS9iUUr5cDUDgyhEIgAxFcHEqMpKTD+eMK09PlsiFAVGQpu6atJ5kMwDfHsEBcLpweZqlX06ruXVzSqCfEQBANiYEpyUAqYh8jIKEGq+nkSCI1gEY2IqURg28OYvlrW+nr5152AOsuUhV2fSy+EwgAAAA==') format('woff2'),
url('./fonts/iconfont.woff?t=1574760464482') format('woff'),
url('./fonts/iconfont.ttf?t=1574760464482') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */
url('./fonts/iconfont.svg?t=1574760464482#iconfont') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family: "iconfont" !important;
font-size: inherit;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-star:before {
content: "\e6e3";
}

View File

@@ -0,0 +1,218 @@
<template>
<view class="rate-box" :class="[{ animation }, containerClass]" @touchmove="ontouchmove" @touchend="touchMoving = false">
<view
v-for="(val, i) in list"
:key="val"
class="rate"
:style="{ fontSize, paddingLeft: i !== 0 ? rateMargin : 0, paddingRight: i < list.length - 1 ? rateMargin : 0 }"
:class="[
{ scale: !disabled && val <= rateValue && animation && touchMoving, 'color-base-text': val <= rateValue, defaultColor: val > rateValue },
`rate-${i}`,
rateClass
]"
:data-val="val"
@click="onItemClick"
>
<text class="iconfont icon-star"></text>
</view>
</view>
</template>
<script>
import { getClientRect } from './common';
export default {
name: 'sx-rate',
props: {
// 当前值
value: {
type: [Number, String]
},
// 最大星星数量
max: {
type: Number,
default: 5
},
// 禁用
disabled: {
type: Boolean,
default: false
},
// 动画效果
animation: {
type: Boolean,
default: true
},
// 默认星星颜色
defaultColor: {
type: String,
default: '#ccc'
},
// 滑选后星星颜色
activeColor: {
type: String
// default: '#FFB700'
},
// 星星大小
fontSize: {
type: String,
default: 'inherit'
},
// 星星间距
margin: {
type: String,
default: ''
},
// 自定义类名-容器
containerClass: {
type: String,
default: ''
},
// 自定义类名-星星
rateClass: {
type: String,
default: ''
},
index: {
// 如果页面中存在多个该组件,通过该属性区分
type: [Number, String]
}
},
data() {
return {
rateValue: 0,
touchMoving: false,
startX: [],
startW: 30
};
},
computed: {
list() {
return [...new Array(this.max)].map((_, i) => i + 1);
},
rateMargin() {
let margin = this.margin;
if (!margin) return 0;
switch (typeof margin) {
case 'number':
margin = margin * 2 + 'rpx';
case 'string':
break;
default:
return 0;
}
let reg = /^(\d+)([^\d]*)/;
let result = reg.exec(margin);
if (!result) return 0;
let [_, num, unit] = result;
return num / 2 + unit;
}
},
watch: {
value: {
handler(val) {
this.rateValue = val;
},
immediate: true
}
},
methods: {
// 计算星星位置
async initStartX() {
let { max } = this;
this.startX = [];
for (let i = 0; i < max; i++) {
let selector = `.rate-${i}`;
let { left, width } = await getClientRect(selector, this);
this.startX.push(left);
this.startW = width;
}
},
/**
* 手指滑动事件回调
* https://github.com/sunxi1997/uni-app-sx-rate/pull/1
* 原本的触摸处理在自定了样式后可能会出现bug, 已解决
*/
async ontouchmove(e) {
if (!this.touchMoving) {
this.touchMoving = true;
// 开始手指滑动时重新计算星星位置,防止星星位置意外变化
await this.initStartX();
}
let { startX, startW, max } = this;
let { touches } = e;
// 触摸焦点停留的位置
let { pageX } = touches[touches.length - 1];
// 超出最左边, 0 星
if (pageX <= startX[0]) return this.toggle(0);
// 刚好在第一颗星
else if (pageX <= startX[0] + startW) return this.toggle(1);
// 超出最右边, 最大星
else if (pageX >= startX[max - 1]) return this.toggle(max);
//计算星星停留的位置
let startXHash = startX.concat(pageX).sort((a, b) => a - b);
this.toggle(startXHash.indexOf(pageX));
},
// 点击回调
onItemClick(e) {
let { val } = e.currentTarget.dataset;
this.toggle(val);
},
// 修改值
toggle(val) {
let { disabled } = this;
if (disabled) return;
if (this.rateValue !== val) {
this.rateValue = val;
this.$emit('update:value', val);
let data = {
index: this.index,
value: val
};
this.$emit('change', data);
}
}
},
mounted() {}
};
</script>
<style scoped>
@import './iconfont.css';
</style>
<style lang="scss" scoped>
.rate-box {
min-height: 1.4em;
display: flex;
align-items: center;
}
.rate {
display: inline-flex;
justify-content: center;
align-items: center;
width: 1.2em;
transition: all 0.15s linear;
}
.rate.scale {
transform: scale(1.1);
}
.defaultColor {
color: #ccc !important;
}
.activeColor {
}
</style>