价格显示问题
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
"name" : "心灵空间",
|
||||
"appid" : "__UNI__BBBDFD2",
|
||||
"description" : "心灵空间",
|
||||
"versionName" : "1.0.11",
|
||||
"versionCode" : 1011,
|
||||
"versionName" : "1.0.22",
|
||||
"versionCode" : 1022,
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
@@ -30,7 +30,7 @@
|
||||
"prompt" : "template",
|
||||
"template" : {
|
||||
"title" : "用户协议和隐私政策",
|
||||
"message" : "请你务必审慎阅读、充分理解“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/> 你可阅读<a href='https://soulspace.taihumed.com/agreement.html'>《用户协议》</a>和<a href='https://soulspace.taihumed.com/privacy.html'>《隐私协议》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。",
|
||||
"message" : "请你务必审慎阅读、充分理解“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。<br/>你可阅读<a href='https://soulspace.taihumed.com/agreement.html'>《用户协议》</a>和<a href='https://soulspace.taihumed.com/privacy.html'>《隐私协议》</a>了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。",
|
||||
"buttonAccept" : "同意",
|
||||
"buttonRefuse" : "暂不同意"
|
||||
}
|
||||
@@ -56,7 +56,8 @@
|
||||
],
|
||||
"minSdkVersion" : 23,
|
||||
"targetSdkVersion" : 35,
|
||||
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ]
|
||||
"abiFilters" : [ "armeabi-v7a", "arm64-v8a", "x86" ],
|
||||
"schemes" : "soulspace"
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {
|
||||
@@ -70,13 +71,14 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"idfa" : false,
|
||||
"plistcmds" : [ "Delete :NSUserTrackingUsageDescription" ],
|
||||
"idfa" : true,
|
||||
"privacyDescription" : {
|
||||
"NSPhotoLibraryUsageDescription" : "保障您在此app中的修改头像、申诉反馈上传图片功能的正常使用",
|
||||
"NSPhotoLibraryAddUsageDescription" : "保障您在此app中的修改头像、申诉反馈上传图片功能的正常使用",
|
||||
"NSCameraUsageDescription" : "保障您在此app中的修改头像、申诉反馈上传图片功能的正常使用"
|
||||
}
|
||||
"NSCameraUsageDescription" : "保障您在此app中的修改头像、申诉反馈上传图片功能的正常使用",
|
||||
"NSUserTrackingUsageDescription" : "请放心,开启权限不会获取您在其他站点的隐私信息,该权限仅用于标识设备并保障服务安全与提示浏览体验"
|
||||
},
|
||||
"urltypes" : "soulspace"
|
||||
},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {
|
||||
|
||||
15
pages.json
15
pages.json
@@ -412,6 +412,21 @@
|
||||
"popGesture": "none"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "uni_modules/uni-upgrade-center-app/pages/upgrade-popup",
|
||||
"style": {
|
||||
"app-plus": {
|
||||
"animationDuration": 200,
|
||||
"animationType": "fade-in",
|
||||
"background": "transparent",
|
||||
"backgroundColorTop": "transparent",
|
||||
"popGesture": "none",
|
||||
"scrollIndicator": false,
|
||||
"titleNView": false
|
||||
},
|
||||
"disableScroll": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"tabBar": {
|
||||
|
||||
@@ -14,15 +14,15 @@
|
||||
|
||||
<view :class="`common_radius_box goods_box popup_content`">
|
||||
<view class="title title_box">
|
||||
<!-- <view class="title_price" v-if="selectGoodsData.isVipPrice==1&&selectGoodsData.vipPrice!=null&&selectGoodsData.vipPrice!=0">
|
||||
<view class="title_price" v-if="selectGoodsData.isVipPrice==1&&selectGoodsData.vipPrice!=null&&selectGoodsData.vipPrice!=0">
|
||||
¥{{selectGoodsData.vipPrice}}
|
||||
<text style=" font-weight: normal; padding-left: 15rpx; font-size: 26rpx;">VIP到手价</text>
|
||||
</view>
|
||||
<view class="title_price" v-else-if="selectGoodsData.activityPrice&&selectGoodsData.activityPrice>0">
|
||||
¥{{selectGoodsData.activityPrice}}
|
||||
<text style=" font-weight: normal; padding-left: 15rpx; font-size: 26rpx; color: #999;">活动价</text>
|
||||
</view> -->
|
||||
<text class="title_price">
|
||||
</view>
|
||||
<text class="title_price" v-else>
|
||||
¥{{selectGoodsData.price}}
|
||||
</text>
|
||||
<u-icon
|
||||
@@ -68,20 +68,11 @@
|
||||
<view :class="`goods_info `">
|
||||
<view class="name">{{ slotProps.row.productName }}</view>
|
||||
<view class="price">
|
||||
<!-- <view class="goods_price" v-if="slotProps.row.isVipPrice==1&&slotProps.row.vipPrice!=null&&slotProps.row.vipPrice!=0">
|
||||
¥{{slotProps.row.vipPrice}}
|
||||
<text class="line_text">¥{{slotProps.row.price}}</text>
|
||||
</view>
|
||||
<view class="goods_price" v-else-if="slotProps.row.activityPrice&&slotProps.row.activityPrice>0">
|
||||
¥{{slotProps.row.activityPrice}}
|
||||
<text class="line_text">¥{{slotProps.row.price}}</text>
|
||||
</view> -->
|
||||
<text>
|
||||
¥{{slotProps.row.price}}
|
||||
</text>
|
||||
<!-- <text class="goods_text" v-if="slotProps.row.isVipPrice==1&&slotProps.row.vipPrice!=null&&slotProps.row.vipPrice!=0">
|
||||
<text v-html="getPrice(slotProps)"></text>
|
||||
|
||||
<text class="goods_text" v-if="slotProps.row.isVipPrice==1&&slotProps.row.vipPrice!=null&&slotProps.row.vipPrice!=0">
|
||||
VIP优惠
|
||||
</text> -->
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -129,6 +120,38 @@ export default {
|
||||
...mapState(["userInfo"]),
|
||||
},
|
||||
methods: {
|
||||
getPrice(slotProps) {
|
||||
if (
|
||||
Number(slotProps.row.isVipPrice) === 1 &&
|
||||
Number(slotProps.row.vipPrice) > 0
|
||||
) {
|
||||
return `
|
||||
<text style="color: #e97512; font-size: 28rpx; font-weight: bold;">
|
||||
¥${Number(slotProps.row.vipPrice).toFixed(2)}
|
||||
</text>
|
||||
<text
|
||||
style="color: #8a8a8a; font-size: 22rpx; margin-left: 4px; font-weight: bold; text-decoration: line-through;"
|
||||
>
|
||||
¥${Number(slotProps.row.price).toFixed(2)}
|
||||
</text>
|
||||
`;
|
||||
} else if (Number(slotProps.row.activityPrice) > 0) {
|
||||
return `
|
||||
<text style="color: #e97512; font-size: 28rpx; font-weight: bold;">
|
||||
¥${Number(slotProps.row.activityPrice).toFixed(2)}
|
||||
</text>
|
||||
<text
|
||||
style="color: #8a8a8a; font-size: 22rpx; margin-left: 4px; font-weight: bold; text-decoration: line-through;"
|
||||
>
|
||||
¥${Number(slotProps.row.price).toFixed(2)}
|
||||
</text>
|
||||
`;
|
||||
} else {
|
||||
return `<span style="color: #e97512;font-size: 28rpx;font-weight: bold;">
|
||||
¥${Number(slotProps.row.price).toFixed(2)}</span>
|
||||
`;
|
||||
}
|
||||
},
|
||||
// 放大图片
|
||||
previewImage(url) {
|
||||
console.log(url);
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
</view>
|
||||
</z-nav-bar>
|
||||
<view class="cateList">
|
||||
<view class="labels_block" v-if="id!=75&&labelsList.length>0">
|
||||
<!-- <view class="labels_block" v-if="labelsList.length>0" :style="`top: ${45 + statusBarHeight}px;`"> -->
|
||||
<view class="labels_block" v-if="labelsList.length>0" :style="`top: ${45 + statusBarHeight}px;`">
|
||||
<view class="labels_item"
|
||||
:style="{ width: labelsList.length > 0 ? `${100 / labelsList.length}%` : '100%' }"
|
||||
v-for="(tabData,tabIndex) in labelsList" :key="tabIndex"
|
||||
@@ -54,7 +53,7 @@
|
||||
<text v-if="statusNull" class="text_null">暂无数据</text>
|
||||
</view>
|
||||
|
||||
<view class="xlcp_block" :class="XL_id==78?'xlcp_block_2':''" v-if="statusXLCP" style=" margin-top: 0;">
|
||||
<view class="xlcp_block" :class="XL_id==78?'xlcp_block_2':''" v-if="statusXLCP">
|
||||
<view class="form_block" v-if="XL_id==77">
|
||||
<view class="form_item" v-for="(item,index) in formList" :key="index">
|
||||
<text class="form_title">{{item.title}}</text>
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
</span>
|
||||
<span>¥</span>{{ orderContet.shippingMoney }}
|
||||
</view>
|
||||
<!-- <view class="orderReal" v-if="orderContet.orderType == 'order'&&orderContet.vipDiscountAmount&&orderContet.vipDiscountAmount>0">
|
||||
<view class="orderReal" v-if="orderContet.orderType == 'order'&&orderContet.vipDiscountAmount&&orderContet.vipDiscountAmount>0">
|
||||
<span style="color: red; margin-right: 10rpx; float: left;">VIP专享立减 :
|
||||
</span>
|
||||
<span style=" color: red;">-¥{{orderContet.vipDiscountAmount}}</span>
|
||||
@@ -162,18 +162,76 @@
|
||||
<span style="color: red; margin-right: 10rpx; float: left;">活动立减 :
|
||||
</span>
|
||||
<span style=" color: red;">-¥{{orderContet.districtMoney}}</span>
|
||||
</view> -->
|
||||
<view class="orderReal" v-if="orderContet.orderType == 'order'">
|
||||
<span style="color: #666; margin-right: 10rpx; float: left">积分 :
|
||||
</view>
|
||||
<view class="orderReal" v-if="orderContet.jfDeduction > 0">
|
||||
<span style="color: #666; margin-right: 10rpx; float: left"
|
||||
>积分抵扣:
|
||||
</span>
|
||||
<span v-if="orderContet.jfDeduction > 0">-</span> <span>¥</span>{{ orderContet.jfDeduction }}
|
||||
<span style="color: #fa2d12" v-if="orderContet.jfDeduction > 0"
|
||||
>- </span
|
||||
>
|
||||
<span style="color: #fa2d12"> {{ orderContet.jfDeduction }}</span>
|
||||
</view>
|
||||
<view
|
||||
class="orderReal"
|
||||
v-if="orderContet.paymentMethod == 4 && orderContet.realMoney > 0"
|
||||
>
|
||||
<span style="color: #666; margin-right: 10rpx; float: left"
|
||||
>天医币抵扣:
|
||||
</span>
|
||||
<span style="color: #fa2d12">- </span>
|
||||
<span style="color: #fa2d12">¥{{ orderContet.realMoney }}</span>
|
||||
</view>
|
||||
|
||||
<view class="orderReal" v-if="orderContet.orderStatus != 0">
|
||||
<span style="color: #666; margin-right: 10rpx; float: left">
|
||||
实付款:
|
||||
</span>
|
||||
<b style="color: red;"><span>¥</span>{{ orderContet.realMoney }}</b>
|
||||
<b v-if="orderContet.orderType == 'point'" style="color: #dd3c0c"
|
||||
>¥ {{ orderContet.bookBuyConfigEntity.realMoney }}</b
|
||||
>
|
||||
<b style="color: #dd3c0c" v-else>
|
||||
<template v-if="orderContet.realMoney > 0&&orderContet.jfDeduction>0">
|
||||
¥{{ orderContet.realMoney }}
|
||||
|
||||
<text style="font-size: 24rpx;margin-left: 10rpx;">
|
||||
<span
|
||||
style=""
|
||||
v-if="orderContet.paymentMethod == 1"
|
||||
>微信支付</span
|
||||
>
|
||||
<span
|
||||
style=""
|
||||
v-if="orderContet.paymentMethod == 2"
|
||||
>支付宝支付</span
|
||||
>
|
||||
<span
|
||||
style=""
|
||||
v-if="orderContet.paymentMethod == 3"
|
||||
>苹果支付</span
|
||||
>
|
||||
<span
|
||||
style=""
|
||||
v-if="orderContet.paymentMethod == 4"
|
||||
>
|
||||
天医币支付
|
||||
</span>
|
||||
</text>
|
||||
</template>
|
||||
<template v-if="orderContet.realMoney == 0&&orderContet.jfDeduction==0">¥0</template>
|
||||
<text
|
||||
style="margin: 0 4rpx"
|
||||
v-if="
|
||||
orderContet.realMoney > 0 && orderContet.jfDeduction > 0
|
||||
"
|
||||
>
|
||||
+
|
||||
</text>
|
||||
|
||||
<text v-if="orderContet.jfDeduction > 0"
|
||||
>{{ orderContet.jfDeduction }} 积分</text
|
||||
>
|
||||
</b>
|
||||
</view>
|
||||
<view class="orderReal" v-if="orderContet.remark">
|
||||
<span style="color: #666; margin-right: 10rpx; float: left">
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<view class="goods_box">
|
||||
<view class="curriulum_title_box">
|
||||
<view v-if="this.options.isMiaosha == 1" class="miaosha_box">
|
||||
<!-- <view class="price_box"
|
||||
<view class="price_box"
|
||||
v-if="curriculumData.isVipPrice==1&&curriculumData.vipPrice!=null&&curriculumData.vipPrice!=0
|
||||
||curriculumData.activityPrice && curriculumData.activityPrice > 0">
|
||||
<view class="price_left">
|
||||
@@ -44,8 +44,8 @@
|
||||
</text>
|
||||
<text class="xianshimaiosha" v-else-if="curriculumData.activityPrice && curriculumData.activityPrice > 0">活动立减</text>
|
||||
</view>
|
||||
</view> -->
|
||||
<view class="putong">
|
||||
</view>
|
||||
<view class="putong" v-else>
|
||||
<template>
|
||||
<text class="aui-text-danger price">
|
||||
¥{{ curriculumData.price }}
|
||||
|
||||
@@ -27,14 +27,14 @@
|
||||
|
||||
<view class="order_top common_radius_box color_shandow goods_box">
|
||||
<view class="curriulum_title_box goods_item" style=" position: relative;" v-for="(v, i) in goodsDataList">
|
||||
<!-- <text class="goods_item_vip" v-if="v.isVipPrice==1&&v.vipPrice!=null&&v.vipPrice!=0">VIP优惠</text> -->
|
||||
<text class="goods_item_vip" v-if="v.isVipPrice==1&&v.vipPrice!=null&&v.vipPrice!=0">VIP优惠</text>
|
||||
<image class="goods_item_img" :src="v.productImages" mode="aspectFit">
|
||||
</image>
|
||||
<view class="normal_box">
|
||||
<view class="normal_box_top">
|
||||
<view class="curriulum_title">{{ v.productName }} </view>
|
||||
<view class="price_box">
|
||||
<!-- <view class="vip_price" v-if="v.isVipPrice==1&&v.vipPrice!=null&&v.vipPrice!=0">
|
||||
<view class="vip_price" v-if="v.isVipPrice==1&&v.vipPrice!=null&&v.vipPrice!=0">
|
||||
<text class="vip_price_jg">¥{{ v.vipPrice }}</text>
|
||||
<text class="vip_price_text">VIP到手价</text>
|
||||
<text class="vip_price_line">¥{{ v.price }}</text>
|
||||
@@ -43,8 +43,8 @@
|
||||
<text class="vip_price_jg">¥{{ v.activityPrice }}</text>
|
||||
<text class="vip_price_text">活动价</text>
|
||||
<text class="vip_price_line">¥{{ v.price }}</text>
|
||||
</text> -->
|
||||
<text>¥{{ v.price }}</text>
|
||||
</text>
|
||||
<text v-else>¥{{ v.price }}</text>
|
||||
|
||||
<view>
|
||||
x 1
|
||||
@@ -92,13 +92,13 @@
|
||||
<text style="color: #aaa; margin-left: 10rpx">
|
||||
(全部积分:{{ initData.user.jf }})</text>
|
||||
</template>
|
||||
<!-- <template v-else-if="v.type == 5">
|
||||
<template v-else-if="v.type == 5">
|
||||
<text class="type_text_red">活动立减</text>
|
||||
</template>
|
||||
|
||||
<template v-else-if="v.type == 6">
|
||||
<text class="type_text_red">VIP专享立减</text>
|
||||
</template> -->
|
||||
</template>
|
||||
<text v-else>{{ v.text }}</text>
|
||||
</view>
|
||||
<view class="right">
|
||||
@@ -110,12 +110,12 @@
|
||||
<template v-if="v.type == 3">
|
||||
<text style="color: #fe6035"> -¥{{ jfNumberShow }}</text>
|
||||
</template>
|
||||
<!-- <template v-if="v.type == 5">
|
||||
<template v-if="v.type == 5">
|
||||
<text class="type_text_red">-¥{{districtAmount}}</text>
|
||||
</template>
|
||||
<template v-if="v.type == 6">
|
||||
<text class="type_text_red">-¥{{vipPrice}}</text>
|
||||
</template> -->
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
<text v-else> {{ v.text }}</text>
|
||||
</view>
|
||||
<template v-if="isDefaultCurrency">
|
||||
<radio :value="v.value" color="#7dc1f0"
|
||||
<radio :value="v.value" color="#7dc1f0" v-if="i == 2"
|
||||
:checked="selectPayIndex == i ? true : false" @click="radioChange(i)" size="10" />
|
||||
</template>
|
||||
<template v-else>
|
||||
@@ -213,10 +213,19 @@
|
||||
<common-goods-nav :iconList="[]" :customButton="customButton" @submit="goBuyJie">
|
||||
<!-- leftSlot -->
|
||||
<template slot="leftSlot" slot-scope="slotProps">
|
||||
<view class="price_box order_bottom_box"><text class="number">共{{ number }}件</text>
|
||||
<text class="price">合计:
|
||||
<view class="price_box order_bottom_box">
|
||||
<text class="price">合计:
|
||||
|
||||
<text class="total">¥{{ actualPayment }}</text>
|
||||
<text class="total">
|
||||
<template v-if="actualPayment>0">
|
||||
¥{{ Number(actualPayment).toFixed(2) }}
|
||||
</template>
|
||||
<text style="margin: 0 4rpx;" v-if="actualPayment>0&&jfNumber>0">
|
||||
+
|
||||
</text>
|
||||
|
||||
<text v-if="jfNumber>0">{{ jfNumber }} 积分</text>
|
||||
</text>
|
||||
</text>
|
||||
</view>
|
||||
</template>
|
||||
@@ -282,7 +291,18 @@ import parse from "../../uni_modules/uview-ui/libs/config/props/parse";
|
||||
this.selectPayIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
this.payType = this.payList[this.selectPayIndex].type;
|
||||
if (this.actualPayment == 0) {
|
||||
var that = this;
|
||||
this.payList.forEach((e, i) => {
|
||||
if (e.type == 4) {
|
||||
that.selectPayIndex = i;
|
||||
that.payType = 4;
|
||||
}
|
||||
});
|
||||
this.$forceUpdate();
|
||||
}
|
||||
this.$forceUpdate();
|
||||
},
|
||||
},
|
||||
@@ -370,7 +390,7 @@ import parse from "../../uni_modules/uview-ui/libs/config/props/parse";
|
||||
freightNum: "book/buyOrder/calculateTransportPrice", //运费
|
||||
},
|
||||
customButton: [{
|
||||
width: "340rpx",
|
||||
width: "300rpx",
|
||||
text: "立即支付",
|
||||
backgroundColor: "linear-gradient(90deg, #294a97 0%, #7dc1f0 80%)",
|
||||
color: "#fff",
|
||||
@@ -558,10 +578,19 @@ import parse from "../../uni_modules/uview-ui/libs/config/props/parse";
|
||||
this.jfNumberShow = this.jfNumber.toFixed(2);
|
||||
}
|
||||
|
||||
this.actualPayment = this.totalPrice - this.jfNumber + this.freightNum;
|
||||
this.actualPayment = this.totalPrice - this.jfNumber - this.vipPrice - this.districtAmount + this.freightNum;
|
||||
|
||||
// 如果实际支付金额为0,设置支付方式为默认货币
|
||||
if (this.actualPayment == 0) {
|
||||
console.log("this.actualPayment at line 1097:", this.actualPayment);
|
||||
this.isDefaultCurrency = true;
|
||||
this.payList.forEach((e, i) => {
|
||||
if (e.type == 4) {
|
||||
this.selectPayIndex = i;
|
||||
this.payType = 4;
|
||||
}
|
||||
});
|
||||
this.$forceUpdate();
|
||||
} else {
|
||||
this.isDefaultCurrency = false;
|
||||
}
|
||||
@@ -597,17 +626,17 @@ import parse from "../../uni_modules/uview-ui/libs/config/props/parse";
|
||||
},
|
||||
];
|
||||
//如果是活动
|
||||
// if(this.goodsDataList[0].activityPrice&&this.goodsDataList[0].activityPrice>0&&!this.goodsDataList[0].vipPrice>0){
|
||||
// this.priceBreakdownList.push({
|
||||
// type: 5,
|
||||
// })
|
||||
// }
|
||||
// //如果是vip
|
||||
// if(this.goodsDataList[0].isVipPrice==1&&this.goodsDataList[0].vipPrice!=null&&this.goodsDataList[0].vipPrice!=0){
|
||||
// this.priceBreakdownList.push({
|
||||
// type: 6,
|
||||
// })
|
||||
// }
|
||||
if(this.goodsDataList[0].activityPrice&&this.goodsDataList[0].activityPrice>0&&!this.goodsDataList[0].vipPrice>0){
|
||||
this.priceBreakdownList.push({
|
||||
type: 5,
|
||||
})
|
||||
}
|
||||
//如果是vip
|
||||
if(this.goodsDataList[0].isVipPrice==1&&this.goodsDataList[0].vipPrice!=null&&this.goodsDataList[0].vipPrice!=0){
|
||||
this.priceBreakdownList.push({
|
||||
type: 6,
|
||||
})
|
||||
}
|
||||
|
||||
var data = {
|
||||
uid: this.userInfo.id,
|
||||
@@ -753,8 +782,8 @@ import parse from "../../uni_modules/uview-ui/libs/config/props/parse";
|
||||
|
||||
if (!this.isShowAddress) {
|
||||
if (this.initData.user.jf >= that.totalPrice) {
|
||||
this.jfNumber = that.totalPrice;
|
||||
this.jfNumberMax = that.totalPrice;
|
||||
this.jfNumber = that.totalPrice - that.vipPrice - that.districtAmount;
|
||||
this.jfNumberMax = that.totalPrice - that.vipPrice - that.districtAmount;
|
||||
} else {
|
||||
this.jfNumber = this.initData.user.jf;
|
||||
this.jfNumberMax = this.initData.user.jf;
|
||||
@@ -766,23 +795,13 @@ import parse from "../../uni_modules/uview-ui/libs/config/props/parse";
|
||||
that.jfNumberShow = that.jfNumber.toFixed(2);
|
||||
that.actualPayment = that.totalPrice - that.jfNumber;
|
||||
}
|
||||
that.actualPayment = that.actualPayment + that.freightNum;
|
||||
that.actualPayment = that.actualPayment + that.freightNum - that.vipPrice- that.districtAmount;
|
||||
} else {
|
||||
that.actualPayment = that.totalPrice + that.freightNum;
|
||||
that.actualPayment = that.totalPrice + that.freightNum - that.vipPrice - that.districtAmount;
|
||||
}
|
||||
|
||||
if (this.actualPayment == 0 && !this.isShowAddress) {
|
||||
this.isDefaultCurrency = true;
|
||||
this.payList = [
|
||||
{
|
||||
text: "天医币",
|
||||
imgUrl: require("@/static/icon/pay_3.png"),
|
||||
type: 4,
|
||||
value: "2",
|
||||
},
|
||||
];
|
||||
this.selectPayIndex = 0;
|
||||
this.payType = 4;
|
||||
} else {
|
||||
this.isDefaultCurrency = false;
|
||||
}
|
||||
@@ -1212,9 +1231,8 @@ import parse from "../../uni_modules/uview-ui/libs/config/props/parse";
|
||||
|
||||
.price {
|
||||
width: auto;
|
||||
font-size: 30rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 600;
|
||||
float: right;
|
||||
margin-right: 10rpx;
|
||||
color: #333;
|
||||
}
|
||||
@@ -1378,7 +1396,6 @@ import parse from "../../uni_modules/uview-ui/libs/config/props/parse";
|
||||
.number {
|
||||
font-size: 26rpx;
|
||||
margin-right: 15rpx;
|
||||
margin-top: 5rpx;
|
||||
}
|
||||
|
||||
.price {
|
||||
@@ -1395,7 +1412,6 @@ import parse from "../../uni_modules/uview-ui/libs/config/props/parse";
|
||||
width: calc(100% - 220rpx);
|
||||
height: auto;
|
||||
position: relative;
|
||||
// overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1409,6 +1425,7 @@ import parse from "../../uni_modules/uview-ui/libs/config/props/parse";
|
||||
.order_bottom_box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.pay_box {
|
||||
|
||||
@@ -37,13 +37,22 @@
|
||||
</view>
|
||||
<view class="cate_box">
|
||||
<scroll-view scroll-x="true">
|
||||
<view class="cate_list" v-if="cateList.length>0">
|
||||
<view class="cate_list" v-if="$platform!='android'&&cateList.length>0">
|
||||
<view class="cate_item_box" v-if="item.id!=75" v-for="(item, index) in cateList" @click="handleClickCate(item)">
|
||||
<view class="cate_item_border">
|
||||
<image :src="item.icon"></image>
|
||||
</view>
|
||||
<view class="cate_item_name" v-if="index==2">心身健康科学</view>
|
||||
<view class="cate_item_name" v-else>{{ item.title }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="cate_list" v-if="$platform=='android'&&cateList.length>0">
|
||||
<view class="cate_item_box" v-for="(item, index) in cateList" @click="handleClickCate(item)">
|
||||
<view class="cate_item_border">
|
||||
<image :src="item.icon"></image>
|
||||
</view>
|
||||
<view class="cate_item_name" v-if="$platform!='android'&&index==2">心身健康科学</view>
|
||||
<view class="cate_item_name" v-else>{{ item.title }}</view>
|
||||
<view class="cate_item_name">{{ item.title }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
@@ -66,7 +75,7 @@
|
||||
<view class="miaosha_list">
|
||||
<view class="miaosha_item" @click="goGoodsDetail(v)"
|
||||
v-for="(v, i) in seckillLst">
|
||||
<!-- <text class="miaosha_youhui" v-if="$platform=='android'&&v.isVipPrice==1&&v.vipPrice!=null&&v.vipPrice!=0">VIP优惠</text> -->
|
||||
<text class="miaosha_youhui" v-if="v.isVipPrice==1&&v.vipPrice!=null&&v.vipPrice!=0">VIP优惠</text>
|
||||
<image class="book_image" :src="v.productImages" mode="aspectFit"></image>
|
||||
<view class="book_name">{{ v.productName }}</view>
|
||||
</view>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</view>
|
||||
<view class="userInfoBox">
|
||||
<view class="name">{{ userMes.nickname ? userMes.nickname : "未设置" }}</view>
|
||||
<!-- <view class="phone" v-if="userMes.tel">手机号:({{ userMes.tel }})</view> -->
|
||||
<view class="phone" v-if="userMes.tel&&$platform=='android'">手机号:({{ userMes.tel }})</view>
|
||||
<view class="vip_type" v-if="$platform=='android'&&textList.length>0">
|
||||
<view class="vip_type_item" v-for="(item,index) in textList" :key="index">
|
||||
{{item}}<image src="@/static/icon/chao_vip.png"></image>
|
||||
|
||||
@@ -115,7 +115,8 @@
|
||||
font-weight: 700;
|
||||
">
|
||||
<text style="font-size: 20rpx">¥</text>
|
||||
{{item2.product.price ? item2.product.price : ""}}
|
||||
<text v-if="item2.product.price>=0">{{item2.product.price}}</text>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
<view class="btns flexbox" style="margin-top: 10rpx">
|
||||
@@ -138,66 +139,63 @@
|
||||
</view>
|
||||
|
||||
<view style="margin-top: 10rpx; overflow: hidden">
|
||||
<view class="btns flexbox" style="float: right; width: auto !important">
|
||||
<view class="right flexbox opbtns" style="
|
||||
<view
|
||||
class="btns flexbox"
|
||||
style="float: right; width: auto !important"
|
||||
>
|
||||
<view
|
||||
class="right flexbox opbtns"
|
||||
style="
|
||||
width: auto;
|
||||
line-height: 44rpx;
|
||||
letter-spacing: 1rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
">
|
||||
<view style="
|
||||
"
|
||||
>
|
||||
<view
|
||||
style="
|
||||
line-height: 46rpx;
|
||||
color: #000;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
margin-right: 10rpx;
|
||||
">实付款</view>
|
||||
<view style="
|
||||
"
|
||||
>实付款</view
|
||||
>
|
||||
<view
|
||||
style="
|
||||
line-height: 46rpx;
|
||||
color: #333;
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
">
|
||||
<text style="font-size: 20rpx">¥</text>
|
||||
{{ slotProps.row.realMoney || slotProps.row.realMoney == 0 ? slotProps.row.realMoney: "" }}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="btns flexbox" style="
|
||||
margin-top: 0rpx;
|
||||
float: right;
|
||||
width: auto;
|
||||
margin-left: 20rpx;"
|
||||
"
|
||||
>
|
||||
<text v-if="slotProps.row.orderType == 'point'">
|
||||
{{ slotProps.row.bookBuyConfigEntity.realMoney }}
|
||||
</text>
|
||||
<text v-if="slotProps.row.orderType != 'point'">
|
||||
<text v-if="slotProps.row.realMoney && slotProps.row.realMoney > 0">
|
||||
¥{{ slotProps.row.realMoney }}
|
||||
</text>
|
||||
<text v-if="slotProps.row.realMoney==0&&slotProps.row.jfDeduction==0">
|
||||
¥0
|
||||
</text>
|
||||
|
||||
<text
|
||||
style="margin: 0 4rpx"
|
||||
v-if="
|
||||
(slotProps.row.addressId == 0 ||
|
||||
slotProps.row.addressId == null) &&
|
||||
slotProps.row.orderType == 'order' &&
|
||||
slotProps.row.realMoney > 0 &&
|
||||
slotProps.row.jfDeduction > 0
|
||||
">
|
||||
<view class="right flexbox opbtns" style="
|
||||
line-height: 44rpx;
|
||||
letter-spacing: 1rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
"><text style="color: #9b9b9b">( </text>
|
||||
<view style="
|
||||
line-height: 46rpx;
|
||||
color: #9b9b9b;
|
||||
font-size: 24rpx;
|
||||
font-weight: 500;
|
||||
margin-right: 10rpx;
|
||||
">积分抵扣</view>
|
||||
<view style="
|
||||
line-height: 46rpx;
|
||||
color: #9b9b9b;
|
||||
font-size: 26rpx;
|
||||
font-weight: 700;
|
||||
">
|
||||
<text style="font-size: 20rpx">¥</text>
|
||||
{{ slotProps.row.jfDeduction }}
|
||||
"
|
||||
>
|
||||
+
|
||||
</text>
|
||||
</text>
|
||||
|
||||
<text v-if="slotProps.row.jfDeduction > 0">{{ slotProps.row.jfDeduction }} 积分</text>
|
||||
</view>
|
||||
</view>
|
||||
</view><text style="color: #9b9b9b">)</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="right">
|
||||
<u-icon @click="toLogin()" class="editIcon" name="shopping-cart-fill"
|
||||
<u-icon class="editIcon" name="shopping-cart-fill"
|
||||
color="#FF2B57" size="30"
|
||||
style="display: inline-block; margin-left: 10rpx"></u-icon>
|
||||
</view>
|
||||
@@ -56,8 +56,7 @@
|
||||
<view class="shiting_content">
|
||||
<view class="catalogueList">
|
||||
<view class="chapter_content">
|
||||
<courseDescription :isCondition="true" :dataList="slotProps.dataList"
|
||||
@hancleClick="toLogin()" label="title">
|
||||
<courseDescription :isCondition="true" :dataList="slotProps.dataList" label="title">
|
||||
<template slot="labelSlot" slot-scope="slotProps">
|
||||
<view :style="`${
|
||||
slotProps.row.isAudition==1
|
||||
@@ -218,21 +217,6 @@
|
||||
});
|
||||
return list;
|
||||
},
|
||||
//登录
|
||||
toLogin(){
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '为了方便您后期用不同的设备查阅订购的记录,请先完成登录或注册。',
|
||||
confirmText: '确认',
|
||||
success(res){
|
||||
if (res.confirm) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/user/login'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<view class="cate_box">
|
||||
<scroll-view scroll-x="true">
|
||||
<view class="cate_list" v-if="cateList.length>0">
|
||||
<view class="cate_item_box" v-for="(item, index) in cateList" @click="handleClickCate(item)">
|
||||
<view class="cate_item_box" v-if="item.id!=75" v-for="(item, index) in cateList" @click="handleClickCate(item)">
|
||||
<view class="cate_item_border">
|
||||
<image :src="item.icon"></image>
|
||||
</view>
|
||||
@@ -258,7 +258,7 @@ export default {
|
||||
align-items: center;
|
||||
|
||||
.cate_item_box {
|
||||
width: 20%;
|
||||
width: 25%;
|
||||
padding: 40rpx 0 30rpx;
|
||||
text-align: center;
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<view class="list_item_title">{{item.title}}</view>
|
||||
<view class="list_item_content" v-html="item.content"></view>
|
||||
<view class="list_item_bt">
|
||||
<text class="list_item_study" @click="toLogin()">了解课程</text>
|
||||
<text class="list_item_study">了解课程</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -20,7 +20,7 @@
|
||||
</view>
|
||||
|
||||
<view class="xlcp_block" v-if="statusXLCP">
|
||||
<view class="level_block" @click="toLogin()">
|
||||
<view class="level_block">
|
||||
<view class="level_item">自恋型人格障碍诊断标准</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -44,13 +44,13 @@ export default {
|
||||
|
||||
},
|
||||
onLoad(options) {
|
||||
this.title = options.title;
|
||||
this.id = options.id;
|
||||
//如果是心理评测
|
||||
if(this.id==75){
|
||||
this.statusXLCP = true;
|
||||
}else{
|
||||
this.getData();
|
||||
//针对身心医学的判断
|
||||
if(options.title=='心身医学'){
|
||||
this.title = '心身健康科学'
|
||||
}else{
|
||||
this.title = options.title;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -74,20 +74,6 @@ export default {
|
||||
this.statusNull = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
toLogin(){
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '为了方便您后期用不同的设备查阅订购的记录,请先完成登录或注册。',
|
||||
confirmText: '确认',
|
||||
success(res){
|
||||
if (res.confirm) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/user/login'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
<template>
|
||||
<view class="commonPage commonPageBox">
|
||||
<view class="bg_top">
|
||||
<u-icon @click="goSetting()" class="setIcon" labelColor="#294a97" labelPos="bottom" label="设置" name="setting"
|
||||
:style="`top:${(20 + statusBarHeight) * 2}rpx`" color="#294a97" size="22"></u-icon>
|
||||
</view>
|
||||
|
||||
<view class="mine_box" :style="`top:${(80 + statusBarHeight) * 2}rpx`">
|
||||
<view class="per_mes">
|
||||
|
||||
@@ -313,7 +313,7 @@ export default {
|
||||
quantity: 1,
|
||||
manualFinishTransaction: true, // 3.5.1+ 支持,设置此参数后需要开发者主动关闭订单,参见下面的关闭订单方法 finishTransaction()
|
||||
}
|
||||
this.transaction = await this.requestPayment(orderInfo)
|
||||
that.transaction = await that.requestPayment(orderInfo)
|
||||
},
|
||||
iapCheck(result) {
|
||||
let that = this;
|
||||
@@ -337,7 +337,7 @@ export default {
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.code == 0) {
|
||||
this.transaction = null
|
||||
that.transaction = null
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: '充值成功!',
|
||||
|
||||
BIN
uni_modules/cx-audio-play111.rar
Normal file
BIN
uni_modules/cx-audio-play111.rar
Normal file
Binary file not shown.
2
uni_modules/multiple-choice/changelog.md
Normal file
2
uni_modules/multiple-choice/changelog.md
Normal file
@@ -0,0 +1,2 @@
|
||||
## 1.0.0(2021-05-12)
|
||||
1. 支持uni_modules
|
||||
@@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="popupClick" @click="onPopupShow()"><slot></slot></view>
|
||||
<z-popup v-model="currentValue">
|
||||
<view class="multiple_choice_title">
|
||||
<text @click="currentValue = false">取消</text>
|
||||
<view>{{title}}</view>
|
||||
<text @click="onConfirm">确定</text>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" class="multiple_choice_scroll">
|
||||
<view class="multiple_choice_box">
|
||||
<view class="multiple_choice_content">
|
||||
<view class="multiple_choice_item" v-for="(item,index) of rangeList" :key="index" @click="onSelect(index)">
|
||||
<view class="select" :class="{active: item.select }"></view>
|
||||
<view class="value">{{item[rangeKey]}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</z-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
range: {
|
||||
type: Array,
|
||||
default: function(){
|
||||
return []
|
||||
}
|
||||
},
|
||||
rangeKey: {
|
||||
type: String,
|
||||
default: "name"
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (typeof this.value !== 'undefined') {
|
||||
this.currentValue = this.value;
|
||||
}
|
||||
this.rangeList = this.range.map(item => {
|
||||
item.select = false;
|
||||
return item;
|
||||
});
|
||||
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
this.currentValue = val;
|
||||
},
|
||||
currentValue(val) {
|
||||
this.$emit(val ? 'on-show' : 'on-hide');
|
||||
this.$emit('input', val);
|
||||
},
|
||||
range(val){
|
||||
this.rangeList = val.map(item => {
|
||||
item.select = false;
|
||||
return item;
|
||||
});
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentValue: false,
|
||||
rangeList: []
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onPopupShow(){
|
||||
this.currentValue = true;
|
||||
},
|
||||
onSelect(index){
|
||||
let item = this.rangeList[index];
|
||||
item.select = !item.select;
|
||||
this.$set(this.rangeList, index, item);
|
||||
},
|
||||
onConfirm(){
|
||||
let resultList = this.rangeList.filter(item => {
|
||||
if(item.select){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if(resultList.length > 0){
|
||||
this.currentValue = false;
|
||||
this.$emit("change", resultList);
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: "请选择",
|
||||
icon: "none"
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/style/mixin.scss';
|
||||
.multiple_choice_title {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
height: 88upx;
|
||||
line-height: 88upx;
|
||||
border-bottom: 2upx solid #ebebeb;
|
||||
padding: 0 20upx;
|
||||
background-color: #FFF;
|
||||
}
|
||||
.multiple_choice_title view {
|
||||
font-size: 32upx;
|
||||
}
|
||||
.multiple_choice_title text {
|
||||
width: 80upx;
|
||||
flex-shrink: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.multiple_choice_title text {
|
||||
font-size: 28upx;
|
||||
color: #999;
|
||||
}
|
||||
.multiple_choice_title text:last-child {
|
||||
color: $themeColor;
|
||||
}
|
||||
.multiple_choice_scroll {
|
||||
background-color: #FFF;
|
||||
max-height: 60vh;
|
||||
min-height: 30vh;
|
||||
}
|
||||
.multiple_choice_box {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 30vh;
|
||||
}
|
||||
.multiple_choice_content {
|
||||
.multiple_choice_item {
|
||||
height: 100rpx;
|
||||
padding: 0 30rpx;
|
||||
font-size: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// &:nth-child(2n) {
|
||||
// background-color: #f7f7f7;
|
||||
// }
|
||||
.select {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 15rpx;
|
||||
// background-image: url(../../static/icon/ic_notselected.png);
|
||||
// background-size: 100% 100%;
|
||||
flex-shrink: 0;
|
||||
border-radius: 50%;
|
||||
border: 2rpx solid #ccc;
|
||||
&.active {
|
||||
border: 2rpx solid $themeColor;
|
||||
background-color: $themeColor;
|
||||
text-align: center;
|
||||
line-height: 38rpx;
|
||||
transform:rotate(15deg);
|
||||
}
|
||||
&.active::before {
|
||||
content: "√";
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
.value {
|
||||
width: calc(100% - 55rpx);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
77
uni_modules/multiple-choice/package.json
Normal file
77
uni_modules/multiple-choice/package.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"id": "multiple-choice",
|
||||
"displayName": "多选组件",
|
||||
"version": "1.0.0",
|
||||
"description": "多选组件",
|
||||
"keywords": [
|
||||
"多选",
|
||||
"多选组件"
|
||||
],
|
||||
"repository": "https://github.com/zhouwei1994/uni-app-demo",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.0.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": "465081029"
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
uni_modules/multiple-choice/readme.md
Normal file
29
uni_modules/multiple-choice/readme.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# 多选组件
|
||||
|
||||
多选组件
|
||||
|
||||
| `QQ交流群(607391225)` | `微信交流群(加我好友备注"进群")` |
|
||||
| ----------------------------|--------------------------- |
|
||||
|||
|
||||
| QQ群号:607391225 |微信号:zhou0612wei|
|
||||
|
||||
### [点击跳转-5年的web前端开源的uni-app快速开发模板-下载看文档](https://ext.dcloud.net.cn/plugin?id=2009)
|
||||
|
||||
### 案例一
|
||||
```
|
||||
<multiple-choice v-model="true" title="选择性别" :range="[{name: '男'}, {name: '女'}]" rangeKey="name"></multiple-choice>
|
||||
```
|
||||
### 案例二
|
||||
```
|
||||
<multiple-choice title="选择性别" :range="[{name: '男'}, {name: '女'}]" rangeKey="name">
|
||||
<button>打开</button>
|
||||
</multiple-choice>
|
||||
```
|
||||
|
||||
### 属性
|
||||
| 名称 | 类型 | 默认值 | 描述 |
|
||||
| ----------------------------|--------------- | ------------- | ---------------------------------------------------|
|
||||
| value | Boolean | false | 控制弹窗是否打开 |
|
||||
| title | String | | 弹窗标题|
|
||||
| range | Array | [] | 可选内容 |
|
||||
| rangeKey | String | name | 显示内容的key|
|
||||
72
uni_modules/qf-image-cropper/changelog.md
Normal file
72
uni_modules/qf-image-cropper/changelog.md
Normal file
@@ -0,0 +1,72 @@
|
||||
## 2.2.5(2024-07-30)
|
||||
* 修复 当 checkRange=true 时,拖动四个伸缩角放大图片时还可能会超出或未到边界的问题
|
||||
* 修复 当 checkRange=false 时,图片旋转时会放大图片适应裁剪尺寸的问题
|
||||
* 修复 当 checkRange=true 时,图片旋转 90° 或 270° 进行缩放可能会无法拖动图片的问题
|
||||
## 2.2.4(2024-06-21)
|
||||
* 新增 reverseRotatable 属性,是否支持逆向翻转
|
||||
* 修复 `2.1.7` 版本导致旋转后图片没有自动适配裁剪框的问题
|
||||
|
||||
## 2.2.3(2024-06-21)
|
||||
* 新增 gpu 属性,是否开启硬件加速,图片缩放过程中如果出现元素的“留影”或“重影”效果,可通过该方式解决或减轻这一问题
|
||||
* 修复 组件使用 `v-if` 并设置 `src` 属性时可能会出现图片渲染位置存在偏差的问题
|
||||
|
||||
## 2.2.2(2024-06-21)
|
||||
* 优化 组件实例 chooseImage 方法支持传参
|
||||
* 修复 组件使用 `v-if` 时组件无非正常渲染的问题
|
||||
|
||||
## 2.2.1(2024-06-15)
|
||||
* 修复 H5平台不支持手势拖动图片的问题
|
||||
|
||||
## 2.2.0(2024-05-31)
|
||||
* 修复 APP平台 `vue2` 项目因 `2.1.9` 版本修复 `vue3` 项目bug而引发的问题
|
||||
|
||||
## 2.1.9(2024-05-29)
|
||||
* 修复 APP平台 `vue3` 项目因 uniapp `renderjs` 中未支持条件编译,导致运行了H5平台代码报错的问题
|
||||
|
||||
## 2.1.8(2024-05-29)
|
||||
* 新增 zIndex 属性,调整组件层级
|
||||
* 新增 组件内容插槽
|
||||
* 优化 微信小程序平台动态修改元素style时的多余内容
|
||||
|
||||
## 2.1.7(2024-05-28)
|
||||
* 新增 checkRange 属性,当 checkRange=false 时允许图片位置超出裁剪边界
|
||||
* 新增 minScale 属性,图片最小缩放倍数,当 minScale<0 时可使图片宽高不再受裁剪区域宽高限制
|
||||
* 新增 backgroundColor 属性,生成图片背景色,如果裁剪区域没有完全包含在图片中时,不设置该属性生成图片存在一定的透明块
|
||||
* 优化 动态修改图片宽高但没有传入src时,尺寸适应问题
|
||||
* 修复 APP平台通过 `this.$ownerInstance` 获取组件实例时机过早,其值为 `undefined` 导致报错界面没有正常渲染的问题
|
||||
|
||||
## 2.1.6(2023-04-16)
|
||||
* 修复 组件使用 v-show 指令会导致选择图片后初始位置严重偏位的问题
|
||||
|
||||
## 2.1.5(2023-04-15)
|
||||
* 新增 兼容APP平台
|
||||
|
||||
## 2.1.4(2023-03-13)
|
||||
* 新增 fileType 属性,用于指定生成文件的类型,只支持 'jpg' 或 'png',默认为 'png'
|
||||
* 新增 delay 属性,微信小程序平台使用 `Canvas 2D` 绘制时控制图片从绘制到生成所需时间
|
||||
* 优化 当生成图片的尺寸宽/高超过 Canvas 2D 最大限制(1365*1365)则将画布尺寸缩放在限制范围内绘制完成后输出目标尺寸
|
||||
* 优化 旋转图标指示方向与实际旋转方向不符
|
||||
|
||||
## 2.1.3(2023-02-06)
|
||||
* 优化 vue3支持
|
||||
|
||||
## 2.1.2(2023-02-03)
|
||||
* 新增 navigation 属性,H5平台当 showAngle 为 true 时,使用插件的页面在 `page.json` 中配置了 "navigationStyle": "custom" 时,必须将此值设为 false ,否则四个可拉伸角的触发位置会有偏差
|
||||
* 修复 H5平台部分设备(已知iPhone11以下机型)拍照的图片缩放时会闪动的问题
|
||||
|
||||
## 2.1.1(2022-12-06)
|
||||
* 修复 横屏适配问题
|
||||
|
||||
## 2.1.0(2022-12-06)
|
||||
* 新增 兼容H5平台,使用 renderjs 响应手势事件
|
||||
|
||||
## 2.0.0(2022-12-05)
|
||||
* 重构 插件,使用 WXS 响应手势事件
|
||||
* 新增 图片翻转
|
||||
* 新增 拉伸裁剪框放大图片
|
||||
* 新增 监听PC鼠标滚轮触发缩放
|
||||
* 新增 圆形、圆角矩形的图片裁剪
|
||||
* 优化 图片缩放,移动端以双指触摸中心点为缩放中心点,PC端以鼠标所在点为缩放中心点
|
||||
* 优化 裁剪框样式
|
||||
* 优化 图片位置拖动 支持边界回弹效果(滑动时可滑出边界,释放时回弹到边界)
|
||||
* 优化 生成图片使用新版 Canvas 2D 接口
|
||||
@@ -0,0 +1,855 @@
|
||||
/**
|
||||
* 图片编辑器-手势监听
|
||||
* 1. 支持编译到app-vue(uni-app 2.5.5及以上版本)、H5上
|
||||
*/
|
||||
/** 图片偏移量 */
|
||||
var offset = { x: 0, y: 0 };
|
||||
/** 图片缩放比例 */
|
||||
var scale = 1;
|
||||
/** 图片最小缩放比例 */
|
||||
var minScale = 1;
|
||||
/** 图片旋转角度 */
|
||||
var rotate = 0;
|
||||
/** 触摸点 */
|
||||
var touches = [];
|
||||
/** 图片布局信息 */
|
||||
var img = {};
|
||||
/** 系统信息 */
|
||||
var sys = {};
|
||||
/** 裁剪区域布局信息 */
|
||||
var area = {};
|
||||
/** 触摸行为类型 */
|
||||
var touchType = '';
|
||||
/** 操作角的位置 */
|
||||
var activeAngle = 0;
|
||||
/** 裁剪区域布局信息偏移量 */
|
||||
var areaOffset = { left: 0, right: 0, top: 0, bottom: 0 };
|
||||
/** 元素ID */
|
||||
var elIds = {
|
||||
'imageStyles': 'crop-image',
|
||||
'maskStylesList': 'crop-mask-block',
|
||||
'borderStyles': 'crop-border',
|
||||
'circleBoxStyles': 'crop-circle-box',
|
||||
'circleStyles': 'crop-circle',
|
||||
'gridStylesList': 'crop-grid',
|
||||
'angleStylesList': 'crop-angle',
|
||||
}
|
||||
/** 记录上次初始化时间戳,排除APP重复更新 */
|
||||
var timestamp = 0;
|
||||
/** vue3 renderjs 条件编译无效,以此方式区别 APP 和 H5 */
|
||||
// #ifdef H5
|
||||
var platform = 'H5';
|
||||
// #endif
|
||||
// #ifdef APP
|
||||
var platform = 'APP';
|
||||
// #endif
|
||||
/** 容错值 */
|
||||
var fault = 0.000001;
|
||||
/**
|
||||
* 获取a、b两数中的最小正数
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
function minimum(a, b) {
|
||||
if (a > 0 && b < 0) return a;
|
||||
if (a < 0 && b > 0) return b;
|
||||
if (a > 0 && b > 0) return Math.min(a, b);
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* 在容错访问内获取n近似值
|
||||
* @param n
|
||||
*/
|
||||
function num(n) {
|
||||
var m = parseFloat((n).toFixed(6));
|
||||
return m === fault || m === -fault ? 0 : m;
|
||||
}
|
||||
/**
|
||||
* 比较a值在容错值范围内是否等于b值
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
function equalsByFault(a, b) {
|
||||
return Math.abs(a - b) <= fault;
|
||||
}
|
||||
/**
|
||||
* 比较a值在容错值范围内是否小于b值
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
function lessThanByFault(a, b) {
|
||||
var c = a - b;
|
||||
return c < 0 ? c < -fault : c < fault;
|
||||
}
|
||||
/**
|
||||
* 验证并获取有效最大值
|
||||
* @param v
|
||||
* @param max
|
||||
* @param isInclude
|
||||
* @param x
|
||||
* @param y
|
||||
* @param rate
|
||||
* @returns
|
||||
*/
|
||||
function validMax(v, max, isInclude, x, y, rate) {
|
||||
if(typeof max === 'number') {
|
||||
if(isInclude && equalsByFault(max, y)) { // 宽高不等时,x轴用y轴值要做等比例转换
|
||||
var n = num(max * rate);
|
||||
if (n <= x) return n; // 转化后值在x轴最大值范围内
|
||||
return x; // 转化后值超出x轴最大值范围则用最大值
|
||||
}
|
||||
return max;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
/**
|
||||
* 样式对象转字符串
|
||||
* @param {Object} style 样式对象
|
||||
*/
|
||||
function styleToString(style) {
|
||||
if(typeof style === 'string') return style;
|
||||
var str = '';
|
||||
for (let k in style) {
|
||||
str += k + ':' + style[k] + ';';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {Object} instance 页面实例对象
|
||||
* @param {Object} key 要修改样式的key
|
||||
* @param {Object|Array} style 样式
|
||||
*/
|
||||
function setStyle(instance, key, style) {
|
||||
// console.log('setStyle', instance, key, JSON.stringify(style))
|
||||
// #ifdef APP-PLUS
|
||||
if(platform === 'APP') {
|
||||
if(Object.prototype.toString.call(style) === '[object Array]') {
|
||||
for (var i = 0, len = style.length; i < len; i++) {
|
||||
var el = window.document.getElementById(elIds[key] + '-' + (i + 1));
|
||||
el && (el.style = styleToString(style[i]));
|
||||
}
|
||||
} else {
|
||||
var el = window.document.getElementById(elIds[key]);
|
||||
el && (el.style = styleToString(style));
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
if(platform === 'H5') instance[key] = style;
|
||||
// #endif
|
||||
}
|
||||
/**
|
||||
* 触发页面实例指定方法
|
||||
* @param {Object} instance 页面实例对象
|
||||
* @param {Object} name 方法名称
|
||||
* @param {Object} obj 传递参数
|
||||
*/
|
||||
function callMethod(instance, name, obj) {
|
||||
// #ifdef APP-PLUS
|
||||
if(platform === 'APP') instance.callMethod(name, obj);
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
if(platform === 'H5') instance[name](obj);
|
||||
// #endif
|
||||
}
|
||||
/**
|
||||
* 计算两点间距
|
||||
* @param {Object} touches 触摸点信息
|
||||
*/
|
||||
function getDistanceByTouches(touches) {
|
||||
// 根据勾股定理求两点间距离
|
||||
var a = touches[1].pageX - touches[0].pageX;
|
||||
var b = touches[1].pageY - touches[0].pageY;
|
||||
var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
|
||||
// 求两点间的中点坐标
|
||||
// 1. a、b可能为负值
|
||||
// 2. 在求a、b时,如用touches[1]减touches[0],则求中点坐标也得用touches[1]减a/2、b/2
|
||||
// 3. 同理,在求a、b时,也可用touches[0]减touches[1],则求中点坐标也得用touches[0]减a/2、b/2
|
||||
var x = touches[1].pageX - a / 2;
|
||||
var y = touches[1].pageY - b / 2;
|
||||
return { c, x, y };
|
||||
};
|
||||
|
||||
/**
|
||||
* 修正取值
|
||||
* @param {Object} a
|
||||
* @param {Object} b
|
||||
* @param {Object} c
|
||||
* @param {Object} reverse 是否反向
|
||||
*/
|
||||
function correctValue(a, b, c, reverse) {
|
||||
return num(reverse ? Math.max(Math.min(a, b), c) : Math.min(Math.max(a, b), c));
|
||||
}
|
||||
|
||||
/**
|
||||
* 旋转90°或270°时检查边界:限制 x、y 拖动范围,禁止滑出边界
|
||||
* @param {Object} e 点坐标
|
||||
* @param {Object} xReverse x是否反向
|
||||
* @param {Object} yReverse y是否反向
|
||||
*/
|
||||
function checkRotateRange(e, xReverse, yReverse) {
|
||||
var o = num((img.height - img.width) / 2); // 宽高差值一半
|
||||
return {
|
||||
x: correctValue(e.x, -img.height + o + area.width + area.left, area.left + o, xReverse),
|
||||
y: correctValue(e.y, -img.width - o + area.height + area.top, area.top - o, yReverse)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查边界:限制 x、y 拖动范围,禁止滑出边界
|
||||
* @param {Object} e 点坐标
|
||||
*/
|
||||
function checkRange(e) {
|
||||
var r = rotate / 90 % 2;
|
||||
if(r === 1) { // 因图片宽高可能不等,翻转 90° 或 270° 后图片宽高需反着计算,且左右和上下边界要根据差值做偏移
|
||||
if (area.width === area.height) {
|
||||
return checkRotateRange(e, img.height < area.height, img.width < area.width);
|
||||
}
|
||||
var isInclude = img.height < area.width && img.width < area.height; // 图片是否包含在裁剪区域内
|
||||
if (img.width < area.height || img.height < area.width) {
|
||||
if (area.width < area.height && img.width < img.height) {
|
||||
return isInclude
|
||||
? checkRotateRange(e, area.width < area.height, area.width < area.height)
|
||||
: checkRotateRange(e, false, true);
|
||||
}
|
||||
if (area.height < area.width && img.height < img.width) {
|
||||
return isInclude
|
||||
? checkRotateRange(e, area.height < area.width, area.height < area.width)
|
||||
: checkRotateRange(e, true, false);
|
||||
}
|
||||
}
|
||||
if (img.height >= area.width && img.width >= area.height) {
|
||||
return checkRotateRange(e, false, false);
|
||||
}
|
||||
if (isInclude) {
|
||||
return area.height < area.width
|
||||
? checkRotateRange(e, true, true)
|
||||
: checkRotateRange(e, area.width < area.height, area.width < area.height);
|
||||
}
|
||||
if (img.height < area.width && !img.width < area.height) {
|
||||
return checkRotateRange(e, true, false);
|
||||
}
|
||||
if (!img.height < area.width && img.width < area.height) {
|
||||
return checkRotateRange(e, false, true);
|
||||
}
|
||||
return checkRotateRange(e, img.height < area.height, img.width < area.width);
|
||||
}
|
||||
return {
|
||||
x: correctValue(e.x, -img.width + area.width + area.left, area.left, img.width < area.width),
|
||||
y: correctValue(e.y, -img.height + area.height + area.top, area.top, img.height < area.height)
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 变更图片布局信息
|
||||
* @param {Object} e 布局信息
|
||||
*/
|
||||
function changeImageRect(e) {
|
||||
// console.log('changeImageRect', e)
|
||||
offset.x += e.x || 0;
|
||||
offset.y += e.y || 0;
|
||||
if(e.check && area.checkRange) { // 检查边界
|
||||
var point = checkRange(offset);
|
||||
if(offset.x !== point.x || offset.y !== point.y) {
|
||||
offset = point;
|
||||
}
|
||||
}
|
||||
|
||||
// 因频繁修改 width/height 会造成大量的内存消耗,改为scale
|
||||
// e.instance.imageStyles = {
|
||||
// width: img.width + 'px',
|
||||
// height: img.height + 'px',
|
||||
// transform: 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + ox) + 'px) rotate(' + rotate +'deg)'
|
||||
// };
|
||||
var ox = (img.width - img.oldWidth) / 2;
|
||||
var oy = (img.height - img.oldHeight) / 2;
|
||||
// e.instance.imageStyles = {
|
||||
// width: img.oldWidth + 'px',
|
||||
// height: img.oldHeight + 'px',
|
||||
// transform: 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + oy) + 'px) rotate(' + rotate +'deg) scale(' + scale + ')'
|
||||
// };
|
||||
setStyle(e.instance, 'imageStyles', {
|
||||
width: img.oldWidth + 'px',
|
||||
height: img.oldHeight + 'px',
|
||||
transform: (img.gpu ? 'translateZ(0) ' : '') + 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + oy) + 'px' + ') rotate(' + rotate +'deg) scale(' + scale + ')'
|
||||
});
|
||||
callMethod(e.instance, 'dataChange', {
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
x: offset.x,
|
||||
y: offset.y,
|
||||
rotate: rotate
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 变更裁剪区域布局信息
|
||||
* @param {Object} e 布局信息
|
||||
*/
|
||||
function changeAreaRect(e) {
|
||||
// console.log('changeAreaRect', e)
|
||||
// 变更蒙版样式
|
||||
setStyle(e.instance, 'maskStylesList', [
|
||||
{
|
||||
left: 0,
|
||||
width: (area.left + areaOffset.left) + 'px',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
'z-index': area.zIndex + 2
|
||||
},
|
||||
{
|
||||
left: (area.right + areaOffset.right) + 'px',
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
'z-index': area.zIndex + 2
|
||||
},
|
||||
{
|
||||
left: (area.left + areaOffset.left) + 'px',
|
||||
width: (area.width + areaOffset.right - areaOffset.left) + 'px',
|
||||
top: 0,
|
||||
height: (area.top + areaOffset.top) + 'px',
|
||||
'z-index': area.zIndex + 2
|
||||
},
|
||||
{
|
||||
left: (area.left + areaOffset.left) + 'px',
|
||||
width: (area.width + areaOffset.right - areaOffset.left) + 'px',
|
||||
top: (area.bottom + areaOffset.bottom) + 'px',
|
||||
// height: (area.top - areaOffset.bottom + sys.offsetBottom) + 'px',
|
||||
bottom: 0,
|
||||
'z-index': area.zIndex + 2
|
||||
}
|
||||
]);
|
||||
// 变更边框样式
|
||||
if(area.showBorder) {
|
||||
setStyle(e.instance, 'borderStyles', {
|
||||
left: (area.left + areaOffset.left) + 'px',
|
||||
top: (area.top + areaOffset.top) + 'px',
|
||||
width: (area.width + areaOffset.right - areaOffset.left) + 'px',
|
||||
height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
});
|
||||
}
|
||||
|
||||
// 变更参考线样式
|
||||
if(area.showGrid) {
|
||||
setStyle(e.instance, 'gridStylesList', [
|
||||
{
|
||||
'border-width': '1px 0 0 0',
|
||||
left: (area.left + areaOffset.left) + 'px',
|
||||
right: (area.right + areaOffset.right) + 'px',
|
||||
top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) / 3 - 0.5) + 'px',
|
||||
width: (area.width + areaOffset.right - areaOffset.left) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
},
|
||||
{
|
||||
'border-width': '1px 0 0 0',
|
||||
left: (area.left + areaOffset.left) + 'px',
|
||||
right: (area.right + areaOffset.right) + 'px',
|
||||
top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) * 2 / 3 - 0.5) + 'px',
|
||||
width: (area.width + areaOffset.right - areaOffset.left) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
},
|
||||
{
|
||||
'border-width': '0 1px 0 0',
|
||||
top: (area.top + areaOffset.top) + 'px',
|
||||
bottom: (area.bottom + areaOffset.bottom) + 'px',
|
||||
left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) / 3 - 0.5) + 'px',
|
||||
height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
},
|
||||
{
|
||||
'border-width': '0 1px 0 0',
|
||||
top: (area.top + areaOffset.top) + 'px',
|
||||
bottom: (area.bottom + areaOffset.bottom) + 'px',
|
||||
left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) * 2 / 3 - 0.5) + 'px',
|
||||
height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
// 变更四个伸缩角样式
|
||||
if(area.showAngle) {
|
||||
setStyle(e.instance, 'angleStylesList', [
|
||||
{
|
||||
'border-width': area.angleBorderWidth + 'px 0 0 ' + area.angleBorderWidth + 'px',
|
||||
left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px',
|
||||
top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
},
|
||||
{
|
||||
'border-width': area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0 0',
|
||||
left: (area.right + areaOffset.right - area.angleSize) + 'px',
|
||||
top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
},
|
||||
{
|
||||
'border-width': '0 0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px',
|
||||
left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px',
|
||||
top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
},
|
||||
{
|
||||
'border-width': '0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0',
|
||||
left: (area.right + areaOffset.right - area.angleSize) + 'px',
|
||||
top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
// 变更圆角样式
|
||||
if(area.radius > 0) {
|
||||
var radius = area.radius;
|
||||
if(area.width === area.height && area.radius >= area.width / 2) { // 圆形
|
||||
radius = (area.width / 2);
|
||||
} else { // 圆角矩形
|
||||
if(area.width !== area.height) { // 限制圆角半径不能超过短边的一半
|
||||
radius = Math.min(area.width / 2, area.height / 2, radius);
|
||||
}
|
||||
}
|
||||
setStyle(e.instance, 'circleBoxStyles', {
|
||||
left: (area.left + areaOffset.left) + 'px',
|
||||
top: (area.top + areaOffset.top) + 'px',
|
||||
width: (area.width + areaOffset.right - areaOffset.left) + 'px',
|
||||
height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
|
||||
'z-index': area.zIndex + 2
|
||||
});
|
||||
setStyle(e.instance, 'circleStyles', {
|
||||
'box-shadow': '0 0 0 ' + Math.max(area.width, area.height) + 'px rgba(51, 51, 51, 0.8)',
|
||||
'border-radius': radius + 'px'
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 缩放图片
|
||||
* @param {Object} e 布局信息
|
||||
*/
|
||||
function scaleImage(e) {
|
||||
// console.log('scaleImage', e)
|
||||
var last = scale;
|
||||
scale = Math.min(Math.max(e.scale + scale, minScale), img.maxScale);
|
||||
if(last !== scale) {
|
||||
img.width = num(img.oldWidth * scale);
|
||||
img.height = num(img.oldHeight * scale);
|
||||
// 参考问题:有一个长4000px、宽4000px的四方形ABCD,A点的坐标固定在(-2000,-2000),
|
||||
// 该四边形上有一个点E,坐标为(-100,-300),将该四方形复制一份并缩小到90%后,
|
||||
// 新四边形的A点坐标为多少时可使新四边形的E点与原四边形的E点重合?
|
||||
// 预期效果:从图中选取某点(参照物)为中心点进行缩放,缩放时无论图像怎么变化,该点位置始终固定不变
|
||||
// 计算方法:以相同起点先计算缩放前后两点间的距离,再加上原图像偏移量即可
|
||||
e.x = num((e.x - offset.x) * (1 - scale / last));
|
||||
e.y = num((e.y - offset.y) * (1 - scale / last));
|
||||
changeImageRect(e);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
/**
|
||||
* 获取触摸点在哪个角
|
||||
* @param {number} x 触摸点x轴坐标
|
||||
* @param {number} y 触摸点y轴坐标
|
||||
* @return {number} 角的位置:0=无;1=左上;2=右上;3=左下;4=右下;
|
||||
*/
|
||||
function getToucheAngle(x, y) {
|
||||
// console.log('getToucheAngle', x, y, JSON.stringify(area))
|
||||
var o = area.angleBorderWidth; // 需扩大触发范围则把 o 值加大即可
|
||||
var oy = sys.navigation ? 0 : sys.windowTop;
|
||||
if(y >= area.top - o + oy && y <= area.top + area.angleSize + o + oy) {
|
||||
if(x >= area.left - o && x <= area.left + area.angleSize + o) {
|
||||
return 1; // 左上角
|
||||
} else if(x >= area.right - area.angleSize - o && x <= area.right + o) {
|
||||
return 2; // 右上角
|
||||
}
|
||||
} else if(y >= area.bottom - area.angleSize - o + oy && y <= area.bottom + o + oy) {
|
||||
if(x >= area.left - o && x <= area.left + area.angleSize + o) {
|
||||
return 3; // 左下角
|
||||
} else if(x >= area.right - area.angleSize - o && x <= area.right + o) {
|
||||
return 4; // 右下角
|
||||
}
|
||||
}
|
||||
return 0; // 无触摸到角
|
||||
};
|
||||
/**
|
||||
* 重置数据
|
||||
*/
|
||||
function resetData() {
|
||||
offset = { x: 0, y: 0 };
|
||||
scale = 1;
|
||||
minScale = img.minScale;
|
||||
rotate = 0;
|
||||
};
|
||||
function getTouchs(touches) {
|
||||
var result = [];
|
||||
var len = touches ? touches.length : 0
|
||||
for (var i = 0; i < len; i++) {
|
||||
result[i] = {
|
||||
pageX: touches[i].pageX,
|
||||
// h5无标题栏时,窗口顶部距离仍为标题栏高度,且触摸点y轴坐标还是有标题栏的值,即减去标题栏高度的值
|
||||
pageY: touches[i].pageY + sys.windowTop
|
||||
};
|
||||
}
|
||||
return result;
|
||||
};
|
||||
var mouseEvent = false;
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
imageStyles: {},
|
||||
maskStylesList: [{}, {}, {}, {}],
|
||||
borderStyles: {},
|
||||
gridStylesList: [{}, {}, {}, {}],
|
||||
angleStylesList: [{}, {}, {}, {}],
|
||||
circleBoxStyles: {},
|
||||
circleStyles: {}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 监听 PC 端鼠标滚轮
|
||||
// #ifdef H5
|
||||
platform === 'H5' && window.addEventListener('mousewheel', async (e) => {
|
||||
var touchs = getTouchs([e])
|
||||
img.src && scaleImage({
|
||||
instance: await this.getInstance(),
|
||||
check: true,
|
||||
// 鼠标向上滚动时,deltaY 固定 -100,鼠标向下滚动时,deltaY 固定 100
|
||||
scale: e.deltaY > 0 ? -0.05 : 0.05,
|
||||
x: touchs[0].pageX,
|
||||
y: touchs[0].pageY
|
||||
});
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
// #ifdef H5
|
||||
mounted() {
|
||||
platform === 'H5' && this.initH5Events();
|
||||
},
|
||||
// #endif
|
||||
setPlatform(p) {
|
||||
platform = p;
|
||||
},
|
||||
methods: {
|
||||
// #ifdef H5
|
||||
getTouchEvent(e) {
|
||||
e.touches = [
|
||||
{ pageX: e.pageX, pageY: e.pageY }
|
||||
];
|
||||
return e;
|
||||
},
|
||||
initH5Events() {
|
||||
const preview = document.getElementById('pic-preview');
|
||||
preview?.addEventListener('mousedown', (e, ev) => {
|
||||
mouseEvent = true;
|
||||
this.touchstart(this.getTouchEvent(e));
|
||||
});
|
||||
preview?.addEventListener('mousemove', (e) => {
|
||||
if (!mouseEvent) return;
|
||||
this.touchmove(this.getTouchEvent(e));
|
||||
});
|
||||
preview?.addEventListener('mouseup', (e) => {
|
||||
mouseEvent = false;
|
||||
this.touchend(this.getTouchEvent(e))
|
||||
});
|
||||
preview?.addEventListener('mouseleave', (e) => {
|
||||
mouseEvent = false;
|
||||
this.touchend(this.getTouchEvent(e))
|
||||
});
|
||||
},
|
||||
// #endif
|
||||
async getInstance() {
|
||||
// #ifdef APP-PLUS
|
||||
if(platform === 'APP')
|
||||
return this.$ownerInstance
|
||||
? Promise.resolve(this.$ownerInstance)
|
||||
: new Promise((resolve) => {
|
||||
setTimeout(async () => {
|
||||
resolve(await this.getInstance());
|
||||
});
|
||||
});
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
if(platform === 'H5')
|
||||
return Promise.resolve(this);
|
||||
// #endif
|
||||
},
|
||||
/**
|
||||
* 初始化:观察数据变更
|
||||
* @param {Object} newVal 新数据
|
||||
* @param {Object} oldVal 旧数据
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
initObserver: async function(newVal, oldVal, o, i) {
|
||||
// console.log('initObserver', newVal, oldVal, o, i)
|
||||
if(newVal && (!img.src || timestamp !== newVal.timestamp)) {
|
||||
timestamp = newVal.timestamp;
|
||||
img = newVal.img;
|
||||
sys = newVal.sys;
|
||||
area = newVal.area;
|
||||
minScale = img.minScale;
|
||||
resetData();
|
||||
const instance = await this.getInstance()
|
||||
img.src && changeImageRect({
|
||||
instance,
|
||||
x: (sys.windowWidth - img.width) / 2,
|
||||
y: (sys.windowHeight + sys.windowTop - sys.offsetBottom - img.height) / 2
|
||||
});
|
||||
changeAreaRect({
|
||||
instance
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 鼠标滚轮滚动
|
||||
* @param {Object} e 事件对象
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
mousewheel: function(e, o) {
|
||||
// h5平台 wheel 事件无法判断滚轮滑动方向,需使用 mousewheel
|
||||
},
|
||||
/**
|
||||
* 触摸开始
|
||||
* @param {Object} e 事件对象
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
touchstart: function(e, o) {
|
||||
if(!img.src) return;
|
||||
touches = getTouchs(e.touches);
|
||||
activeAngle = area.showAngle ? getToucheAngle(touches[0].pageX, touches[0].pageY) : 0;
|
||||
if(touches.length === 1 && activeAngle !== 0) {
|
||||
touchType = 'stretch'; // 伸缩裁剪区域
|
||||
} else {
|
||||
touchType = '';
|
||||
}
|
||||
// console.log('touchstart', e, activeAngle)
|
||||
},
|
||||
/**
|
||||
* 触摸移动
|
||||
* @param {Object} e 事件对象
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
touchmove: async function(e, o) {
|
||||
if(!img.src) return;
|
||||
// console.log('touchmove', e, o)
|
||||
e.touches = getTouchs(e.touches);
|
||||
if(touchType === 'stretch') { // 触摸四个角进行拉伸
|
||||
var point = e.touches[0];
|
||||
var start = touches[0];
|
||||
var x = point.pageX - start.pageX;
|
||||
var y = point.pageY - start.pageY;
|
||||
if(x !== 0 || y !== 0) {
|
||||
var maxX = num(area.width * (1 - area.minScale));
|
||||
var maxY = num(area.height * (1 - area.minScale));
|
||||
// console.log(x, y, maxX, maxY, offset, area)
|
||||
touches[0] = point;
|
||||
var r = rotate / 90 % 2;
|
||||
var m = r === 1 ? num((img.height - img.width) / 2) : 0; // 宽高差值一半
|
||||
var xCompare = r === 1 ? lessThanByFault(img.height, area.width) : lessThanByFault(img.width, area.width);
|
||||
var yCompare = r === 1 ? lessThanByFault(img.width, area.height) : lessThanByFault(img.height, area.height)
|
||||
var isInclude = xCompare && yCompare;
|
||||
var isIntersect = area.checkRange && (xCompare || yCompare); // 图片是否包含在裁剪区域内
|
||||
var isReverse = !isInclude || num((offset.x - area.left) / area.width) <= num((offset.y - area.top) / area.height) || (area.width > area.height && img.width < img.height && r === 1);
|
||||
switch(activeAngle) {
|
||||
case 1: // 左上角
|
||||
x = num(x + areaOffset.left);
|
||||
y = num(y + areaOffset.top);
|
||||
if(x >= 0 && y >= 0) { // 有效滑动
|
||||
var t = num(offset.y + m - area.top);
|
||||
var l = num(offset.x - m - area.left);
|
||||
// && (offset.x + img.width < area.right || offset.y + img.height < area.bottom)
|
||||
var max = isIntersect && ((l >= 0) || (t >= 0))
|
||||
? minimum(t, l)
|
||||
: false;
|
||||
if(x > y && isReverse) { // 以x轴滑动距离为缩放基准
|
||||
maxX = validMax(maxX, max, isInclude, l, t, area.width / area.height);
|
||||
if(x > maxX) x = maxX;
|
||||
y = num(x * area.height / area.width);
|
||||
} else { // 以y轴滑动距离为缩放基准
|
||||
maxY = validMax(maxY, max, isInclude, t, l, area.height / area.width);
|
||||
if(y > maxY) y = maxY;
|
||||
x = num(y * area.width / area.height);
|
||||
}
|
||||
areaOffset.left = x;
|
||||
areaOffset.top = y;
|
||||
}
|
||||
break;
|
||||
case 2: // 右上角
|
||||
x = num(x + areaOffset.right);
|
||||
y = num(y + areaOffset.top);
|
||||
if(x <= 0 && y >= 0) { // 有效滑动
|
||||
var w = (r === 1 ? img.height : img.width);
|
||||
var t = num(offset.y + m - area.top);
|
||||
var l = num(area.right + m - offset.x - w);
|
||||
var max = isIntersect && ((t >= 0) || (l >= 0))
|
||||
? minimum(t, l)
|
||||
: false;
|
||||
if(-x > y && isReverse) { // 以x轴滑动距离为缩放基准
|
||||
maxX = validMax(maxX, max, isInclude, l, t, area.width / area.height);
|
||||
if(-x > maxX) x = -maxX;
|
||||
y = num(-x * area.height / area.width);
|
||||
} else { // 以y轴滑动距离为缩放基准
|
||||
maxY = validMax(maxY, max, isInclude, t, l, area.height / area.width);
|
||||
if(y > maxY) y = maxY;
|
||||
x = num(-y * area.width / area.height);
|
||||
}
|
||||
areaOffset.right = x;
|
||||
areaOffset.top = y;
|
||||
}
|
||||
break;
|
||||
case 3: // 左下角
|
||||
x += num(x + areaOffset.left);
|
||||
y += num(y + areaOffset.bottom);
|
||||
if(x >= 0 && y <= 0) { // 有效滑动
|
||||
var w = (r === 1 ? img.width : img.height);
|
||||
var t = num(area.bottom - m - offset.y - w);
|
||||
var l = num(offset.x - m - area.left);
|
||||
var max = isIntersect && ((l >= 0) || (t >= 0))
|
||||
? minimum(t, l)
|
||||
: false;
|
||||
if(x > -y && isReverse) { // 以x轴滑动距离为缩放基准
|
||||
maxX = validMax(maxX, max, isInclude, l, t, area.width / area.height);
|
||||
if(x > maxX) x = maxX;
|
||||
y = num(-x * area.height / area.width);
|
||||
} else { // 以y轴滑动距离为缩放基准
|
||||
maxY = validMax(maxY, max, isInclude, t, l, area.height / area.width);
|
||||
if(-y > maxY) y = -maxY;
|
||||
x = num(-y * area.width / area.height);
|
||||
}
|
||||
areaOffset.left = x;
|
||||
areaOffset.bottom = y;
|
||||
}
|
||||
break;
|
||||
case 4: // 右下角
|
||||
x = num(x + areaOffset.right);
|
||||
y = num(y + areaOffset.bottom);
|
||||
if(x <= 0 && y <= 0) { // 有效滑动
|
||||
var w = (r === 1 ? img.height : img.width);
|
||||
var h = (r === 1 ? img.width : img.height);
|
||||
var t = num(area.bottom - offset.y - h - m);
|
||||
var l = num(area.right + m - offset.x - w);
|
||||
var max = isIntersect && ((l >= 0) || (t >= 0))
|
||||
? minimum(t, l)
|
||||
: false;
|
||||
if(-x > -y && isReverse) { // 以x轴滑动距离为缩放基准
|
||||
maxX = validMax(maxX, max, isInclude, l, t, area.width / area.height);
|
||||
if(-x > maxX) x = -maxX;
|
||||
y = num(x * area.height / area.width);
|
||||
} else { // 以y轴滑动距离为缩放基准
|
||||
maxY = validMax(maxY, max, isInclude, t, l, area.height / area.width);
|
||||
if(-y > maxY) y = -maxY;
|
||||
x = num(y * area.width / area.height);
|
||||
}
|
||||
areaOffset.right = x;
|
||||
areaOffset.bottom = y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// console.log(x, y, JSON.stringify(areaOffset))
|
||||
changeAreaRect({
|
||||
instance: await this.getInstance(),
|
||||
});
|
||||
// this.draw();
|
||||
}
|
||||
} else if (e.touches.length == 2) { // 双点触摸缩放
|
||||
var start = getDistanceByTouches(touches);
|
||||
var end = getDistanceByTouches(e.touches);
|
||||
scaleImage({
|
||||
instance: await this.getInstance(),
|
||||
check: !area.bounce,
|
||||
scale: (end.c - start.c) / 100,
|
||||
x: end.x,
|
||||
y: end.y
|
||||
});
|
||||
touchType = 'scale';
|
||||
} else if(touchType === 'scale') {// 从双点触摸变成单点触摸 / 从缩放变成拖动
|
||||
touchType = 'move';
|
||||
} else {
|
||||
changeImageRect({
|
||||
instance: await this.getInstance(),
|
||||
check: !area.bounce,
|
||||
x: e.touches[0].pageX - touches[0].pageX,
|
||||
y: e.touches[0].pageY - touches[0].pageY
|
||||
});
|
||||
touchType = 'move';
|
||||
}
|
||||
touches = e.touches;
|
||||
},
|
||||
/**
|
||||
* 触摸结束
|
||||
* @param {Object} e 事件对象
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
touchend: async function(e, o) {
|
||||
if(!img.src) return;
|
||||
if(touchType === 'stretch') { // 拉伸裁剪区域的四个角缩放
|
||||
// 裁剪区域宽度被缩放到多少
|
||||
var left = areaOffset.left;
|
||||
var right = areaOffset.right;
|
||||
var top = areaOffset.top;
|
||||
var bottom = areaOffset.bottom;
|
||||
var w = area.width + right - left;
|
||||
var h = area.height + bottom - top;
|
||||
// 图像放大倍数
|
||||
var p = scale * (area.width / w) - scale;
|
||||
// 复原裁剪区域
|
||||
areaOffset = { left: 0, right: 0, top: 0, bottom: 0 };
|
||||
changeAreaRect({
|
||||
instance: await this.getInstance(),
|
||||
});
|
||||
scaleImage({
|
||||
instance: await this.getInstance(),
|
||||
scale: p,
|
||||
x: area.left + left + (1 === activeAngle || 3 === activeAngle ? w : 0),
|
||||
y: area.top + top + (1 === activeAngle || 2 === activeAngle ? h : 0)
|
||||
});
|
||||
} else if (area.bounce) { // 检查边界并矫正,实现拖动到边界时有回弹效果
|
||||
changeImageRect({
|
||||
instance: await this.getInstance(),
|
||||
check: true
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 顺时针翻转图片90°
|
||||
* @param {Object} e 事件对象
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
rotateImage: async function(r) {
|
||||
rotate = (rotate + (r || 90)) % 360;
|
||||
|
||||
if(img.minScale >= 1 && area.checkRange) {
|
||||
// 因图片宽高可能不等,翻转后图片宽高需足够填满裁剪区域
|
||||
minScale = 1;
|
||||
if(img.width < area.height) {
|
||||
minScale = area.height / img.oldWidth;
|
||||
} else if(img.height < area.width) {
|
||||
minScale = area.width / img.oldHeight;
|
||||
}
|
||||
if(minScale !== 1) {
|
||||
scaleImage({
|
||||
instance: await this.getInstance(),
|
||||
scale: minScale - scale,
|
||||
x: sys.windowWidth / 2,
|
||||
y: (sys.windowHeight - sys.offsetBottom) / 2
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 由于拖动画布后会导致图片位置偏移,翻转时的旋转中心点需是图片区域+偏移区域的中心点
|
||||
// 翻转x轴中心点 = (超出裁剪区域右侧的图片宽度 - 超出裁剪区域左侧的图片宽度) / 2
|
||||
// 翻转y轴中心点 = (超出裁剪区域下方的图片宽度 - 超出裁剪区域上方的图片宽度) / 2
|
||||
var ox = ((offset.x + img.width - area.right) - (area.left - offset.x)) / 2;
|
||||
var oy = ((offset.y + img.height - area.bottom) - (area.top - offset.y)) / 2;
|
||||
changeImageRect({
|
||||
instance: await this.getInstance(),
|
||||
check: true,
|
||||
x: -ox - oy,
|
||||
y: -oy + ox
|
||||
});
|
||||
},
|
||||
rotateImage90: function() {
|
||||
this.rotateImage(90)
|
||||
},
|
||||
rotateImage270: function() {
|
||||
this.rotateImage(270)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,746 @@
|
||||
<template>
|
||||
<view class="image-cropper" :style="{ zIndex }" @wheel="cropper.mousewheel">
|
||||
<slot name="slotNamess" />
|
||||
<canvas v-if="use2d" type="2d" id="imgCanvas" class="img-canvas" :style="{
|
||||
width: `${canvansWidth}px`,
|
||||
height: `${canvansHeight}px`
|
||||
}"></canvas>
|
||||
<canvas v-else id="imgCanvas" canvas-id="imgCanvas" class="img-canvas" :style="{
|
||||
width: `${canvansWidth}px`,
|
||||
height: `${canvansHeight}px`
|
||||
}"></canvas>
|
||||
<view id="pic-preview" class="pic-preview" :change:init="cropper.initObserver" :init="initData" @touchstart="cropper.touchstart" @touchmove="cropper.touchmove" @touchend="cropper.touchend">
|
||||
<image v-if="imgSrc" id="crop-image" class="crop-image" :style="cropper.imageStyles" :src="imgSrc" webp></image>
|
||||
<view v-for="(item, index) in maskList" :key="item.id" :id="item.id" class="crop-mask-block" :style="cropper.maskStylesList[index]"></view>
|
||||
<view v-if="showBorder" id="crop-border" class="crop-border" :style="cropper.borderStyles"></view>
|
||||
<view v-if="radius > 0" id="crop-circle-box" class="crop-circle-box" :style="cropper.circleBoxStyles">
|
||||
<view class="crop-circle" id="crop-circle" :style="cropper.circleStyles"></view>
|
||||
</view>
|
||||
<block v-if="showGrid">
|
||||
<view v-for="(item, index) in gridList" :key="item.id" :id="item.id" class="crop-grid" :style="cropper.gridStylesList[index]"></view>
|
||||
</block>
|
||||
<block v-if="showAngle">
|
||||
<view v-for="(item, index) in angleList" :key="item.id" :id="item.id" class="crop-angle" :style="cropper.angleStylesList[index]">
|
||||
<view :style="[{
|
||||
width: `${angleSize}px`,
|
||||
height: `${angleSize}px`
|
||||
}]"></view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<view class="fixed-bottom safe-area-inset-bottom" :style="{ zIndex: initData.area.zIndex + 99 }">
|
||||
<!-- <view class="choose-btn" @click="cancleChoose">取消</view> -->
|
||||
<view v-if="(rotatable || reverseRotatable) && !!imgSrc" class="action-bar">
|
||||
<view v-if="reverseRotatable" class="rotate-icon" @click="cropper.rotateImage270"></view>
|
||||
<view v-if="rotatable" class="rotate-icon is-reverse" @click="cropper.rotateImage90"></view>
|
||||
</view>
|
||||
<view v-if="!choosable" class="choose-btn" @click="cropClick">确定</view>
|
||||
<block v-else-if="!!imgSrc">
|
||||
<view class="rechoose" @click="chooseImage">重选</view>
|
||||
<button class="button" size="mini" @click="cropClick">确定</button>
|
||||
</block>
|
||||
<view v-else class="choose-btn" @click="chooseImage">选择图片</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- #ifdef APP-VUE -->
|
||||
<script module="cropper" lang="renderjs">
|
||||
import cropper from './qf-image-cropper.render.js';
|
||||
// vue3 app renderjs中条件编译无效
|
||||
cropper.setPlatform('APP');
|
||||
export default {
|
||||
mixins: [ cropper ]
|
||||
}
|
||||
</script>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef H5 -->
|
||||
<script module="cropper" lang="renderjs">
|
||||
import cropper from './qf-image-cropper.render.js';
|
||||
export default {
|
||||
mixins: [ cropper ]
|
||||
}
|
||||
</script>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef MP-WEIXIN || MP-QQ -->
|
||||
<script module="cropper" lang="wxs" src="./qf-image-cropper.wxs"></script>
|
||||
<!-- #endif -->
|
||||
<script>
|
||||
/** 裁剪区域最大宽高所占屏幕宽度百分比 */
|
||||
const AREA_SIZE = 75;
|
||||
/** 图片默认宽高 */
|
||||
const IMG_SIZE = 300;
|
||||
|
||||
export default {
|
||||
name:"qf-image-cropper",
|
||||
// #ifdef MP-WEIXIN
|
||||
options: {
|
||||
// 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响
|
||||
styleIsolation: "isolated"
|
||||
},
|
||||
// #endif
|
||||
props: {
|
||||
/** 图片资源地址 */
|
||||
src: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 裁剪宽度,有些平台或设备对于canvas的尺寸有限制,过大可能会导致无法正常绘制 */
|
||||
width: {
|
||||
type: Number,
|
||||
default: IMG_SIZE
|
||||
},
|
||||
/** 裁剪高度,有些平台或设备对于canvas的尺寸有限制,过大可能会导致无法正常绘制 */
|
||||
height: {
|
||||
type: Number,
|
||||
default: IMG_SIZE
|
||||
},
|
||||
/** 是否绘制裁剪区域边框 */
|
||||
showBorder: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
/** 是否绘制裁剪区域网格参考线 */
|
||||
showGrid: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
/** 是否展示四个支持伸缩的角 */
|
||||
showAngle: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
/** 裁剪区域最小缩放倍数 */
|
||||
areaScale: {
|
||||
type: Number,
|
||||
default: 0.3
|
||||
},
|
||||
/** 图片最小缩放倍数 */
|
||||
minScale: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
/** 图片最大缩放倍数 */
|
||||
maxScale: {
|
||||
type: Number,
|
||||
default: 5
|
||||
},
|
||||
/** 检查图片位置是否超出裁剪边界,如果超出则会矫正位置 */
|
||||
checkRange: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
/** 生成图片背景色:如果裁剪区域没有完全包含在图片中时,不设置该属性生成图片存在一定的透明块 */
|
||||
backgroundColor: {
|
||||
type: String
|
||||
},
|
||||
/** 是否有回弹效果:当 checkRange 为 true 时有效,拖动时可以拖出边界,释放时会弹回边界 */
|
||||
bounce: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
/** 是否支持翻转 */
|
||||
rotatable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
/** 是否支持逆向翻转 */
|
||||
reverseRotatable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/** 是否支持从本地选择素材 */
|
||||
choosable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
/** 是否开启硬件加速,图片缩放过程中如果出现元素的“留影”或“重影”效果,可通过该方式解决或减轻这一问题 */
|
||||
gpu: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/** 四个角尺寸,单位px */
|
||||
angleSize: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
/** 四个角边框宽度,单位px */
|
||||
angleBorderWidth: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
zIndex: {
|
||||
type: [Number, String]
|
||||
},
|
||||
/** 裁剪图片圆角半径,单位px */
|
||||
radius: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
/** 生成文件的类型,只支持 'jpg' 或 'png'。默认为 'png' */
|
||||
fileType: {
|
||||
type: String,
|
||||
default: 'png'
|
||||
},
|
||||
/**
|
||||
* 图片从绘制到生成所需时间,单位ms
|
||||
* 微信小程序平台使用 `Canvas 2D` 绘制时有效
|
||||
* 如绘制大图或出现裁剪图片空白等情况应适当调大该值,因 `Canvas 2d` 采用同步绘制,需自己把控绘制完成时间
|
||||
*/
|
||||
delay: {
|
||||
type: Number,
|
||||
default: 1000
|
||||
},
|
||||
// #ifdef H5
|
||||
/**
|
||||
* 页面是否是原生标题栏
|
||||
* H5平台当 showAngle 为 true 时,使用插件的页面在 `page.json` 中配置了 "navigationStyle": "custom" 时,必须将此值设为 false ,否则四个可拉伸角的触发位置会有偏差。
|
||||
* 注:因H5平台的窗口高度是包含标题栏的,而屏幕触摸点的坐标是不包含的
|
||||
*/
|
||||
navigation: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
emits: ["crop"],
|
||||
data() {
|
||||
return {
|
||||
// 用不同 id 使 v-for key 不重复
|
||||
maskList: [
|
||||
{ id: 'crop-mask-block-1' },
|
||||
{ id: 'crop-mask-block-2' },
|
||||
{ id: 'crop-mask-block-3' },
|
||||
{ id: 'crop-mask-block-4' },
|
||||
],
|
||||
gridList: [
|
||||
{ id: 'crop-grid-1' },
|
||||
{ id: 'crop-grid-2' },
|
||||
{ id: 'crop-grid-3' },
|
||||
{ id: 'crop-grid-4' },
|
||||
],
|
||||
angleList: [
|
||||
{ id: 'crop-angle-1' },
|
||||
{ id: 'crop-angle-2' },
|
||||
{ id: 'crop-angle-3' },
|
||||
{ id: 'crop-angle-4' },
|
||||
],
|
||||
/** 本地缓存的图片路径 */
|
||||
imgSrc: '',
|
||||
/** 图片的裁剪宽度 */
|
||||
imgWidth: IMG_SIZE,
|
||||
/** 图片的裁剪高度 */
|
||||
imgHeight: IMG_SIZE,
|
||||
/** 裁剪区域最大宽度所占屏幕宽度百分比 */
|
||||
widthPercent: AREA_SIZE,
|
||||
/** 裁剪区域最大高度所占屏幕宽度百分比 */
|
||||
heightPercent: AREA_SIZE,
|
||||
/** 裁剪区域布局信息 */
|
||||
area: {},
|
||||
/** 未被缩放过的图片宽 */
|
||||
oldWidth: 0,
|
||||
/** 未被缩放过的图片高 */
|
||||
oldHeight: 0,
|
||||
/** 系统信息 */
|
||||
sys: uni.getSystemInfoSync(),
|
||||
scaleWidth: 0,
|
||||
scaleHeight: 0,
|
||||
rotate: 0,
|
||||
offsetX: 0,
|
||||
offsetY: 0,
|
||||
use2d: false,
|
||||
canvansWidth: 0,
|
||||
canvansHeight: 0,
|
||||
// imageStyles: {},
|
||||
// maskStylesList: [{}, {}, {}, {}],
|
||||
// borderStyles: {},
|
||||
// gridStylesList: [{}, {}, {}, {}],
|
||||
// angleStylesList: [{}, {}, {}, {}],
|
||||
// circleBoxStyles: {},
|
||||
// circleStyles: {},
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
initData() {
|
||||
// console.log('initData')
|
||||
return {
|
||||
timestamp: new Date().getTime(),
|
||||
area: {
|
||||
...this.area,
|
||||
bounce: this.bounce,
|
||||
showBorder: this.showBorder,
|
||||
showGrid: this.showGrid,
|
||||
showAngle: this.showAngle,
|
||||
angleSize: this.angleSize,
|
||||
angleBorderWidth: this.angleBorderWidth,
|
||||
minScale: this.areaScale,
|
||||
widthPercent: this.widthPercent,
|
||||
heightPercent: this.heightPercent,
|
||||
radius: this.radius,
|
||||
checkRange: this.checkRange,
|
||||
zIndex: +this.zIndex || 0,
|
||||
},
|
||||
sys: this.sys,
|
||||
img: {
|
||||
minScale: this.minScale,
|
||||
maxScale: this.maxScale,
|
||||
src: this.imgSrc,
|
||||
width: this.oldWidth,
|
||||
height: this.oldHeight,
|
||||
oldWidth: this.oldWidth,
|
||||
oldHeight: this.oldHeight,
|
||||
gpu: this.gpu,
|
||||
}
|
||||
}
|
||||
},
|
||||
imgProps() {
|
||||
return {
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
src: this.src,
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
imgProps: {
|
||||
handler(val, oldVal) {
|
||||
// 自定义裁剪尺,示例如下:
|
||||
this.imgWidth = Number(val.width) || IMG_SIZE;
|
||||
this.imgHeight = Number(val.height) || IMG_SIZE;
|
||||
let use2d = true;
|
||||
// #ifndef MP-WEIXIN
|
||||
use2d = false;
|
||||
// #endif
|
||||
// if(use2d && (this.imgWidth > 1365 || this.imgHeight > 1365)) {
|
||||
// use2d = false;
|
||||
// }
|
||||
let canvansWidth = this.imgWidth;
|
||||
let canvansHeight = this.imgHeight;
|
||||
let size = Math.max(canvansWidth, canvansHeight)
|
||||
let scalc = 1;
|
||||
if(size > 1365) {
|
||||
scalc = 1365 / size;
|
||||
}
|
||||
this.canvansWidth = canvansWidth * scalc;
|
||||
this.canvansHeight = canvansHeight * scalc;
|
||||
this.use2d = use2d;
|
||||
this.initArea();
|
||||
const src = val.src || this.imgSrc;
|
||||
src && this.initImage(src, oldVal === undefined);
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
/** 提供给wxs调用,用来接收图片变更数据 */
|
||||
dataChange(e) {
|
||||
// console.log('dataChange', e)
|
||||
this.scaleWidth = e.width;
|
||||
this.scaleHeight = e.height;
|
||||
this.rotate = e.rotate;
|
||||
this.offsetX = e.x;
|
||||
this.offsetY = e.y;
|
||||
},
|
||||
/** 初始化裁剪区域布局信息 */
|
||||
initArea() {
|
||||
// 底部操作栏高度 = 底部底部操作栏内容高度 + 设备底部安全区域高度
|
||||
this.sys.offsetBottom = uni.upx2px(100) + this.sys.safeAreaInsets.bottom;
|
||||
// #ifndef H5
|
||||
this.sys.windowTop = 0;
|
||||
this.sys.navigation = true;
|
||||
// #endif
|
||||
// #ifdef H5
|
||||
// h5平台的窗口高度是包含标题栏的
|
||||
this.sys.windowTop = this.sys.windowTop || 44;
|
||||
this.sys.navigation = this.navigation;
|
||||
// #endif
|
||||
let wp = this.widthPercent;
|
||||
let hp = this.heightPercent;
|
||||
if (this.imgWidth > this.imgHeight) {
|
||||
hp = hp * this.imgHeight / this.imgWidth;
|
||||
} else if (this.imgWidth < this.imgHeight) {
|
||||
wp = wp * this.imgWidth / this.imgHeight;
|
||||
}
|
||||
const size = this.sys.windowWidth > this.sys.windowHeight ? this.sys.windowHeight : this.sys.windowWidth;
|
||||
const width = size * wp / 100;
|
||||
const height = size * hp / 100;
|
||||
const left = (this.sys.windowWidth - width) / 2;
|
||||
const right = left + width;
|
||||
const top = (this.sys.windowHeight + this.sys.windowTop - this.sys.offsetBottom - height) / 2;
|
||||
const bottom = this.sys.windowHeight + this.sys.windowTop - this.sys.offsetBottom - top;
|
||||
this.area = { width, height, left, right, top, bottom };
|
||||
this.scaleWidth = width;
|
||||
this.scaleHeight = height;
|
||||
},
|
||||
/** 从本地选取图片 */
|
||||
chooseImage(options) {
|
||||
// #ifdef MP-WEIXIN || MP-JD
|
||||
if(uni.chooseMedia) {
|
||||
uni.chooseMedia({
|
||||
...options,
|
||||
count: 1,
|
||||
mediaType: ['image'],
|
||||
success: (res) => {
|
||||
this.resetData();
|
||||
this.initImage(res.tempFiles[0].tempFilePath);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
// #endif
|
||||
uni.chooseImage({
|
||||
...options,
|
||||
count: 1,
|
||||
success: (res) => {
|
||||
this.resetData();
|
||||
this.initImage(res.tempFiles[0].path);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** 重置数据 */
|
||||
resetData() {
|
||||
this.imgSrc = '';
|
||||
this.rotate = 0;
|
||||
this.offsetX = 0;
|
||||
this.offsetY = 0;
|
||||
this.initArea();
|
||||
},
|
||||
/**
|
||||
* 初始化图片信息
|
||||
* @param {String} url 图片链接
|
||||
*/
|
||||
initImage(url, isFirst) {
|
||||
uni.getImageInfo({
|
||||
src: url,
|
||||
success: async (res) => {
|
||||
if (isFirst && this.src === url) await (new Promise((resolve) => setTimeout(resolve, 50)));
|
||||
this.imgSrc = res.path;
|
||||
let scale = res.width / res.height;
|
||||
let areaScale = this.area.width / this.area.height;
|
||||
if (scale > 1) { // 横向图片
|
||||
if (scale >= areaScale) { // 图片宽不小于目标宽,则高固定,宽自适应
|
||||
this.scaleWidth = (this.scaleHeight / res.height) * this.scaleWidth * (res.width / this.scaleWidth);
|
||||
} else { // 否则宽固定、高自适应
|
||||
this.scaleHeight = res.height * this.scaleWidth / res.width;
|
||||
}
|
||||
} else { // 纵向图片
|
||||
if (scale <= areaScale) { // 图片高不小于目标高,宽固定,高自适应
|
||||
this.scaleHeight = (this.scaleWidth / res.width) * this.scaleHeight / (this.scaleHeight / res.height);
|
||||
} else { // 否则高固定,宽自适应
|
||||
this.scaleWidth = res.width * this.scaleHeight / res.height;
|
||||
}
|
||||
}
|
||||
// 记录原始宽高,为缩放比列做限制
|
||||
this.oldWidth = +this.scaleWidth.toFixed(2);
|
||||
this.oldHeight = +this.scaleHeight.toFixed(2);
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error(err)
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 剪切图片圆角
|
||||
* @param {Object} ctx canvas 的绘图上下文对象
|
||||
* @param {Number} radius 圆角半径
|
||||
* @param {Number} scale 生成图片的实际尺寸与截取区域比
|
||||
* @param {Function} drawImage 执行剪切时所调用的绘图方法,入参为是否执行了剪切
|
||||
*/
|
||||
drawClipImage(ctx, radius, scale, drawImage) {
|
||||
if(radius > 0) {
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
const w = this.canvansWidth;
|
||||
const h = this.canvansHeight;
|
||||
if(w === h && radius >= w / 2) { // 圆形
|
||||
ctx.arc(w / 2, h / 2, w / 2, 0, 2 * Math.PI);
|
||||
} else { // 圆角矩形
|
||||
if(w !== h) { // 限制圆角半径不能超过短边的一半
|
||||
radius = Math.min(w / 2, h / 2, radius);
|
||||
// radius = Math.min(Math.max(w, h) / 2, radius);
|
||||
}
|
||||
ctx.moveTo(radius, 0);
|
||||
ctx.arcTo(w, 0, w, h, radius);
|
||||
ctx.arcTo(w, h, 0, h, radius);
|
||||
ctx.arcTo(0, h, 0, 0, radius);
|
||||
ctx.arcTo(0, 0, w, 0, radius);
|
||||
ctx.closePath();
|
||||
}
|
||||
ctx.clip();
|
||||
drawImage && drawImage(true);
|
||||
ctx.restore();
|
||||
} else {
|
||||
drawImage && drawImage(false);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 旋转图片
|
||||
* @param {Object} ctx canvas 的绘图上下文对象
|
||||
* @param {Number} rotate 旋转角度
|
||||
* @param {Number} scale 生成图片的实际尺寸与截取区域比
|
||||
*/
|
||||
drawRotateImage(ctx, rotate, scale) {
|
||||
if(rotate !== 0) {
|
||||
// 1. 以图片中心点为旋转中心点
|
||||
const x = this.scaleWidth * scale / 2;
|
||||
const y = this.scaleHeight * scale / 2;
|
||||
ctx.translate(x, y);
|
||||
// 2. 旋转画布
|
||||
ctx.rotate(rotate * Math.PI / 180);
|
||||
// 3. 旋转完画布后恢复设置旋转中心时所做的偏移
|
||||
ctx.translate(-x, -y);
|
||||
}
|
||||
},
|
||||
drawImage(ctx, image, callback) {
|
||||
// 生成图片的实际尺寸与截取区域比
|
||||
const scale = this.canvansWidth / this.area.width;
|
||||
if(this.backgroundColor) {
|
||||
if(ctx.setFillStyle) ctx.setFillStyle(this.backgroundColor);
|
||||
else ctx.fillStyle = this.backgroundColor;
|
||||
ctx.fillRect(0, 0, this.canvansWidth, this.canvansHeight);
|
||||
}
|
||||
this.drawClipImage(ctx, this.radius, scale, () => {
|
||||
this.drawRotateImage(ctx, this.rotate, scale);
|
||||
const r = this.rotate / 90;
|
||||
ctx.drawImage(
|
||||
image,
|
||||
[
|
||||
(this.offsetX - this.area.left),
|
||||
(this.offsetY - this.area.top),
|
||||
-(this.offsetX - this.area.left),
|
||||
-(this.offsetY - this.area.top)
|
||||
][r] * scale,
|
||||
[
|
||||
(this.offsetY - this.area.top),
|
||||
-(this.offsetX - this.area.left),
|
||||
-(this.offsetY - this.area.top),
|
||||
(this.offsetX - this.area.left)
|
||||
][r] * scale,
|
||||
this.scaleWidth * scale,
|
||||
this.scaleHeight * scale
|
||||
);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 绘图
|
||||
* @param {Object} canvas
|
||||
* @param {Object} ctx canvas 的绘图上下文对象
|
||||
* @param {String} src 图片路径
|
||||
* @param {Function} callback 开始绘制时回调
|
||||
*/
|
||||
draw2DImage(canvas, ctx, src, callback) {
|
||||
// console.log('draw2DImage', canvas, ctx, src, callback)
|
||||
if(canvas) {
|
||||
const image = canvas.createImage();
|
||||
image.onload = () => {
|
||||
this.drawImage(ctx, image);
|
||||
// 如果觉得`生成时间过长`或`出现生成图片空白`可尝试调整延迟时间
|
||||
callback && setTimeout(callback, this.delay);
|
||||
};
|
||||
image.onerror = (err) => {
|
||||
console.error(err)
|
||||
uni.hideLoading();
|
||||
};
|
||||
image.src = src;
|
||||
} else {
|
||||
this.drawImage(ctx, src);
|
||||
setTimeout(() => {
|
||||
ctx.draw(false, callback);
|
||||
}, 200);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 画布转图片到本地缓存
|
||||
* @param {Object} canvas
|
||||
* @param {String} canvasId
|
||||
*/
|
||||
canvasToTempFilePath(canvas, canvasId) {
|
||||
// console.log('canvasToTempFilePath', canvas, canvasId)
|
||||
uni.canvasToTempFilePath({
|
||||
canvas,
|
||||
canvasId,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: this.canvansWidth,
|
||||
height: this.canvansHeight,
|
||||
destWidth: this.imgWidth, // 必要,保证生成图片宽度不受设备分辨率影响
|
||||
destHeight: this.imgHeight, // 必要,保证生成图片高度不受设备分辨率影响
|
||||
fileType: this.fileType, // 目标文件的类型,默认png
|
||||
success: (res) => {
|
||||
// 生成的图片临时文件路径
|
||||
this.handleImage(res.tempFilePath);
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: '裁剪失败,生成图片异常!', icon: 'none' });
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
/** 确认裁剪 */
|
||||
cropClick() {
|
||||
uni.showLoading({ title: '裁剪中...', mask: true });
|
||||
if(!this.use2d) {
|
||||
const ctx = uni.createCanvasContext('imgCanvas', this);
|
||||
ctx.clearRect(0, 0, this.canvansWidth, this.canvansHeight);
|
||||
this.draw2DImage(null, ctx, this.imgSrc, () => {
|
||||
this.canvasToTempFilePath(null, 'imgCanvas');
|
||||
});
|
||||
return;
|
||||
}
|
||||
// #ifdef MP-WEIXIN
|
||||
const query = uni.createSelectorQuery().in(this);
|
||||
query.select('#imgCanvas')
|
||||
.fields({ node: true, size: true })
|
||||
.exec((res) => {
|
||||
const canvas = res[0].node;
|
||||
|
||||
const dpr = uni.getSystemInfoSync().pixelRatio;
|
||||
canvas.width = res[0].width * dpr;
|
||||
canvas.height = res[0].height * dpr;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.scale(dpr, dpr);
|
||||
ctx.clearRect(0, 0, this.canvansWidth, this.canvansHeight);
|
||||
|
||||
this.draw2DImage(canvas, ctx, this.imgSrc, () => {
|
||||
this.canvasToTempFilePath(canvas);
|
||||
});
|
||||
});
|
||||
// #endif
|
||||
},
|
||||
handleImage(tempFilePath){
|
||||
// 在H5平台下,tempFilePath 为 base64
|
||||
// console.log(tempFilePath)
|
||||
uni.hideLoading();
|
||||
this.$emit('crop', { tempFilePath });
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.image-cropper {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #000;
|
||||
.img-canvas {
|
||||
position: absolute !important;
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
.pic-preview {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
position: relative;
|
||||
|
||||
.crop-mask-block {
|
||||
background-color: rgba(51, 51, 51, 0.8);
|
||||
z-index: 2;
|
||||
position: fixed;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
}
|
||||
.crop-circle-box {
|
||||
position: fixed;
|
||||
box-sizing: border-box;
|
||||
z-index: 2;
|
||||
pointer-events: none;
|
||||
overflow: hidden;
|
||||
.crop-circle {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.crop-image {
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
display: block !important;
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
.crop-border {
|
||||
position: fixed;
|
||||
border: 1px solid #fff;
|
||||
box-sizing: border-box;
|
||||
z-index: 3;
|
||||
pointer-events: none;
|
||||
}
|
||||
.crop-grid {
|
||||
position: fixed;
|
||||
z-index: 3;
|
||||
border-style: dashed;
|
||||
border-color: #fff;
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
.crop-angle {
|
||||
position: fixed;
|
||||
z-index: 3;
|
||||
border-style: solid;
|
||||
border-color: #fff;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
.fixed-bottom {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 99;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
background-color: $uni-bg-color-grey;
|
||||
|
||||
.action-bar {
|
||||
position: absolute;
|
||||
top: -90rpx;
|
||||
left: 10rpx;
|
||||
display: flex;
|
||||
.rotate-icon {
|
||||
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAABCFJREFUaEPtml3IpVMUx3//ko/ChTIyiGFSMyhllI8bc4F85yuNC2FCqLmQC1+FZORiEkUMNW7UjKjJULgxV+NzSkxDhEkZgwsyigv119J63p7zvOc8z37OmXdOb51dz82711r7/99r7bXXXucVi3xokeNnRqCvB20fDmwAlgK/5bcD+FTSr33tHXQP2H4MeHQE0A+B5yRtLiUyDQJrgVc6AAaBpyV93kXkoBMIQLbfBS5NcK8BRwDXNcD+AdwnaVMbiWkRCPBBohpxHuK7M7865sclRdgNHVMhkF6IMIpwirFEUhzo8M7lwIvASTXEqyVtH8ZgagQSbOzsDknv18HZXpHn5IL8+94IOUm7miSmSqAttjPdbgGuTrnNktYsGgLpoYuAD2qg1zRTbG8P2D4SOC6/Q7vSHPALsE/S7wWy80RsPw/ckxMfSTq/LtRJwPbxwF3ASiCUTxwHCPAnEBfVF8AWSTtL7Ng+LfWOTfmlkn6udFsJ5K15R6a4kvX6yGyUFBvTOWzHXXFzCt4g6c1OArYj9iIGh43YgR+BvztXh1PSa4cMkd0jaVmXDduPAE+k3HpJD7cSGFKvfAc8FQUX8IOk/V2L1udtB/hTgdOBW4Aba/M7Ja1qs2f7euCNlHlZUlx4/495IWQ7Jl+qGbxX0gt9AHfJ2o6zFBVoNVrDKe+F3Sm8VdK1bQQ+A85JgXckXdkFaJx527cC9TpnVdvBtl3h2iapuhsGPdBw1b9xnUvaNw7AEh3bnwDnpuwGSfeP0rN9NvAMELXRXFkxEEK2nwQeSiOtRVQJwC4Z29cAW1Nuu6TVXTrN+SaBt4ErUug2Sa/2NdhH3vZy4NvU2S/p6D768w5xI3WOrAD7LtISFpGdIhVXKfaYvjd20wP13L9M0p4DBbaFRKToSLExVkr6qs+aIwlI6iwz+izUQqC+ab29PiMwqRcmPXczD8w8MFj1zg7xXEqbpdHCw7FgWSjafZL+KcQxtpjteCeflwYulFR/J3TabSslVkj6utPChAK2f6q9uZdLitKieLQRuExSvX9ZbLRUMFs09efpUZL+KtUfVo1GW/umNHC3pOhRLtiwfSbwZS6wV9IJfRdreuBBYH0a2STp9r4G+8jbXgc8mzoDT8VSO00ClwDv1ZR7XyylC4ec7ejaLUmdsV6Aw7oSbwFXpdFdks7qA6pU1na0aR6owgeIR/1cx63UzjAC0YXYVjMQHlkn6ZtSo21ytuPZGKFagQ/xsXZ/3iGuFrYdjafXG0DiQMeBi47c9/GV3BO247UV38n5o0UAP6xmu7jFOGxjRr66On5NPBDOCBsDTapxjHY1dyOcolNXnYlx1himE53p2PmNkxosevfavhg4Izt2k7TXPwZ2S6p6QZPin/2rwcQ7OKmBohCadJGF1P8PG6aaQBKVX/8AAAAASUVORK5CYII=');
|
||||
background-size: 60% 60%;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
&.is-reverse {
|
||||
transform: rotateY(180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.rechoose {
|
||||
color: $uni-color-primary;
|
||||
padding: 0 $uni-spacing-row-lg;
|
||||
line-height: 100rpx;
|
||||
}
|
||||
|
||||
.choose-btn {
|
||||
color: $uni-color-primary;
|
||||
text-align: center;
|
||||
line-height: 100rpx;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin: auto $uni-spacing-row-lg auto auto;
|
||||
background-color: $uni-color-primary;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.safe-area-inset-bottom {
|
||||
padding-bottom: 0;
|
||||
padding-bottom: constant(safe-area-inset-bottom); // 兼容 IOS<11.2
|
||||
padding-bottom: env(safe-area-inset-bottom); // 兼容 IOS>=11.2
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,727 @@
|
||||
/**
|
||||
* 图片编辑器-手势监听
|
||||
* 1. wxs 暂不支持 es6 语法
|
||||
* 2. 支持编译到微信小程序、QQ小程序、app-vue、H5上(uni-app 2.2.5及以上版本)
|
||||
*/
|
||||
/** 图片偏移量 */
|
||||
var offset = { x: 0, y: 0 };
|
||||
/** 图片缩放比例 */
|
||||
var scale = 1;
|
||||
/** 图片最小缩放比例 */
|
||||
var minScale = 1;
|
||||
/** 图片旋转角度 */
|
||||
var rotate = 0;
|
||||
/** 触摸点 */
|
||||
var touches = [];
|
||||
/** 图片布局信息 */
|
||||
var img = {};
|
||||
/** 系统信息 */
|
||||
var sys = {};
|
||||
/** 裁剪区域布局信息 */
|
||||
var area = {};
|
||||
/** 触摸行为类型 */
|
||||
var touchType = '';
|
||||
/** 操作角的位置 */
|
||||
var activeAngle = 0;
|
||||
/** 裁剪区域布局信息偏移量 */
|
||||
var areaOffset = { left: 0, right: 0, top: 0, bottom: 0 };
|
||||
/** 容错值 */
|
||||
var fault = 0.000001;
|
||||
/**
|
||||
* 获取a、b两数中的最小正数
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
function minimum(a, b) {
|
||||
if (a > 0 && b < 0) return a;
|
||||
if (a < 0 && b > 0) return b;
|
||||
if (a > 0 && b > 0) return Math.min(a, b);
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* 在容错访问内获取n近似值
|
||||
* @param n
|
||||
*/
|
||||
function num(n) {
|
||||
var m = parseFloat((n).toFixed(6));
|
||||
return m === fault || m === -fault ? 0 : m;
|
||||
}
|
||||
/**
|
||||
* 比较a值在容错值范围内是否等于b值
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
function equalsByFault(a, b) {
|
||||
return Math.abs(a - b) <= fault;
|
||||
}
|
||||
/**
|
||||
* 比较a值在容错值范围内是否小于b值
|
||||
* @param a
|
||||
* @param b
|
||||
*/
|
||||
function lessThanByFault(a, b) {
|
||||
var c = a - b;
|
||||
return c < 0 ? c < -fault : c < fault;
|
||||
}
|
||||
/**
|
||||
* 验证并获取有效最大值
|
||||
* @param v
|
||||
* @param max
|
||||
* @param isInclude
|
||||
* @param x
|
||||
* @param y
|
||||
* @param rate
|
||||
* @returns
|
||||
*/
|
||||
function validMax(v, max, isInclude, x, y, rate) {
|
||||
if(typeof max === 'number') {
|
||||
if(isInclude && equalsByFault(max, y)) { // 宽高不等时,x轴用y轴值要做等比例转换
|
||||
var n = num(max * rate);
|
||||
if (n <= x) return n; // 转化后值在x轴最大值范围内
|
||||
return x; // 转化后值超出x轴最大值范围则用最大值
|
||||
}
|
||||
return max;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
/**
|
||||
* 计算两点间距
|
||||
* @param {Object} touches 触摸点信息
|
||||
*/
|
||||
function getDistanceByTouches(touches) {
|
||||
// 根据勾股定理求两点间距离
|
||||
var a = touches[1].pageX - touches[0].pageX;
|
||||
var b = touches[1].pageY - touches[0].pageY;
|
||||
var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
|
||||
// 求两点间的中点坐标
|
||||
// 1. a、b可能为负值
|
||||
// 2. 在求a、b时,如用touches[1]减touches[0],则求中点坐标也得用touches[1]减a/2、b/2
|
||||
// 3. 同理,在求a、b时,也可用touches[0]减touches[1],则求中点坐标也得用touches[0]减a/2、b/2
|
||||
var x = touches[1].pageX - a / 2;
|
||||
var y = touches[1].pageY - b / 2;
|
||||
return { c, x, y };
|
||||
};
|
||||
/**
|
||||
* 修正取值
|
||||
* @param {Object} a
|
||||
* @param {Object} b
|
||||
* @param {Object} c
|
||||
* @param {Object} reverse 是否反向
|
||||
*/
|
||||
function correctValue(a, b, c, reverse) {
|
||||
return num(reverse ? Math.max(Math.min(a, b), c) : Math.min(Math.max(a, b), c));
|
||||
}
|
||||
|
||||
/**
|
||||
* 旋转90°或270°时检查边界:限制 x、y 拖动范围,禁止滑出边界
|
||||
* @param {Object} e 点坐标
|
||||
* @param {Object} xReverse x是否反向
|
||||
* @param {Object} yReverse y是否反向
|
||||
*/
|
||||
function checkRotateRange(e, xReverse, yReverse) {
|
||||
var o = num((img.height - img.width) / 2); // 宽高差值一半
|
||||
return {
|
||||
x: correctValue(e.x, -img.height + o + area.width + area.left, area.left + o, xReverse),
|
||||
y: correctValue(e.y, -img.width - o + area.height + area.top, area.top - o, yReverse)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查边界:限制 x、y 拖动范围,禁止滑出边界
|
||||
* @param {Object} e 点坐标
|
||||
*/
|
||||
function checkRange(e) {
|
||||
var r = rotate / 90 % 2;
|
||||
if(r === 1) { // 因图片宽高可能不等,翻转 90° 或 270° 后图片宽高需反着计算,且左右和上下边界要根据差值做偏移
|
||||
if (area.width === area.height) {
|
||||
return checkRotateRange(e, img.height < area.height, img.width < area.width);
|
||||
}
|
||||
var isInclude = img.height < area.width && img.width < area.height; // 图片是否包含在裁剪区域内
|
||||
if (img.width < area.height || img.height < area.width) {
|
||||
if (area.width < area.height && img.width < img.height) {
|
||||
return isInclude
|
||||
? checkRotateRange(e, area.width < area.height, area.width < area.height)
|
||||
: checkRotateRange(e, false, true);
|
||||
}
|
||||
if (area.height < area.width && img.height < img.width) {
|
||||
return isInclude
|
||||
? checkRotateRange(e, area.height < area.width, area.height < area.width)
|
||||
: checkRotateRange(e, true, false);
|
||||
}
|
||||
}
|
||||
if (img.height >= area.width && img.width >= area.height) {
|
||||
return checkRotateRange(e, false, false);
|
||||
}
|
||||
if (isInclude) {
|
||||
return area.height < area.width
|
||||
? checkRotateRange(e, true, true)
|
||||
: checkRotateRange(e, area.width < area.height, area.width < area.height);
|
||||
}
|
||||
if (img.height < area.width && !img.width < area.height) {
|
||||
return checkRotateRange(e, true, false);
|
||||
}
|
||||
if (!img.height < area.width && img.width < area.height) {
|
||||
return checkRotateRange(e, false, true);
|
||||
}
|
||||
return checkRotateRange(e, img.height < area.height, img.width < area.width);
|
||||
}
|
||||
return {
|
||||
x: correctValue(e.x, -img.width + area.width + area.left, area.left, img.width < area.width),
|
||||
y: correctValue(e.y, -img.height + area.height + area.top, area.top, img.height < area.height)
|
||||
};
|
||||
};
|
||||
/**
|
||||
* 变更图片布局信息
|
||||
* @param {Object} e 布局信息
|
||||
*/
|
||||
function changeImageRect(e) {
|
||||
offset.x += e.x || 0;
|
||||
offset.y += e.y || 0;
|
||||
var image = e.instance.selectComponent('.crop-image');
|
||||
if(e.check && area.checkRange) { // 检查边界
|
||||
var point = checkRange(offset);
|
||||
if(offset.x !== point.x || offset.y !== point.y) {
|
||||
offset = point;
|
||||
}
|
||||
}
|
||||
// image.setStyle({
|
||||
// width: img.width + 'px',
|
||||
// height: img.height + 'px',
|
||||
// transform: 'translate(' + offset.x + 'px, ' + offset.y + 'px) rotate(' + rotate +'deg)'
|
||||
// });
|
||||
var ox = (img.width - img.oldWidth) / 2;
|
||||
var oy = (img.height - img.oldHeight) / 2;
|
||||
image.setStyle({
|
||||
width: img.oldWidth + 'px',
|
||||
height: img.oldHeight + 'px',
|
||||
transform: (img.gpu ? 'translateZ(0) ' : '') + 'translate(' + (offset.x + ox) + 'px, ' + (offset.y + oy) + 'px) rotate(' + rotate +'deg) scale(' + scale + ')'
|
||||
});
|
||||
|
||||
e.instance.callMethod('dataChange', {
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
x: offset.x,
|
||||
y: offset.y,
|
||||
rotate: rotate
|
||||
});
|
||||
};
|
||||
/**
|
||||
* 变更裁剪区域布局信息
|
||||
* @param {Object} e 布局信息
|
||||
*/
|
||||
function changeAreaRect(e) {
|
||||
// 变更蒙版样式
|
||||
var masks = e.instance.selectAllComponents('.crop-mask-block');
|
||||
var maskStyles = [
|
||||
{
|
||||
left: 0,
|
||||
width: (area.left + areaOffset.left) + 'px',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
'z-index': area.zIndex + 2
|
||||
},
|
||||
{
|
||||
left: (area.right + areaOffset.right) + 'px',
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
'z-index': area.zIndex + 2
|
||||
},
|
||||
{
|
||||
left: (area.left + areaOffset.left) + 'px',
|
||||
width: (area.width + areaOffset.right - areaOffset.left) + 'px',
|
||||
top: 0,
|
||||
height: (area.top + areaOffset.top) + 'px',
|
||||
'z-index': area.zIndex + 2
|
||||
},
|
||||
{
|
||||
left: (area.left + areaOffset.left) + 'px',
|
||||
width: (area.width + areaOffset.right - areaOffset.left) + 'px',
|
||||
top: (area.bottom + areaOffset.bottom) + 'px',
|
||||
// height: (area.top - areaOffset.bottom + sys.offsetBottom) + 'px',
|
||||
bottom: 0,
|
||||
'z-index': area.zIndex + 2
|
||||
}
|
||||
];
|
||||
var len = masks.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
masks[i].setStyle(maskStyles[i]);
|
||||
}
|
||||
|
||||
// 变更边框样式
|
||||
if(area.showBorder) {
|
||||
var border = e.instance.selectComponent('.crop-border');
|
||||
border.setStyle({
|
||||
left: (area.left + areaOffset.left) + 'px',
|
||||
top: (area.top + areaOffset.top) + 'px',
|
||||
width: (area.width + areaOffset.right - areaOffset.left) + 'px',
|
||||
height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
});
|
||||
}
|
||||
|
||||
// 变更参考线样式
|
||||
if(area.showGrid) {
|
||||
var grids = e.instance.selectAllComponents('.crop-grid');
|
||||
var gridStyles = [
|
||||
{
|
||||
'border-width': '1px 0 0 0',
|
||||
left: (area.left + areaOffset.left) + 'px',
|
||||
right: (area.right + areaOffset.right) + 'px',
|
||||
top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) / 3 - 0.5) + 'px',
|
||||
width: (area.width + areaOffset.right - areaOffset.left) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
},
|
||||
{
|
||||
'border-width': '1px 0 0 0',
|
||||
left: (area.left + areaOffset.left) + 'px',
|
||||
right: (area.right + areaOffset.right) + 'px',
|
||||
top: (area.top + areaOffset.top + (area.height + areaOffset.bottom - areaOffset.top) * 2 / 3 - 0.5) + 'px',
|
||||
width: (area.width + areaOffset.right - areaOffset.left) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
},
|
||||
{
|
||||
'border-width': '0 1px 0 0',
|
||||
top: (area.top + areaOffset.top) + 'px',
|
||||
bottom: (area.bottom + areaOffset.bottom) + 'px',
|
||||
left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) / 3 - 0.5) + 'px',
|
||||
height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
},
|
||||
{
|
||||
'border-width': '0 1px 0 0',
|
||||
top: (area.top + areaOffset.top) + 'px',
|
||||
bottom: (area.bottom + areaOffset.bottom) + 'px',
|
||||
left: (area.left + areaOffset.left + (area.width + areaOffset.right - areaOffset.left) * 2 / 3 - 0.5) + 'px',
|
||||
height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
}
|
||||
];
|
||||
var len = grids.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
grids[i].setStyle(gridStyles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 变更四个伸缩角样式
|
||||
if(area.showAngle) {
|
||||
var angles = e.instance.selectAllComponents('.crop-angle');
|
||||
var angleStyles = [
|
||||
{
|
||||
'border-width': area.angleBorderWidth + 'px 0 0 ' + area.angleBorderWidth + 'px',
|
||||
left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px',
|
||||
top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
},
|
||||
{
|
||||
'border-width': area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0 0',
|
||||
left: (area.right + areaOffset.right - area.angleSize) + 'px',
|
||||
top: (area.top + areaOffset.top - area.angleBorderWidth) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
},
|
||||
{
|
||||
'border-width': '0 0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px',
|
||||
left: (area.left + areaOffset.left - area.angleBorderWidth) + 'px',
|
||||
top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
},
|
||||
{
|
||||
'border-width': '0 ' + area.angleBorderWidth + 'px ' + area.angleBorderWidth + 'px 0',
|
||||
left: (area.right + areaOffset.right - area.angleSize) + 'px',
|
||||
top: (area.bottom + areaOffset.bottom - area.angleSize) + 'px',
|
||||
'z-index': area.zIndex + 3
|
||||
}
|
||||
];
|
||||
var len = angles.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
angles[i].setStyle(angleStyles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// 变更圆角样式
|
||||
if(area.radius > 0) {
|
||||
var circleBox = e.instance.selectComponent('.crop-circle-box');
|
||||
var circle = e.instance.selectComponent('.crop-circle');
|
||||
var radius = area.radius;
|
||||
if(area.width === area.height && area.radius >= area.width / 2) { // 圆形
|
||||
radius = (area.width / 2);
|
||||
} else { // 圆角矩形
|
||||
if(area.width !== area.height) { // 限制圆角半径不能超过短边的一半
|
||||
radius = Math.min(area.width / 2, area.height / 2, radius);
|
||||
}
|
||||
}
|
||||
circleBox.setStyle({
|
||||
left: (area.left + areaOffset.left) + 'px',
|
||||
top: (area.top + areaOffset.top) + 'px',
|
||||
width: (area.width + areaOffset.right - areaOffset.left) + 'px',
|
||||
height: (area.height + areaOffset.bottom - areaOffset.top) + 'px',
|
||||
'z-index': area.zIndex + 2
|
||||
});
|
||||
circle.setStyle({
|
||||
'box-shadow': '0 0 0 ' + Math.max(area.width, area.height) + 'px rgba(51, 51, 51, 0.8)',
|
||||
'border-radius': radius + 'px'
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
* 缩放图片
|
||||
* @param {Object} e 布局信息
|
||||
*/
|
||||
function scaleImage(e) {
|
||||
var last = scale;
|
||||
scale = Math.min(Math.max(e.scale + scale, minScale), img.maxScale);
|
||||
if(last !== scale) {
|
||||
img.width = num(img.oldWidth * scale);
|
||||
img.height = num(img.oldHeight * scale);
|
||||
// 参考问题:有一个长4000px、宽4000px的四方形ABCD,A点的坐标固定在(-2000,-2000),
|
||||
// 该四边形上有一个点E,坐标为(-100,-300),将该四方形复制一份并缩小到90%后,
|
||||
// 新四边形的A点坐标为多少时可使新四边形的E点与原四边形的E点重合?
|
||||
// 预期效果:从图中选取某点(参照物)为中心点进行缩放,缩放时无论图像怎么变化,该点位置始终固定不变
|
||||
// 计算方法:以相同起点先计算缩放前后两点间的距离,再加上原图像偏移量即可
|
||||
e.x = num((e.x - offset.x) * (1 - scale / last));
|
||||
e.y = num((e.y - offset.y) * (1 - scale / last));
|
||||
changeImageRect(e);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
/**
|
||||
* 获取触摸点在哪个角
|
||||
* @param {number} x 触摸点x轴坐标
|
||||
* @param {number} y 触摸点y轴坐标
|
||||
* @return {number} 角的位置:0=无;1=左上;2=右上;3=左下;4=右下;
|
||||
*/
|
||||
function getToucheAngle(x, y) {
|
||||
// console.log('getToucheAngle', x, y, JSON.stringify(area))
|
||||
var o = area.angleBorderWidth; // 需扩大触发范围则把 o 值加大即可
|
||||
if(y >= area.top - o && y <= area.top + area.angleSize + o) {
|
||||
if(x >= area.left - o && x <= area.left + area.angleSize + o) {
|
||||
return 1; // 左上角
|
||||
} else if(x >= area.right - area.angleSize - o && x <= area.right + o) {
|
||||
return 2; // 右上角
|
||||
}
|
||||
} else if(y >= area.bottom - area.angleSize - o && y <= area.bottom + o) {
|
||||
if(x >= area.left - o && x <= area.left + area.angleSize + o) {
|
||||
return 3; // 左下角
|
||||
} else if(x >= area.right - area.angleSize - o && x <= area.right + o) {
|
||||
return 4; // 右下角
|
||||
}
|
||||
}
|
||||
return 0; // 无触摸到角
|
||||
};
|
||||
/**
|
||||
* 重置数据
|
||||
*/
|
||||
function resetData() {
|
||||
offset = { x: 0, y: 0 };
|
||||
scale = 1;
|
||||
minScale = img.minScale;
|
||||
rotate = 0;
|
||||
};
|
||||
/**
|
||||
* 顺时针翻转图片90°
|
||||
* @param {Object} e 事件对象
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
function rotateImage(e, o, r) {
|
||||
rotate = (rotate + r) % 360;
|
||||
if(img.minScale >= 1 && area.checkRange) {
|
||||
// 因图片宽高可能不等,翻转后图片宽高需足够填满裁剪区域
|
||||
minScale = 1;
|
||||
if(img.width < area.height) {
|
||||
minScale = area.height / img.oldWidth;
|
||||
} else if(img.height < area.width) {
|
||||
minScale = area.width / img.oldHeight;
|
||||
}
|
||||
if(minScale !== 1) {
|
||||
scaleImage({
|
||||
instance: o,
|
||||
scale: minScale - scale,
|
||||
x: sys.windowWidth / 2,
|
||||
y: (sys.windowHeight - sys.offsetBottom) / 2
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 由于拖动画布后会导致图片位置偏移,翻转时的旋转中心点需是图片区域+偏移区域的中心点
|
||||
// 翻转x轴中心点 = (超出裁剪区域右侧的图片宽度 - 超出裁剪区域左侧的图片宽度) / 2
|
||||
// 翻转y轴中心点 = (超出裁剪区域下方的图片宽度 - 超出裁剪区域上方的图片宽度) / 2
|
||||
var ox = ((offset.x + img.width - area.right) - (area.left - offset.x)) / 2;
|
||||
var oy = ((offset.y + img.height - area.bottom) - (area.top - offset.y)) / 2;
|
||||
changeImageRect({
|
||||
instance: o,
|
||||
check: true,
|
||||
x: -ox - oy,
|
||||
y: -oy + ox
|
||||
});
|
||||
};
|
||||
module.exports = {
|
||||
/**
|
||||
* 初始化:观察数据变更
|
||||
* @param {Object} newVal 新数据
|
||||
* @param {Object} oldVal 旧数据
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
initObserver: function(newVal, oldVal, o, i) {
|
||||
if(newVal) {
|
||||
img = newVal.img;
|
||||
sys = newVal.sys;
|
||||
area = newVal.area;
|
||||
minScale = img.minScale;
|
||||
resetData();
|
||||
img.src && changeImageRect({
|
||||
instance: o,
|
||||
x: (sys.windowWidth - img.width) / 2,
|
||||
y: (sys.windowHeight - sys.offsetBottom - img.height) / 2
|
||||
});
|
||||
changeAreaRect({
|
||||
instance: o
|
||||
});
|
||||
// console.log('initRect', JSON.stringify(newVal))
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 鼠标滚轮滚动
|
||||
* @param {Object} e 事件对象
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
mousewheel: function(e, o) {
|
||||
if(!img.src) return;
|
||||
scaleImage({
|
||||
instance: o,
|
||||
check: true,
|
||||
// 鼠标向上滚动时,deltaY 固定 -100,鼠标向下滚动时,deltaY 固定 100
|
||||
scale: e.detail.deltaY > 0 ? -0.05 : 0.05,
|
||||
x: e.touches[0].pageX,
|
||||
y: e.touches[0].pageY
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 触摸开始
|
||||
* @param {Object} e 事件对象
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
touchstart: function(e, o) {
|
||||
if(!img.src) return;
|
||||
touches = e.touches;
|
||||
activeAngle = area.showAngle ? getToucheAngle(touches[0].pageX, touches[0].pageY) : 0;
|
||||
if(touches.length === 1 && activeAngle !== 0) {
|
||||
touchType = 'stretch'; // 伸缩裁剪区域
|
||||
} else {
|
||||
touchType = '';
|
||||
}
|
||||
// console.log('touchstart', JSON.stringify(e), activeAngle)
|
||||
},
|
||||
/**
|
||||
* 触摸移动
|
||||
* @param {Object} e 事件对象
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
touchmove: function(e, o) {
|
||||
if(!img.src) return;
|
||||
// console.log('touchmove', JSON.stringify(e), JSON.stringify(o))
|
||||
if(touchType === 'stretch') { // 触摸四个角进行拉伸
|
||||
var point = e.touches[0];
|
||||
var start = touches[0];
|
||||
var x = point.pageX - start.pageX;
|
||||
var y = point.pageY - start.pageY;
|
||||
if(x !== 0 || y !== 0) {
|
||||
var maxX = num(area.width * (1 - area.minScale));
|
||||
var maxY = num(area.height * (1 - area.minScale));
|
||||
// console.log(x, y, maxX, maxY, offset, area)
|
||||
touches[0] = point;
|
||||
var r = rotate / 90 % 2;
|
||||
var m = r === 1 ? num((img.height - img.width) / 2) : 0; // 宽高差值一半
|
||||
var xCompare = r === 1 ? lessThanByFault(img.height, area.width) : lessThanByFault(img.width, area.width);
|
||||
var yCompare = r === 1 ? lessThanByFault(img.width, area.height) : lessThanByFault(img.height, area.height)
|
||||
var isInclude = xCompare && yCompare;
|
||||
var isIntersect = area.checkRange && (xCompare || yCompare); // 图片是否包含在裁剪区域内
|
||||
var isReverse = !isInclude || num((offset.x - area.left) / area.width) <= num((offset.y - area.top) / area.height) || (area.width > area.height && img.width < img.height && r === 1);
|
||||
switch(activeAngle) {
|
||||
case 1: // 左上角
|
||||
x = num(x + areaOffset.left);
|
||||
y = num(y + areaOffset.top);
|
||||
if(x >= 0 && y >= 0) { // 有效滑动
|
||||
var t = num(offset.y + m - area.top);
|
||||
var l = num(offset.x - m - area.left);
|
||||
// && (offset.x + img.width < area.right || offset.y + img.height < area.bottom)
|
||||
var max = isIntersect && ((l >= 0) || (t >= 0))
|
||||
? minimum(t, l)
|
||||
: false;
|
||||
if(x > y && isReverse) { // 以x轴滑动距离为缩放基准
|
||||
maxX = validMax(maxX, max, isInclude, l, t, area.width / area.height);
|
||||
if(x > maxX) x = maxX;
|
||||
y = num(x * area.height / area.width);
|
||||
} else { // 以y轴滑动距离为缩放基准
|
||||
maxY = validMax(maxY, max, isInclude, t, l, area.height / area.width);
|
||||
if(y > maxY) y = maxY;
|
||||
x = num(y * area.width / area.height);
|
||||
}
|
||||
areaOffset.left = x;
|
||||
areaOffset.top = y;
|
||||
}
|
||||
break;
|
||||
case 2: // 右上角
|
||||
x = num(x + areaOffset.right);
|
||||
y = num(y + areaOffset.top);
|
||||
if(x <= 0 && y >= 0) { // 有效滑动
|
||||
var w = (r === 1 ? img.height : img.width);
|
||||
var t = num(offset.y + m - area.top);
|
||||
var l = num(area.right + m - offset.x - w);
|
||||
var max = isIntersect && ((t >= 0) || (l >= 0))
|
||||
? minimum(t, l)
|
||||
: false;
|
||||
// var max = isInclude && ((offset.x > 0 && offset.x + img.width <= area.right) || (offset.y > 0 && offset.y >= area.top))
|
||||
// ? minimum(offset.y - area.top, area.right - offset.x - img.width)
|
||||
// : false;
|
||||
// console.log(offset.x, offset.y, img.width, img.height, area.top, area.right, m, max)
|
||||
// console.log(offset.y + m - area.top, area.right + m - offset.x - w)
|
||||
if(-x > y && isReverse) { // 以x轴滑动距离为缩放基准
|
||||
maxX = validMax(maxX, max, isInclude, l, t, area.width / area.height);
|
||||
if(-x > maxX) x = -maxX;
|
||||
y = num(-x * area.height / area.width);
|
||||
} else { // 以y轴滑动距离为缩放基准
|
||||
maxY = validMax(maxY, max, isInclude, t, l, area.height / area.width);
|
||||
if(y > maxY) y = maxY;
|
||||
x = num(-y * area.width / area.height);
|
||||
}
|
||||
areaOffset.right = x;
|
||||
areaOffset.top = y;
|
||||
}
|
||||
break;
|
||||
case 3: // 左下角
|
||||
x += num(x + areaOffset.left);
|
||||
y += num(y + areaOffset.bottom);
|
||||
if(x >= 0 && y <= 0) { // 有效滑动
|
||||
var w = (r === 1 ? img.width : img.height);
|
||||
var t = num(area.bottom - m - offset.y - w);
|
||||
var l = num(offset.x - m - area.left);
|
||||
var max = isIntersect && ((l >= 0) || (t >= 0))
|
||||
? minimum(t, l)
|
||||
: false;
|
||||
if(x > -y && isReverse) { // 以x轴滑动距离为缩放基准
|
||||
maxX = validMax(maxX, max, isInclude, l, t, area.width / area.height);
|
||||
if(x > maxX) x = maxX;
|
||||
y = num(-x * area.height / area.width);
|
||||
} else { // 以y轴滑动距离为缩放基准
|
||||
maxY = validMax(maxY, max, isInclude, t, l, area.height / area.width);
|
||||
if(-y > maxY) y = -maxY;
|
||||
x = num(-y * area.width / area.height);
|
||||
}
|
||||
areaOffset.left = x;
|
||||
areaOffset.bottom = y;
|
||||
}
|
||||
break;
|
||||
case 4: // 右下角
|
||||
x = num(x + areaOffset.right);
|
||||
y = num(y + areaOffset.bottom);
|
||||
if(x <= 0 && y <= 0) { // 有效滑动
|
||||
var w = (r === 1 ? img.height : img.width);
|
||||
var h = (r === 1 ? img.width : img.height);
|
||||
var t = num(area.bottom - offset.y - h - m);
|
||||
var l = num(area.right + m - offset.x - w);
|
||||
var max = isIntersect && ((l >= 0) || (t >= 0))
|
||||
? minimum(t, l)
|
||||
: false;
|
||||
if(-x > -y && isReverse) { // 以x轴滑动距离为缩放基准
|
||||
maxX = validMax(maxX, max, isInclude, l, t, area.width / area.height);
|
||||
if(-x > maxX) x = -maxX;
|
||||
y = num(x * area.height / area.width);
|
||||
} else { // 以y轴滑动距离为缩放基准
|
||||
maxY = validMax(maxY, max, isInclude, t, l, area.height / area.width);
|
||||
if(-y > maxY) y = -maxY;
|
||||
x = num(y * area.width / area.height);
|
||||
}
|
||||
areaOffset.right = x;
|
||||
areaOffset.bottom = y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// console.log(x, y, JSON.stringify(areaOffset))
|
||||
changeAreaRect({
|
||||
instance: o,
|
||||
});
|
||||
// this.draw();
|
||||
}
|
||||
} else if (e.touches.length == 2) { // 双点触摸缩放
|
||||
var start = getDistanceByTouches(touches);
|
||||
var end = getDistanceByTouches(e.touches);
|
||||
scaleImage({
|
||||
instance: o,
|
||||
check: !area.bounce,
|
||||
scale: (end.c - start.c) / 100,
|
||||
x: end.x,
|
||||
y: end.y
|
||||
});
|
||||
touchType = 'scale';
|
||||
} else if(touchType === 'scale') {// 从双点触摸变成单点触摸 / 从缩放变成拖动
|
||||
touchType = 'move';
|
||||
} else {
|
||||
changeImageRect({
|
||||
instance: o,
|
||||
check: !area.bounce,
|
||||
x: e.touches[0].pageX - touches[0].pageX,
|
||||
y: e.touches[0].pageY - touches[0].pageY
|
||||
});
|
||||
touchType = 'move';
|
||||
}
|
||||
touches = e.touches;
|
||||
},
|
||||
/**
|
||||
* 触摸结束
|
||||
* @param {Object} e 事件对象
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
touchend: function(e, o) {
|
||||
if(!img.src) return;
|
||||
if(touchType === 'stretch') { // 拉伸裁剪区域的四个角缩放
|
||||
// 裁剪区域宽度被缩放到多少
|
||||
var left = areaOffset.left;
|
||||
var right = areaOffset.right;
|
||||
var top = areaOffset.top;
|
||||
var bottom = areaOffset.bottom;
|
||||
var w = area.width + right - left;
|
||||
var h = area.height + bottom - top;
|
||||
// 图像放大倍数
|
||||
var p = scale * (area.width / w) - scale;
|
||||
// 复原裁剪区域
|
||||
areaOffset = { left: 0, right: 0, top: 0, bottom: 0 };
|
||||
changeAreaRect({
|
||||
instance: o,
|
||||
});
|
||||
scaleImage({
|
||||
instance: o,
|
||||
scale: p,
|
||||
x: area.left + left + (1 === activeAngle || 3 === activeAngle ? w : 0),
|
||||
y: area.top + top + (1 === activeAngle || 2 === activeAngle ? h : 0)
|
||||
});
|
||||
} else if (area.bounce) { // 检查边界并矫正,实现拖动到边界时有回弹效果
|
||||
changeImageRect({
|
||||
instance: o,
|
||||
check: true
|
||||
});
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 顺时针翻转图片90°
|
||||
* @param {Object} e 事件对象
|
||||
* @param {Object} o 组件实例对象
|
||||
*/
|
||||
rotateImage: function(e, o) {
|
||||
rotateImage(e, o, 90);
|
||||
},
|
||||
rotateImage90: function(e, o) {
|
||||
rotateImage(e, o, 90)
|
||||
},
|
||||
rotateImage270: function(e, o) {
|
||||
rotateImage(e, o, 270)
|
||||
},
|
||||
// 此处只用于对齐其他平台端的样式参数,防止异常,无作用
|
||||
imageStyles: '',
|
||||
maskStylesList: ['', '', '', ''],
|
||||
borderStyles: '',
|
||||
gridStylesList: ['', '', '', ''],
|
||||
angleStylesList: ['', '', '', ''],
|
||||
circleBoxStyles: '',
|
||||
circleStyles: '',
|
||||
}
|
||||
81
uni_modules/qf-image-cropper/package.json
Normal file
81
uni_modules/qf-image-cropper/package.json
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"id": "qf-image-cropper",
|
||||
"displayName": "图片裁剪插件",
|
||||
"version": "2.2.5",
|
||||
"description": "图片裁剪插件,支持自定义尺寸、定点等比例缩放、拖动、图片翻转、剪切圆形/圆角图片、定制样式,功能多性能高体验好注释全。",
|
||||
"keywords": [
|
||||
"qf-image-cropper",
|
||||
"图片裁剪",
|
||||
"图片编辑",
|
||||
"头像裁剪",
|
||||
"小程序"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "n"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "u"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "u",
|
||||
"IE": "u",
|
||||
"Edge": "u",
|
||||
"Firefox": "u",
|
||||
"Safari": "u"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "y",
|
||||
"阿里": "n",
|
||||
"百度": "n",
|
||||
"字节跳动": "n",
|
||||
"QQ": "u",
|
||||
"钉钉": "n",
|
||||
"快手": "n",
|
||||
"飞书": "n",
|
||||
"京东": "n"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "n",
|
||||
"联盟": "n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
97
uni_modules/qf-image-cropper/readme.md
Normal file
97
uni_modules/qf-image-cropper/readme.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# qf-image-cropper
|
||||
## 图片裁剪插件
|
||||
uniapp微信小程序图片裁剪插件,支持自定义尺寸、定点等比例缩放、拖动、图片翻转、剪切圆形/圆角图片、定制样式,功能多性能高体验好注释全。
|
||||
|
||||
### 平台支持:
|
||||
1. 支持微信小程序:移动端、PC端、开发者工具
|
||||
2. 支持H5平台(2.1.0版本起)
|
||||
3. 支持APP平台(2.1.5版本起):Android、IOS
|
||||
4. 其他平台暂未测试兼容性未知
|
||||
|
||||
### 支持功能:
|
||||
1. 自定义裁剪尺寸
|
||||
2. 定点等比例缩放:移动端以双指触摸中心点为缩放中心点,PC端以鼠标所在点为缩放中心点
|
||||
3. 自由拖动:支持限制滑出边界,也支持回弹效果(滑动时可滑出边界,释放时回弹到边界)
|
||||
4. 图片翻转:在裁剪尺寸非 1:1 的情况下,翻转时宽高无法铺满裁剪区域时,图片会自动放大到合适尺寸
|
||||
5. 裁剪生成新图片
|
||||
6. 本地选择图片
|
||||
7. 可定制样式:可自由选择是否渲染裁剪边框、可伸缩裁剪顶角、参考线
|
||||
8. 裁剪圆角图片:圆形、圆角矩形
|
||||
|
||||
### 属性说明
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
|:---|:---|:---|:---|
|
||||
| src | String | | 图片资源地址 |
|
||||
| width | Number | 300 | 裁剪宽度 |
|
||||
| height | Number | 300 | 裁剪高度 |
|
||||
| showBorder | Boolean | true | 是否绘制裁剪区域边框 |
|
||||
| showGrid | Boolean | true | 是否绘制裁剪区域网格参考线 |
|
||||
| showAngle | Boolean | true | 是否展示四个支持伸缩的角 |
|
||||
| areaScale | Number | 0.3 | 裁剪区域最小缩放倍数 |
|
||||
| minScale | Number | 1 | 图片最小缩放倍数 |
|
||||
| maxScale | Number | 5 | 图片最大缩放倍数 |
|
||||
| checkRange | Boolean | true | 检查图片位置是否超出裁剪边界,如果超出则会矫正位置 |
|
||||
| backgroundColor | String | | 生成图片背景色:如果裁剪区域没有完全包含在图片中时,不设置该属性则生成图片存在一定的透明块 |
|
||||
| bounce | Boolean | true | 是否有回弹效果:当 checkRange 为 true 时有效,拖动时可以拖出边界,释放时会弹回边界 |
|
||||
| rotatable | Boolean | true | 是否支持翻转 |
|
||||
| reverseRotatable | Boolean | false | 是否支持逆向翻转 |
|
||||
| choosable | Boolean | true | 是否支持从本地选择素材 |
|
||||
| gpu | Boolean | false | 是否开启硬件加速,图片缩放过程中如果出现元素的“留影”或“重影”效果,可通过该方式解决或减轻这一问题 |
|
||||
| angleSize | Number | 20 | 四个角尺寸,单位px |
|
||||
| angleBorderWidth | Number | 2 | 四个角边框宽度,单位px |
|
||||
| zIndex | Number/String | | 调整组件层级 |
|
||||
| radius | Number | | 裁剪图片圆角半径,单位px |
|
||||
| fileType | String | png | 生成文件的类型,只支持 'jpg' 或 'png'。默认为 'png' |
|
||||
| delay | Number | 1000 | 图片从绘制到生成所需时间,单位ms<br>微信小程序平台使用 `Canvas 2D` 绘制时有效<br>如绘制大图或出现裁剪图片空白等情况应适当调大该值,因 `Canvas 2d` 采用同步绘制,需自己把控绘制完成时间 |
|
||||
| navigation | Boolean | true | 页面是否是原生标题栏:<br>H5平台当 showAngle 为 true 时,使用插件的页面在 `page.json` 中配置了 `"navigationStyle": "custom"` 时,必须将此值设为 false ,否则四个可拉伸角的触发位置会有偏差。<br>注:因H5平台的窗口高度是包含标题栏的,而屏幕触摸点的坐标是不包含的 |
|
||||
| @crop | EventHandle | | 剪裁完成后触发,event = { tempFilePath }。在H5平台下,tempFilePath 为 base64 |
|
||||
|
||||
### 基本用法
|
||||
```
|
||||
<template>
|
||||
<div>
|
||||
<qf-image-cropper :width="500" :height="500" :radius="30" @crop="handleCrop"></qf-image-cropper>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import QfImageCropper from '@/components/qf-image-cropper/qf-image-cropper.vue';
|
||||
export default {
|
||||
components: {
|
||||
QfImageCropper
|
||||
},
|
||||
methods: {
|
||||
handleCrop(e) {
|
||||
uni.previewImage({
|
||||
urls: [e.tempFilePath],
|
||||
current: 0
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
通过ref组件实例可在进入页面后直接打开相册选择图片
|
||||
```
|
||||
mounted() {
|
||||
this.$refs.qfImageCropper.chooseImage({ sourceType: ['album'] });
|
||||
}
|
||||
```
|
||||
### 使用说明
|
||||
1.建议在`pages.json`中将引用插件的页面添加一下配置禁止下拉刷新和禁止页面滑动,防止出现性能或页面抖动等问题。
|
||||
```
|
||||
{
|
||||
"enablePullDownRefresh": false,
|
||||
"disableScroll": true
|
||||
}
|
||||
```
|
||||
2.建议使用本插件不要设置过大宽高的目标图片尺寸,建议1365x1365以内,否则可能会导致如下问题:
|
||||
```
|
||||
1.界面卡顿,内存占用过高
|
||||
2.生成图片失真(模糊)
|
||||
3.确定裁剪后一直显示 `裁剪中...`,该问题是由 `uni.canvasToTempFilePath` 无法回调导致,不同平台不同设备限制可能有所不同。
|
||||
```
|
||||
3.如裁剪后的图片存在偏移的问题,请检查是否受自己项目中父组件或全局样式影响。
|
||||
4.src属性设置网络图片时,图片资源必须是能触发 `getImageInfo` API 的 success 回调才可用于插件裁剪。因此小程序平台获取网络图片信息需先配置download域名白名单才能生效。
|
||||
5.如果组件无法正常渲染且使用了 `v-if` 时,可尝试将 `v-if` 替换为 `v-show`
|
||||
6.如果App端导入组件后无法正常渲染,请尝试重新运行
|
||||
@@ -1,17 +1,23 @@
|
||||
## 1.4.10(2023-04-10)
|
||||
- 修复 某些情况 monthSwitch 未触发的Bug
|
||||
## 1.4.9(2023-02-02)
|
||||
- 修复 某些情况切换月份错误的Bug
|
||||
## 1.4.8(2023-01-30)
|
||||
- 修复 某些情况切换月份错误的Bug [详情](https://ask.dcloud.net.cn/question/161964)
|
||||
## 1.4.7(2022-09-16)
|
||||
- 可以使用 uni-scss 控制主题色
|
||||
- 优化 支持使用 uni-scss 控制主题色
|
||||
## 1.4.6(2022-09-08)
|
||||
- fix: 表头年月切换,导致改变当前日期为选择月1号,且未触发change事件
|
||||
- 修复 表头年月切换,导致改变当前日期为选择月1号,且未触发change事件的Bug
|
||||
## 1.4.5(2022-02-25)
|
||||
- 修复 条件编译 nvue 不支持的 css 样式
|
||||
- 修复 条件编译 nvue 不支持的 css 样式的Bug
|
||||
## 1.4.4(2022-02-25)
|
||||
- 修复 条件编译 nvue 不支持的 css 样式
|
||||
- 修复 条件编译 nvue 不支持的 css 样式的Bug
|
||||
## 1.4.3(2021-09-22)
|
||||
- 修复 startDate、 endDate 属性失效的 bug
|
||||
- 修复 startDate、 endDate 属性失效的Bug
|
||||
## 1.4.2(2021-08-24)
|
||||
- 新增 支持国际化
|
||||
## 1.4.1(2021-08-05)
|
||||
- 修复 弹出层被 tabbar 遮盖 bug
|
||||
- 修复 弹出层被 tabbar 遮盖的Bug
|
||||
## 1.4.0(2021-07-30)
|
||||
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||
## 1.3.16(2021-05-12)
|
||||
|
||||
@@ -51,11 +51,10 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
initVueI18n
|
||||
} from '@dcloudio/uni-i18n'
|
||||
import messages from './i18n/index.js'
|
||||
const { t } = initVueI18n(messages)
|
||||
import { initVueI18n } from '@dcloudio/uni-i18n'
|
||||
import i18nMessages from './i18n/index.js'
|
||||
const { t } = initVueI18n(i18nMessages)
|
||||
|
||||
export default {
|
||||
emits:['change'],
|
||||
props: {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<view class="uni-calendar__header-btn-box" @click.stop="next">
|
||||
<view class="uni-calendar__header-btn uni-calendar--right"></view>
|
||||
</view>
|
||||
<text class="uni-calendar__backtoday" @click="backtoday">{{todayText}}</text>
|
||||
<text class="uni-calendar__backtoday" @click="backToday">{{todayText}}</text>
|
||||
|
||||
</view>
|
||||
<view class="uni-calendar__box">
|
||||
@@ -62,12 +62,12 @@
|
||||
|
||||
<script>
|
||||
import Calendar from './util.js';
|
||||
import calendarItem from './uni-calendar-item.vue'
|
||||
import {
|
||||
initVueI18n
|
||||
} from '@dcloudio/uni-i18n'
|
||||
import messages from './i18n/index.js'
|
||||
const { t } = initVueI18n(messages)
|
||||
import CalendarItem from './uni-calendar-item.vue'
|
||||
|
||||
import { initVueI18n } from '@dcloudio/uni-i18n'
|
||||
import i18nMessages from './i18n/index.js'
|
||||
const { t } = initVueI18n(i18nMessages)
|
||||
|
||||
/**
|
||||
* Calendar 日历
|
||||
* @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
|
||||
@@ -90,7 +90,7 @@
|
||||
*/
|
||||
export default {
|
||||
components: {
|
||||
calendarItem
|
||||
CalendarItem
|
||||
},
|
||||
emits:['close','confirm','change','monthSwitch'],
|
||||
props: {
|
||||
@@ -199,26 +199,26 @@
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 获取日历方法实例
|
||||
this.cale = new Calendar({
|
||||
// date: new Date(),
|
||||
selected: this.selected,
|
||||
startDate: this.startDate,
|
||||
endDate: this.endDate,
|
||||
range: this.range,
|
||||
})
|
||||
// 选中某一天
|
||||
// this.cale.setDate(this.date)
|
||||
this.init(this.date)
|
||||
// this.setDay
|
||||
},
|
||||
methods: {
|
||||
// 取消穿透
|
||||
clean() {},
|
||||
bindDateChange(e) {
|
||||
const value = e.detail.value + '-1'
|
||||
console.log(this.cale.getDate(value));
|
||||
this.setDate(value)
|
||||
|
||||
const { year,month } = this.cale.getDate(value)
|
||||
this.$emit('monthSwitch', {
|
||||
year,
|
||||
month
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 初始化日期显示
|
||||
@@ -323,11 +323,16 @@
|
||||
/**
|
||||
* 回到今天
|
||||
*/
|
||||
backtoday() {
|
||||
console.log(this.cale.getDate(new Date()).fullDate);
|
||||
let date = this.cale.getDate(new Date()).fullDate
|
||||
// this.cale.setDate(date)
|
||||
this.init(date)
|
||||
backToday() {
|
||||
const nowYearMonth = `${this.nowDate.year}-${this.nowDate.month}`
|
||||
const date = this.cale.getDate(new Date())
|
||||
const todayYearMonth = `${date.year}-${date.month}`
|
||||
|
||||
if(nowYearMonth !== todayYearMonth) {
|
||||
this.monthSwitch()
|
||||
}
|
||||
|
||||
this.init(date.fullDate)
|
||||
this.change()
|
||||
},
|
||||
/**
|
||||
@@ -446,7 +451,6 @@
|
||||
|
||||
.uni-calendar--fixed-width {
|
||||
width: 50px;
|
||||
// padding: 0 15px;
|
||||
}
|
||||
|
||||
.uni-calendar__backtoday {
|
||||
|
||||
@@ -76,10 +76,20 @@ class Calendar {
|
||||
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break
|
||||
case 'month':
|
||||
if (dd.getDate() === 31) {
|
||||
if (dd.getDate() === 31 && AddDayCount>0) {
|
||||
dd.setDate(dd.getDate() + AddDayCount)
|
||||
} else {
|
||||
dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
const preMonth = dd.getMonth()
|
||||
dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期
|
||||
const nextMonth = dd.getMonth()
|
||||
// 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
|
||||
if(AddDayCount<0 && preMonth!==0 && nextMonth-preMonth>AddDayCount){
|
||||
dd.setMonth(nextMonth+(nextMonth-preMonth+AddDayCount))
|
||||
}
|
||||
// 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
|
||||
if(AddDayCount>0 && nextMonth-preMonth>AddDayCount){
|
||||
dd.setMonth(nextMonth-(nextMonth-preMonth-AddDayCount))
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'year':
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-calendar",
|
||||
"displayName": "uni-calendar 日历",
|
||||
"version": "1.4.7",
|
||||
"version": "1.4.10",
|
||||
"description": "日历组件",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
|
||||
@@ -77,7 +77,7 @@ export default {
|
||||
### Calendar Props
|
||||
|
||||
| 属性名 | 类型 | 默认值| 说明 |
|
||||
| | |
|
||||
| - | - | - | - |
|
||||
| date | String |- | 自定义当前时间,默认为今天 |
|
||||
| lunar | Boolean | false | 显示农历 |
|
||||
| startDate | String |- | 日期选择范围-开始日期 |
|
||||
@@ -91,7 +91,7 @@ export default {
|
||||
### Calendar Events
|
||||
|
||||
| 事件名 | 说明 |返回值|
|
||||
| | | |
|
||||
| - | - | - |
|
||||
| open | 弹出日历组件,`insert :false` 时生效|- |
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
## 1.4.4(2024-03-20)
|
||||
- 修复 titleBorder类型修正
|
||||
## 1.4.3(2022-01-25)
|
||||
- 修复 初始化的时候 ,open 属性失效的bug
|
||||
## 1.4.2(2022-01-21)
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
* @property {String} name 唯一标志符
|
||||
* @property {Boolean} open = [true|false] 是否展开组件
|
||||
* @property {Boolean} titleBorder = [true|false] 是否显示标题分隔线
|
||||
* @property {Boolean} border = [true|false] 是否显示分隔线
|
||||
* @property {String} border = ['auto'|'show'|'none'] 是否显示分隔线
|
||||
* @property {Boolean} disabled = [true|false] 是否展开面板
|
||||
* @property {Boolean} showAnimation = [true|false] 开启动画
|
||||
* @property {Boolean} showArrow = [true|false] 是否显示右侧箭头
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-collapse",
|
||||
"displayName": "uni-collapse 折叠面板",
|
||||
"version": "1.4.3",
|
||||
"version": "1.4.4",
|
||||
"description": "Collapse 组件,可以折叠 / 展开的内容区域。",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
@@ -17,10 +17,6 @@
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
@@ -37,7 +33,8 @@
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
|
||||
@@ -5,9 +5,5 @@
|
||||
"main": "index.js",
|
||||
"keywords": [],
|
||||
"author": "DCloud",
|
||||
"license": "Apache-2.0",
|
||||
"origin-plugin-dev-name": "uni-config-center",
|
||||
"origin-plugin-version": "0.0.3",
|
||||
"plugin-dev-name": "uni-config-center",
|
||||
"plugin-version": "0.0.3"
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
@@ -1,3 +1,12 @@
|
||||
## 1.1.2(2023-04-11)
|
||||
- 修复 更改 modelValue 报错的 bug
|
||||
- 修复 v-for 未使用 key 值控制台 warning
|
||||
## 1.1.1(2023-02-21)
|
||||
- 修复代码合并时引发 value 属性为空时不渲染数据的问题
|
||||
## 1.1.0(2023-02-15)
|
||||
- 修复 localdata 不支持动态更新的bug
|
||||
## 1.0.9(2023-02-15)
|
||||
- 修复 localdata 不支持动态更新的bug
|
||||
## 1.0.8(2022-09-16)
|
||||
- 可以使用 uni-scss 控制主题色
|
||||
## 1.0.7(2022-07-06)
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
</view>
|
||||
</scroll-view>
|
||||
<text v-else class="selected-area placeholder">{{placeholder}}</text>
|
||||
<view v-if="clearIcon && !readonly && inputSelected.length" class="icon-clear"
|
||||
@click.stop="clear">
|
||||
<view v-if="clearIcon && !readonly && inputSelected.length" class="icon-clear" @click.stop="clear">
|
||||
<uni-icons type="clear" color="#c0c4cc" size="24"></uni-icons>
|
||||
</view>
|
||||
<view class="arrow-area" v-if="(!clearIcon || !inputSelected.length) && !readonly ">
|
||||
@@ -40,8 +39,8 @@
|
||||
</view>
|
||||
<data-picker-view class="picker-view" ref="pickerView" v-model="dataValue" :localdata="localdata"
|
||||
:preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where"
|
||||
:step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true"
|
||||
:map="map" :ellipsis="ellipsis" @change="onchange" @datachange="ondatachange" @nodeclick="onnodeclick">
|
||||
:step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true" :map="map"
|
||||
:ellipsis="ellipsis" @change="onchange" @datachange="ondatachange" @nodeclick="onnodeclick">
|
||||
</data-picker-view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -76,7 +75,7 @@
|
||||
*/
|
||||
export default {
|
||||
name: 'UniDataPicker',
|
||||
emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change', 'update:modelValue'],
|
||||
emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change', 'update:modelValue','inputclick'],
|
||||
mixins: [dataPicker],
|
||||
components: {
|
||||
DataPickerView
|
||||
@@ -128,58 +127,49 @@
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.form = this.getForm('uniForms')
|
||||
this.formItem = this.getForm('uniFormsItem')
|
||||
if (this.formItem) {
|
||||
if (this.formItem.name) {
|
||||
this.rename = this.formItem.name
|
||||
this.form.inputChildrens.push(this)
|
||||
}
|
||||
}
|
||||
|
||||
this.$nextTick(() => {
|
||||
this.load()
|
||||
this.load();
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
localdata: {
|
||||
handler() {
|
||||
this.load()
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
clear() {
|
||||
this.inputSelected.splice(0)
|
||||
this._dispatchEvent([])
|
||||
this._dispatchEvent([]);
|
||||
},
|
||||
onPropsChange() {
|
||||
this._treeData = []
|
||||
this.selectedIndex = 0
|
||||
this.load()
|
||||
this._treeData = [];
|
||||
this.selectedIndex = 0;
|
||||
|
||||
this.load();
|
||||
},
|
||||
load() {
|
||||
if (this.readonly) {
|
||||
this._processReadonly(this.localdata, this.dataValue)
|
||||
return
|
||||
this._processReadonly(this.localdata, this.dataValue);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.isLocaldata) {
|
||||
this.loadData()
|
||||
this.inputSelected = this.selected.slice(0)
|
||||
} else if (!this.parentField && !this.selfField && this.hasValue) {
|
||||
this.getNodeData(() => {
|
||||
this.inputSelected = this.selected.slice(0)
|
||||
})
|
||||
} else if (this.hasValue) {
|
||||
this.getTreePath(() => {
|
||||
this.inputSelected = this.selected.slice(0)
|
||||
// 回显本地数据
|
||||
if (this.isLocalData) {
|
||||
this.loadData();
|
||||
this.inputSelected = this.selected.slice(0);
|
||||
} else if (this.isCloudDataList || this.isCloudDataTree) { // 回显 Cloud 数据
|
||||
this.loading = true;
|
||||
this.getCloudDataValue().then((res) => {
|
||||
this.loading = false;
|
||||
this.inputSelected = res;
|
||||
}).catch((err) => {
|
||||
this.loading = false;
|
||||
this.errorMessage = err;
|
||||
})
|
||||
}
|
||||
},
|
||||
getForm(name = 'uniForms') {
|
||||
let parent = this.$parent;
|
||||
let parentName = parent.$options.name;
|
||||
while (parentName !== name) {
|
||||
parent = parent.$parent;
|
||||
if (!parent) return false;
|
||||
parentName = parent.$options.name;
|
||||
}
|
||||
return parent;
|
||||
},
|
||||
show() {
|
||||
this.isOpened = true
|
||||
setTimeout(() => {
|
||||
@@ -197,6 +187,7 @@
|
||||
},
|
||||
handleInput() {
|
||||
if (this.readonly) {
|
||||
this.$emit('inputclick')
|
||||
return
|
||||
}
|
||||
this.show()
|
||||
@@ -413,7 +404,12 @@
|
||||
.uni-data-tree-dialog {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
/* #ifndef APP-NVUE */
|
||||
top: 20%;
|
||||
/* #endif */
|
||||
/* #ifdef APP-NVUE */
|
||||
top: 200px;
|
||||
/* #endif */
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #FFFFFF;
|
||||
@@ -436,7 +432,7 @@
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
/* border-bottom: 1px solid #f5f5f5; */
|
||||
/* border-bottom: 1px solid #f0f0f0; */
|
||||
}
|
||||
|
||||
.title-area {
|
||||
@@ -505,7 +501,7 @@
|
||||
max-height: 50vh;
|
||||
background-color: #fff;
|
||||
border: 1px solid #EBEEF5;
|
||||
box-shadow: 0px 0px 3px 0px rgba(0, 82, 79, 0.65);
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
overflow: unset;
|
||||
}
|
||||
@@ -550,5 +546,6 @@
|
||||
border-top-width: 0;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</style>
|
||||
|
||||
@@ -42,7 +42,7 @@ export default {
|
||||
},
|
||||
pageSize: {
|
||||
type: Number,
|
||||
default: 20
|
||||
default: 500
|
||||
},
|
||||
getcount: {
|
||||
type: [Boolean, String],
|
||||
@@ -122,19 +122,22 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isLocaldata() {
|
||||
return !this.collection.length
|
||||
isLocalData() {
|
||||
return !this.collection.length;
|
||||
},
|
||||
postField() {
|
||||
let fields = [this.field];
|
||||
if (this.parentField) {
|
||||
fields.push(`${this.parentField} as parent_value`);
|
||||
}
|
||||
return fields.join(',');
|
||||
isCloudData() {
|
||||
return this.collection.length > 0;
|
||||
},
|
||||
isCloudDataList() {
|
||||
return (this.isCloudData && (!this.parentField && !this.selfField));
|
||||
},
|
||||
isCloudDataTree() {
|
||||
return (this.isCloudData && this.parentField && this.selfField);
|
||||
},
|
||||
dataValue() {
|
||||
let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null || this.modelValue !== undefined)
|
||||
return isModelValue ? this.modelValue : this.value
|
||||
let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null ||
|
||||
this.modelValue !== undefined);
|
||||
return isModelValue ? this.modelValue : this.value;
|
||||
},
|
||||
hasValue() {
|
||||
if (typeof this.dataValue === 'number') {
|
||||
@@ -183,8 +186,169 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
onPropsChange() {
|
||||
this._treeData = []
|
||||
this._treeData = [];
|
||||
},
|
||||
|
||||
// 填充 pickview 数据
|
||||
async loadData() {
|
||||
if (this.isLocalData) {
|
||||
this.loadLocalData();
|
||||
} else if (this.isCloudDataList) {
|
||||
this.loadCloudDataList();
|
||||
} else if (this.isCloudDataTree) {
|
||||
this.loadCloudDataTree();
|
||||
}
|
||||
},
|
||||
|
||||
// 加载本地数据
|
||||
async loadLocalData() {
|
||||
this._treeData = [];
|
||||
this._extractTree(this.localdata, this._treeData);
|
||||
|
||||
let inputValue = this.dataValue;
|
||||
if (inputValue === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(inputValue)) {
|
||||
inputValue = inputValue[inputValue.length - 1];
|
||||
if (typeof inputValue === 'object' && inputValue[this.map.value]) {
|
||||
inputValue = inputValue[this.map.value];
|
||||
}
|
||||
}
|
||||
|
||||
this.selected = this._findNodePath(inputValue, this.localdata);
|
||||
},
|
||||
|
||||
// 加载 Cloud 数据 (单列)
|
||||
async loadCloudDataList() {
|
||||
if (this.loading) {
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
let response = await this.getCommand();
|
||||
let responseData = response.result.data;
|
||||
|
||||
this._treeData = responseData;
|
||||
|
||||
this._updateBindData();
|
||||
this._updateSelected();
|
||||
|
||||
this.onDataChange();
|
||||
} catch (e) {
|
||||
this.errorMessage = e;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 加载 Cloud 数据 (树形)
|
||||
async loadCloudDataTree() {
|
||||
if (this.loading) {
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
let commandOptions = {
|
||||
field: this._cloudDataPostField(),
|
||||
where: this._cloudDataTreeWhere()
|
||||
};
|
||||
if (this.gettree) {
|
||||
commandOptions.startwith = `${this.selfField}=='${this.dataValue}'`;
|
||||
}
|
||||
|
||||
let response = await this.getCommand(commandOptions);
|
||||
let responseData = response.result.data;
|
||||
|
||||
this._treeData = responseData;
|
||||
this._updateBindData();
|
||||
this._updateSelected();
|
||||
|
||||
this.onDataChange();
|
||||
} catch (e) {
|
||||
this.errorMessage = e;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 加载 Cloud 数据 (节点)
|
||||
async loadCloudDataNode(callback) {
|
||||
if (this.loading) {
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
let commandOptions = {
|
||||
field: this._cloudDataPostField(),
|
||||
where: this._cloudDataNodeWhere()
|
||||
};
|
||||
|
||||
let response = await this.getCommand(commandOptions);
|
||||
let responseData = response.result.data;
|
||||
|
||||
callback(responseData);
|
||||
} catch (e) {
|
||||
this.errorMessage = e;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 回显 Cloud 数据
|
||||
getCloudDataValue() {
|
||||
if (this.isCloudDataList) {
|
||||
return this.getCloudDataListValue();
|
||||
}
|
||||
|
||||
if (this.isCloudDataTree) {
|
||||
return this.getCloudDataTreeValue();
|
||||
}
|
||||
},
|
||||
|
||||
// 回显 Cloud 数据 (单列)
|
||||
getCloudDataListValue() {
|
||||
// 根据 field's as value标识匹配 where 条件
|
||||
let where = [];
|
||||
let whereField = this._getForeignKeyByField();
|
||||
if (whereField) {
|
||||
where.push(`${whereField} == '${this.dataValue}'`)
|
||||
}
|
||||
|
||||
where = where.join(' || ');
|
||||
|
||||
if (this.where) {
|
||||
where = `(${this.where}) && (${where})`
|
||||
}
|
||||
|
||||
return this.getCommand({
|
||||
field: this._cloudDataPostField(),
|
||||
where
|
||||
}).then((res) => {
|
||||
this.selected = res.result.data;
|
||||
return res.result.data;
|
||||
});
|
||||
},
|
||||
|
||||
// 回显 Cloud 数据 (树形)
|
||||
getCloudDataTreeValue() {
|
||||
return this.getCommand({
|
||||
field: this._cloudDataPostField(),
|
||||
getTreePath: {
|
||||
startWith: `${this.selfField}=='${this.dataValue}'`
|
||||
}
|
||||
}).then((res) => {
|
||||
let treePath = [];
|
||||
this._extractTreePath(res.result.data, treePath);
|
||||
this.selected = treePath;
|
||||
return treePath;
|
||||
});
|
||||
},
|
||||
|
||||
getCommand(options = {}) {
|
||||
/* eslint-disable no-undef */
|
||||
let db = uniCloud.database(this.spaceInfo)
|
||||
@@ -229,125 +393,16 @@ export default {
|
||||
|
||||
return db
|
||||
},
|
||||
getNodeData(callback) {
|
||||
if (this.loading) {
|
||||
return
|
||||
|
||||
_cloudDataPostField() {
|
||||
let fields = [this.field];
|
||||
if (this.parentField) {
|
||||
fields.push(`${this.parentField} as parent_value`);
|
||||
}
|
||||
this.loading = true
|
||||
this.getCommand({
|
||||
field: this.postField,
|
||||
where: this._pathWhere()
|
||||
}).then((res) => {
|
||||
this.loading = false
|
||||
this.selected = res.result.data
|
||||
callback && callback()
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
this.errorMessage = err
|
||||
})
|
||||
return fields.join(',');
|
||||
},
|
||||
getTreePath(callback) {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.getCommand({
|
||||
field: this.postField,
|
||||
getTreePath: {
|
||||
startWith: `${this.selfField}=='${this.dataValue}'`
|
||||
}
|
||||
}).then((res) => {
|
||||
this.loading = false
|
||||
let treePath = []
|
||||
this._extractTreePath(res.result.data, treePath)
|
||||
this.selected = treePath
|
||||
callback && callback()
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
this.errorMessage = err
|
||||
})
|
||||
},
|
||||
loadData() {
|
||||
if (this.isLocaldata) {
|
||||
this._processLocalData()
|
||||
return
|
||||
}
|
||||
|
||||
if (this.dataValue != null) {
|
||||
this._loadNodeData((data) => {
|
||||
this._treeData = data
|
||||
this._updateBindData()
|
||||
this._updateSelected()
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (this.stepSearh) {
|
||||
this._loadNodeData((data) => {
|
||||
this._treeData = data
|
||||
this._updateBindData()
|
||||
})
|
||||
} else {
|
||||
this._loadAllData((data) => {
|
||||
this._treeData = []
|
||||
this._extractTree(data, this._treeData, null)
|
||||
this._updateBindData()
|
||||
})
|
||||
}
|
||||
},
|
||||
_loadAllData(callback) {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.getCommand({
|
||||
field: this.postField,
|
||||
gettree: true,
|
||||
startwith: `${this.selfField}=='${this.dataValue}'`
|
||||
}).then((res) => {
|
||||
this.loading = false
|
||||
callback(res.result.data)
|
||||
this.onDataChange()
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
this.errorMessage = err
|
||||
})
|
||||
},
|
||||
_loadNodeData(callback, pw) {
|
||||
if (this.loading) {
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
|
||||
this.getCommand({
|
||||
field: this.postField,
|
||||
where: pw || this._postWhere(),
|
||||
pageSize: 500
|
||||
}).then((res) => {
|
||||
this.loading = false
|
||||
callback(res.result.data)
|
||||
this.onDataChange()
|
||||
}).catch((err) => {
|
||||
this.loading = false
|
||||
this.errorMessage = err
|
||||
})
|
||||
},
|
||||
_pathWhere() {
|
||||
let result = []
|
||||
let where_field = this._getParentNameByField();
|
||||
if (where_field) {
|
||||
result.push(`${where_field} == '${this.dataValue}'`)
|
||||
}
|
||||
|
||||
if (this.where) {
|
||||
return `(${this.where}) && (${result.join(' || ')})`
|
||||
}
|
||||
|
||||
return result.join(' || ')
|
||||
},
|
||||
_postWhere() {
|
||||
_cloudDataTreeWhere() {
|
||||
let result = []
|
||||
let selected = this.selected
|
||||
let parentField = this.parentField
|
||||
@@ -364,17 +419,35 @@ export default {
|
||||
if (this.where) {
|
||||
where.push(`(${this.where})`)
|
||||
}
|
||||
|
||||
if (result.length) {
|
||||
where.push(`(${result.join(' || ')})`)
|
||||
}
|
||||
|
||||
return where.join(' && ')
|
||||
},
|
||||
_nodeWhere() {
|
||||
let result = []
|
||||
let selected = this.selected
|
||||
|
||||
_cloudDataNodeWhere() {
|
||||
let where = []
|
||||
let selected = this.selected;
|
||||
if (selected.length) {
|
||||
result.push(`${this.parentField} == '${selected[selected.length - 1].value}'`)
|
||||
where.push(`${this.parentField} == '${selected[selected.length - 1].value}'`);
|
||||
}
|
||||
|
||||
where = where.join(' || ');
|
||||
|
||||
if (this.where) {
|
||||
return `(${this.where}) && (${where})`
|
||||
}
|
||||
|
||||
return where
|
||||
},
|
||||
|
||||
_getWhereByForeignKey() {
|
||||
let result = []
|
||||
let whereField = this._getForeignKeyByField();
|
||||
if (whereField) {
|
||||
result.push(`${whereField} == '${this.dataValue}'`)
|
||||
}
|
||||
|
||||
if (this.where) {
|
||||
@@ -383,41 +456,23 @@ export default {
|
||||
|
||||
return result.join(' || ')
|
||||
},
|
||||
_getParentNameByField() {
|
||||
const fields = this.field.split(',');
|
||||
let where_field = null;
|
||||
|
||||
_getForeignKeyByField() {
|
||||
let fields = this.field.split(',');
|
||||
let whereField = null;
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
const items = fields[i].split('as');
|
||||
if (items.length < 2) {
|
||||
continue;
|
||||
}
|
||||
if (items[1].trim() === 'value') {
|
||||
where_field = items[0].trim();
|
||||
whereField = items[0].trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return where_field
|
||||
},
|
||||
_isTreeView() {
|
||||
return (this.parentField && this.selfField)
|
||||
},
|
||||
_updateSelected() {
|
||||
var dl = this.dataList
|
||||
var sl = this.selected
|
||||
let textField = this.map.text
|
||||
let valueField = this.map.value
|
||||
for (var i = 0; i < sl.length; i++) {
|
||||
var value = sl[i].value
|
||||
var dl2 = dl[i]
|
||||
for (var j = 0; j < dl2.length; j++) {
|
||||
var item2 = dl2[j]
|
||||
if (item2[valueField] === value) {
|
||||
sl[i].text = item2[textField]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return whereField;
|
||||
},
|
||||
|
||||
_updateBindData(node) {
|
||||
const {
|
||||
dataList,
|
||||
@@ -445,6 +500,25 @@ export default {
|
||||
hasNodes
|
||||
}
|
||||
},
|
||||
|
||||
_updateSelected() {
|
||||
let dl = this.dataList
|
||||
let sl = this.selected
|
||||
let textField = this.map.text
|
||||
let valueField = this.map.value
|
||||
for (let i = 0; i < sl.length; i++) {
|
||||
let value = sl[i].value
|
||||
let dl2 = dl[i]
|
||||
for (let j = 0; j < dl2.length; j++) {
|
||||
let item2 = dl2[j]
|
||||
if (item2[valueField] === value) {
|
||||
sl[i].text = item2[textField]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_filterData(data, paths) {
|
||||
let dataList = []
|
||||
let hasNodes = true
|
||||
@@ -453,8 +527,8 @@ export default {
|
||||
return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '')
|
||||
}))
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
var value = paths[i].value
|
||||
var nodes = data.filter((item) => {
|
||||
let value = paths[i].value
|
||||
let nodes = data.filter((item) => {
|
||||
return item.parent_value === value
|
||||
})
|
||||
|
||||
@@ -470,6 +544,7 @@ export default {
|
||||
hasNodes
|
||||
}
|
||||
},
|
||||
|
||||
_extractTree(nodes, result, parent_value) {
|
||||
let list = result || []
|
||||
let valueField = this.map.value
|
||||
@@ -493,6 +568,7 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_extractTreePath(nodes, result) {
|
||||
let list = result || []
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
@@ -512,6 +588,7 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_findNodePath(key, nodes, path = []) {
|
||||
let textField = this.map.text
|
||||
let valueField = this.map.value
|
||||
@@ -540,24 +617,6 @@ export default {
|
||||
path.pop()
|
||||
}
|
||||
return []
|
||||
},
|
||||
_processLocalData() {
|
||||
this._treeData = []
|
||||
this._extractTree(this.localdata, this._treeData)
|
||||
|
||||
var inputValue = this.dataValue
|
||||
if (inputValue === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
if (Array.isArray(inputValue)) {
|
||||
inputValue = inputValue[inputValue.length - 1]
|
||||
if (typeof inputValue === 'object' && inputValue[this.map.value]) {
|
||||
inputValue = inputValue[this.map.value]
|
||||
}
|
||||
}
|
||||
|
||||
this.selected = this._findNodePath(inputValue, this.localdata)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,28 @@
|
||||
<template>
|
||||
<view class="uni-data-pickerview">
|
||||
<scroll-view class="selected-area" scroll-x="true" scroll-y="false" :show-scrollbar="false">
|
||||
<scroll-view v-if="!isCloudDataList" class="selected-area" scroll-x="true">
|
||||
<view class="selected-list">
|
||||
<template v-for="(item,index) in selected">
|
||||
<view class="selected-item"
|
||||
:class="{'selected-item-active':index==selectedIndex, 'selected-item-text-overflow': ellipsis}"
|
||||
v-if="item.text" @click="handleSelect(index)">
|
||||
<text class="">{{item.text}}</text>
|
||||
<view
|
||||
class="selected-item"
|
||||
v-for="(item,index) in selected"
|
||||
:key="index"
|
||||
:class="{
|
||||
'selected-item-active':index == selectedIndex
|
||||
}"
|
||||
@click="handleSelect(index)"
|
||||
>
|
||||
<text>{{item.text || ''}}</text>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="tab-c">
|
||||
<template v-for="(child, i) in dataList" >
|
||||
<scroll-view class="list" :key="i" v-if="i==selectedIndex" :scroll-y="true">
|
||||
<view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in child"
|
||||
@click="handleNodeClick(item, i, j)">
|
||||
<text class="item-text item-text-overflow">{{item[map.text]}}</text>
|
||||
<view class="check" v-if="selected.length > i && item[map.value] == selected[i].value"></view>
|
||||
<scroll-view class="list" :scroll-y="true">
|
||||
<view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in dataList[selectedIndex]" :key="j"
|
||||
@click="handleNodeClick(item, selectedIndex, j)">
|
||||
<text class="item-text">{{item[map.text]}}</text>
|
||||
<view class="check" v-if="selected.length > selectedIndex && item[map.value] == selected[selectedIndex].value"></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</template>
|
||||
|
||||
<view class="loading-cover" v-if="loading">
|
||||
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
|
||||
@@ -64,43 +66,33 @@
|
||||
default: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
created() {
|
||||
if (this.managedMode) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.managedMode) {
|
||||
this.$nextTick(() => {
|
||||
this.load()
|
||||
this.loadData();
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onPropsChange() {
|
||||
this._treeData = []
|
||||
this.selectedIndex = 0
|
||||
this.load()
|
||||
},
|
||||
load() {
|
||||
if (this.isLocaldata) {
|
||||
this.loadData()
|
||||
} else if (this.dataValue.length) {
|
||||
this.getTreePath((res) => {
|
||||
this.loadData()
|
||||
this._treeData = [];
|
||||
this.selectedIndex = 0;
|
||||
this.$nextTick(() => {
|
||||
this.loadData();
|
||||
})
|
||||
}
|
||||
},
|
||||
handleSelect(index) {
|
||||
this.selectedIndex = index
|
||||
this.selectedIndex = index;
|
||||
},
|
||||
handleNodeClick(item, i, j) {
|
||||
if (item.disable) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
const node = this.dataList[i][j]
|
||||
const text = node[this.map.text]
|
||||
const value = node[this.map.value]
|
||||
|
||||
const node = this.dataList[i][j];
|
||||
const text = node[this.map.text];
|
||||
const value = node[this.map.value];
|
||||
|
||||
if (i < this.selected.length - 1) {
|
||||
this.selected.splice(i, this.selected.length - i)
|
||||
this.selected.push({
|
||||
@@ -124,18 +116,16 @@
|
||||
hasNodes
|
||||
} = this._updateBindData()
|
||||
|
||||
if (!this._isTreeView() && !hasNodes) {
|
||||
// 本地数据
|
||||
if (this.isLocalData) {
|
||||
this.onSelectedChange(node, (!hasNodes || isleaf))
|
||||
} else if (this.isCloudDataList) { // Cloud 数据 (单列)
|
||||
this.onSelectedChange(node, true)
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isLocaldata && (!hasNodes || isleaf)) {
|
||||
this.onSelectedChange(node, true)
|
||||
return
|
||||
}
|
||||
|
||||
if (!isleaf && !hasNodes) {
|
||||
this._loadNodeData((data) => {
|
||||
} else if (this.isCloudDataTree) { // Cloud 数据 (树形)
|
||||
if (isleaf) {
|
||||
this.onSelectedChange(node, node.isleaf)
|
||||
} else if (!hasNodes) { // 请求一次服务器以确定是否为叶子节点
|
||||
this.loadCloudDataNode((data) => {
|
||||
if (!data.length) {
|
||||
node.isleaf = true
|
||||
} else {
|
||||
@@ -143,11 +133,9 @@
|
||||
this._updateBindData(node)
|
||||
}
|
||||
this.onSelectedChange(node, node.isleaf)
|
||||
}, this._nodeWhere())
|
||||
return
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.onSelectedChange(node, false)
|
||||
},
|
||||
updateData(data) {
|
||||
this._treeData = data.treeData
|
||||
@@ -160,7 +148,7 @@
|
||||
}
|
||||
},
|
||||
onDataChange() {
|
||||
this.$emit('datachange')
|
||||
this.$emit('datachange');
|
||||
},
|
||||
onSelectedChange(node, isleaf) {
|
||||
if (isleaf) {
|
||||
@@ -177,6 +165,7 @@
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$uni-primary: #007aff !default;
|
||||
|
||||
@@ -231,15 +220,14 @@
|
||||
.selected-area {
|
||||
width: 750rpx;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
.selected-list {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
padding: 0 5px;
|
||||
border-bottom: 1px solid #f8f8f8;
|
||||
}
|
||||
@@ -290,7 +278,7 @@
|
||||
|
||||
.item {
|
||||
padding: 12px 15px;
|
||||
/* border-bottom: 1px solid #f5f5f5; */
|
||||
/* border-bottom: 1px solid #f0f0f0; */
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-data-picker",
|
||||
"displayName": "uni-data-picker 数据驱动的picker选择器",
|
||||
"version": "1.0.8",
|
||||
"version": "1.1.2",
|
||||
"description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
## 1.0.6(2023-04-12)
|
||||
- 修复 微信小程序点击时会改变背景颜色的 bug
|
||||
## 1.0.5(2023-02-03)
|
||||
- 修复 禁用时会显示清空按钮
|
||||
## 1.0.4(2023-02-02)
|
||||
- 优化 查询条件短期内多次变更只查询最后一次变更后的结果
|
||||
- 调整 内部缓存键名调整为 uni-data-select-lastSelectedValue
|
||||
## 1.0.3(2023-01-16)
|
||||
- 修复 不关联服务空间报错的问题
|
||||
## 1.0.2(2023-01-14)
|
||||
|
||||
@@ -6,8 +6,12 @@
|
||||
<view class="uni-select__input-box" @click="toggleSelector">
|
||||
<view v-if="current" class="uni-select__input-text">{{current}}</view>
|
||||
<view v-else class="uni-select__input-text uni-select__input-placeholder">{{typePlaceholder}}</view>
|
||||
<uni-icons v-if="current && clear" type="clear" color="#c0c4cc" size="24" @click="clearVal" />
|
||||
<uni-icons v-else :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
|
||||
<view v-if="current && clear && !disabled" @click.stop="clearVal" >
|
||||
<uni-icons type="clear" color="#c0c4cc" size="24"/>
|
||||
</view>
|
||||
<view v-else>
|
||||
<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="uni-select--mask" v-if="showSelector" @click="toggleSelector" />
|
||||
<view class="uni-select__selector" v-if="showSelector">
|
||||
@@ -43,17 +47,8 @@
|
||||
*/
|
||||
|
||||
export default {
|
||||
name: "uni-stat-select",
|
||||
name: "uni-data-select",
|
||||
mixins: [uniCloud.mixinDatacom || {}],
|
||||
data() {
|
||||
return {
|
||||
showSelector: false,
|
||||
current: '',
|
||||
mixinDatacomResData: [],
|
||||
apps: [],
|
||||
channels: []
|
||||
};
|
||||
},
|
||||
props: {
|
||||
localdata: {
|
||||
type: Array,
|
||||
@@ -99,10 +94,22 @@
|
||||
default: ''
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showSelector: false,
|
||||
current: '',
|
||||
mixinDatacomResData: [],
|
||||
apps: [],
|
||||
channels: [],
|
||||
cacheKey: "uni-data-select-lastSelectedValue",
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.last = `${this.collection}_last_selected_option_value`
|
||||
if (this.collection && !this.localdata.length) {
|
||||
this.debounceGet = this.debounce(() => {
|
||||
this.query();
|
||||
}, 300);
|
||||
if (this.collection && !this.localdata.length) {
|
||||
this.debounceGet();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -117,6 +124,14 @@
|
||||
return placeholder ?
|
||||
common + placeholder :
|
||||
common
|
||||
},
|
||||
valueCom(){
|
||||
// #ifdef VUE3
|
||||
return this.modelValue;
|
||||
// #endif
|
||||
// #ifndef VUE3
|
||||
return this.value;
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -128,16 +143,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
// #ifndef VUE3
|
||||
value() {
|
||||
valueCom(val, old) {
|
||||
this.initDefVal()
|
||||
},
|
||||
// #endif
|
||||
// #ifdef VUE3
|
||||
modelValue() {
|
||||
this.initDefVal()
|
||||
},
|
||||
// #endif
|
||||
mixinDatacomResData: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
@@ -148,6 +156,15 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
debounce(fn, time = 100){
|
||||
let timer = null
|
||||
return function(...args) {
|
||||
if (timer) clearTimeout(timer)
|
||||
timer = setTimeout(() => {
|
||||
fn.apply(this, args)
|
||||
}, time)
|
||||
}
|
||||
},
|
||||
// 执行数据库查询
|
||||
query(){
|
||||
this.mixinDatacomEasyGet();
|
||||
@@ -155,19 +172,17 @@
|
||||
// 监听查询条件变更事件
|
||||
onMixinDatacomPropsChange(){
|
||||
if (this.collection) {
|
||||
this.query()
|
||||
this.debounceGet();
|
||||
}
|
||||
},
|
||||
initDefVal() {
|
||||
let defValue = ''
|
||||
if ((this.value || this.value === 0) && !this.isDisabled(this.value)) {
|
||||
defValue = this.value
|
||||
} else if ((this.modelValue || this.modelValue === 0) && !this.isDisabled(this.modelValue)) {
|
||||
defValue = this.modelValue
|
||||
if ((this.valueCom || this.valueCom === 0) && !this.isDisabled(this.valueCom)) {
|
||||
defValue = this.valueCom
|
||||
} else {
|
||||
let strogeValue
|
||||
if (this.collection) {
|
||||
strogeValue = uni.getStorageSync(this.last)
|
||||
strogeValue = this.getCache()
|
||||
}
|
||||
if (strogeValue || strogeValue === 0) {
|
||||
defValue = strogeValue
|
||||
@@ -205,7 +220,7 @@
|
||||
clearVal() {
|
||||
this.emit('')
|
||||
if (this.collection) {
|
||||
uni.removeStorageSync(this.last)
|
||||
this.removeCache()
|
||||
}
|
||||
},
|
||||
change(item) {
|
||||
@@ -216,14 +231,13 @@
|
||||
}
|
||||
},
|
||||
emit(val) {
|
||||
this.$emit('change', val)
|
||||
this.$emit('input', val)
|
||||
this.$emit('update:modelValue', val)
|
||||
this.$emit('change', val)
|
||||
if (this.collection) {
|
||||
uni.setStorageSync(this.last, val)
|
||||
this.setCache(val);
|
||||
}
|
||||
},
|
||||
|
||||
toggleSelector() {
|
||||
if (this.disabled) {
|
||||
return
|
||||
@@ -256,7 +270,32 @@
|
||||
`未命名${channel_code}`
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
// 获取当前加载的数据
|
||||
getLoadData(){
|
||||
return this.mixinDatacomResData;
|
||||
},
|
||||
// 获取当前缓存key
|
||||
getCurrentCacheKey(){
|
||||
return this.collection;
|
||||
},
|
||||
// 获取缓存
|
||||
getCache(name=this.getCurrentCacheKey()){
|
||||
let cacheData = uni.getStorageSync(this.cacheKey) || {};
|
||||
return cacheData[name];
|
||||
},
|
||||
// 设置缓存
|
||||
setCache(value, name=this.getCurrentCacheKey()){
|
||||
let cacheData = uni.getStorageSync(this.cacheKey) || {};
|
||||
cacheData[name] = value;
|
||||
uni.setStorageSync(this.cacheKey, cacheData);
|
||||
},
|
||||
// 删除缓存
|
||||
removeCache(name=this.getCurrentCacheKey()){
|
||||
let cacheData = uni.getStorageSync(this.cacheKey) || {};
|
||||
delete cacheData[name];
|
||||
uni.setStorageSync(this.cacheKey, cacheData);
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -280,7 +319,9 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// padding: 15px;
|
||||
/* #ifdef H5 */
|
||||
cursor: pointer;
|
||||
/* #endif */
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
box-sizing: border-box;
|
||||
@@ -372,7 +413,7 @@
|
||||
background-color: #FFFFFF;
|
||||
border: 1px solid #EBEEF5;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0px 0px 3px 0px rgba(0, 82, 79, 0.65);
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
z-index: 3;
|
||||
padding: 4px 0;
|
||||
}
|
||||
@@ -384,6 +425,14 @@
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
/* #ifdef H5 */
|
||||
@media (min-width: 768px) {
|
||||
.uni-select__selector-scroll {
|
||||
max-height: 600px;
|
||||
}
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
.uni-select__selector-empty,
|
||||
.uni-select__selector-item {
|
||||
/* #ifndef APP-NVUE */
|
||||
@@ -463,5 +512,6 @@
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-data-select",
|
||||
"displayName": "uni-data-select 下拉框选择器",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.6",
|
||||
"description": "通过数据驱动的下拉框选择器",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
## 2.2.23(2023-05-02)
|
||||
- 修复 部分情况修改时间,开始时间未更新 [详情](https://github.com/dcloudio/uni-ui/issues/737)
|
||||
- 修复 部分平台及设备第一次点击无法显示弹框
|
||||
- 修复 ios 日期格式未补零显示及使用异常 [详情](https://ask.dcloud.net.cn/question/162979)
|
||||
## 2.2.22(2023-03-30)
|
||||
- 修复 日历 picker 修改年月后,自动选中当月1日 [详情](https://ask.dcloud.net.cn/question/165937)
|
||||
- 修复 小程序端 低版本 ios NaN [详情](https://ask.dcloud.net.cn/question/162979)
|
||||
## 2.2.21(2023-02-20)
|
||||
- 修复 firefox 浏览器显示区域点击无法拉起日历弹框的Bug [详情](https://ask.dcloud.net.cn/question/163362)
|
||||
## 2.2.20(2023-02-17)
|
||||
- 优化 值为空依然选中当天问题
|
||||
- 优化 提供 default-value 属性支持配置选择器打开时默认显示的时间
|
||||
- 优化 非范围选择未选择日期时间,点击确认按钮选中当前日期时间
|
||||
- 优化 字节小程序日期时间范围选择,底部日期换行问题
|
||||
## 2.2.19(2023-02-09)
|
||||
- 修复 2.2.18 引起范围选择配置 end 选择无效的Bug [详情](https://github.com/dcloudio/uni-ui/issues/686)
|
||||
## 2.2.18(2023-02-08)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<text v-if="selected && weeks.extraInfo" class="uni-calendar-item__weeks-box-circle"></text>
|
||||
<text class="uni-calendar-item__weeks-box-text uni-calendar-item__weeks-box-text-disable uni-calendar-item--checked-text">{{weeks.date}}</text>
|
||||
</view>
|
||||
<view :class="{'uni-calendar-item--isDay': weeks.isDay}"></view>
|
||||
<view :class="{'uni-calendar-item--today': weeks.isToday}"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -41,10 +41,6 @@
|
||||
return []
|
||||
}
|
||||
},
|
||||
lunar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
checkHover: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
@@ -83,11 +79,6 @@
|
||||
color: darken($color: $uni-primary, $amount: 40%);
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-lunar-text {
|
||||
font-size: 12px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.uni-calendar-item__weeks-box-item {
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
@@ -123,7 +114,7 @@
|
||||
color: #D1D1D1;
|
||||
}
|
||||
|
||||
.uni-calendar-item--isDay {
|
||||
.uni-calendar-item--today {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 17%;
|
||||
|
||||
@@ -1,29 +1,37 @@
|
||||
<template>
|
||||
<view class="uni-calendar" @mouseleave="leaveCale">
|
||||
|
||||
<view v-if="!insert && show" class="uni-calendar__mask" :class="{'uni-calendar--mask-show':aniMaskShow}"
|
||||
@click="clean();maskClick()"></view>
|
||||
@click="maskClick"></view>
|
||||
|
||||
<view v-if="insert || show" class="uni-calendar__content"
|
||||
:class="{'uni-calendar--fixed':!insert,'uni-calendar--ani-show':aniMaskShow, 'uni-calendar__content-mobile': aniMaskShow}">
|
||||
<view class="uni-calendar__header" :class="{'uni-calendar__header-mobile' :!insert}">
|
||||
<view v-if="left" class="uni-calendar__header-btn-box" @click.stop="pre">
|
||||
|
||||
<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('pre')">
|
||||
<view class="uni-calendar__header-btn uni-calendar--left"></view>
|
||||
</view>
|
||||
|
||||
<picker mode="date" :value="date" fields="month" @change="bindDateChange">
|
||||
<text
|
||||
class="uni-calendar__header-text">{{ (nowDate.year||'') + yearText + ( nowDate.month||'') + monthText}}</text>
|
||||
</picker>
|
||||
<view v-if="right" class="uni-calendar__header-btn-box" @click.stop="next">
|
||||
|
||||
<view class="uni-calendar__header-btn-box" @click.stop="changeMonth('next')">
|
||||
<view class="uni-calendar__header-btn uni-calendar--right"></view>
|
||||
</view>
|
||||
<view v-if="!insert" class="dialog-close" @click="clean">
|
||||
|
||||
<view v-if="!insert" class="dialog-close" @click="close">
|
||||
<view class="dialog-close-plus" data-id="close"></view>
|
||||
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="uni-calendar__box">
|
||||
|
||||
<view v-if="showMonth" class="uni-calendar__box-bg">
|
||||
<text class="uni-calendar__box-bg-text">{{nowDate.month}}</text>
|
||||
</view>
|
||||
|
||||
<view class="uni-calendar__weeks" style="padding-bottom: 7px;">
|
||||
<view class="uni-calendar__weeks-day">
|
||||
<text class="uni-calendar__weeks-day-text">{{SUNText}}</text>
|
||||
@@ -47,28 +55,30 @@
|
||||
<text class="uni-calendar__weeks-day-text">{{SATText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="uni-calendar__weeks" v-for="(item,weekIndex) in weeks" :key="weekIndex">
|
||||
<view class="uni-calendar__weeks-item" v-for="(weeks,weeksIndex) in item" :key="weeksIndex">
|
||||
<calendar-item class="uni-calendar-item--hook" :weeks="weeks" :calendar="calendar"
|
||||
:selected="selected" :lunar="lunar" :checkHover="range" @change="choiceDate"
|
||||
:selected="selected" :checkHover="range" @change="choiceDate"
|
||||
@handleMouse="handleMouse">
|
||||
</calendar-item>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-if="!insert && !range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top"
|
||||
|
||||
<view v-if="!insert && !range && hasTime" class="uni-date-changed uni-calendar--fixed-top"
|
||||
style="padding: 0 80px;">
|
||||
<view class="uni-date-changed--time-date">{{tempSingleDate ? tempSingleDate : selectDateText}}</view>
|
||||
<time-picker type="time" :start="reactStartTime" :end="reactEndTime" v-model="time"
|
||||
<time-picker type="time" :start="timepickerStartTime" :end="timepickerEndTime" v-model="time"
|
||||
:disabled="!tempSingleDate" :border="false" :hide-second="hideSecond" class="time-picker-style">
|
||||
</time-picker>
|
||||
</view>
|
||||
|
||||
<view v-if="!insert && range && typeHasTime" class="uni-date-changed uni-calendar--fixed-top">
|
||||
<view v-if="!insert && range && hasTime" class="uni-date-changed uni-calendar--fixed-top">
|
||||
<view class="uni-date-changed--time-start">
|
||||
<view class="uni-date-changed--time-date">{{tempRange.before ? tempRange.before : startDateText}}
|
||||
</view>
|
||||
<time-picker type="time" :start="reactStartTime" v-model="timeRange.startTime" :border="false"
|
||||
<time-picker type="time" :start="timepickerStartTime" v-model="timeRange.startTime" :border="false"
|
||||
:hide-second="hideSecond" :disabled="!tempRange.before" class="time-picker-style">
|
||||
</time-picker>
|
||||
</view>
|
||||
@@ -77,11 +87,12 @@
|
||||
</view>
|
||||
<view class="uni-date-changed--time-end">
|
||||
<view class="uni-date-changed--time-date">{{tempRange.after ? tempRange.after : endDateText}}</view>
|
||||
<time-picker type="time" :end="reactEndTime" v-model="timeRange.endTime" :border="false"
|
||||
<time-picker type="time" :end="timepickerEndTime" v-model="timeRange.endTime" :border="false"
|
||||
:hide-second="hideSecond" :disabled="!tempRange.after" class="time-picker-style">
|
||||
</time-picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="!insert" class="uni-date-changed uni-date-btn--ok">
|
||||
<view class="uni-datetime-picker--btn" @click="confirm">{{confirmText}}</view>
|
||||
</view>
|
||||
@@ -90,7 +101,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Calendar from './util.js';
|
||||
import { Calendar, getDate, getTime } from './util.js';
|
||||
import calendarItem from './calendar-item.vue'
|
||||
import timePicker from './time-picker.vue'
|
||||
|
||||
@@ -103,7 +114,6 @@
|
||||
* @description 日历组件可以查看日期,选择任意范围内的日期,打点操作。常用场景如:酒店日期预订、火车机票选择购买日期、上下班打卡等
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=56
|
||||
* @property {String} date 自定义当前时间,默认为今天
|
||||
* @property {Boolean} lunar 显示农历
|
||||
* @property {String} startDate 日期选择范围-开始日期
|
||||
* @property {String} endDate 日期选择范围-结束日期
|
||||
* @property {Boolean} range 范围选择
|
||||
@@ -113,10 +123,11 @@
|
||||
* @property {Boolean} clearDate = [true|false] 弹窗模式是否清空上次选择内容
|
||||
* @property {Array} selected 打点,期待格式[{date: '2019-06-27', info: '签到', data: { custom: '自定义信息', name: '自定义消息头',xxx:xxx... }}]
|
||||
* @property {Boolean} showMonth 是否选择月份为背景
|
||||
* @property {[String} defaultValue 选择器打开时默认显示的时间
|
||||
* @event {Function} change 日期改变,`insert :ture` 时生效
|
||||
* @event {Function} confirm 确认选择`insert :false` 时生效
|
||||
* @event {Function} monthSwitch 切换月份时触发
|
||||
* @example <uni-calendar :insert="true":lunar="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
|
||||
* @example <uni-calendar :insert="true" :start-date="'2019-3-2'":end-date="'2019-5-20'"@change="change" />
|
||||
*/
|
||||
export default {
|
||||
components: {
|
||||
@@ -144,10 +155,6 @@
|
||||
return []
|
||||
}
|
||||
},
|
||||
lunar: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
startDate: {
|
||||
type: String,
|
||||
default: ''
|
||||
@@ -168,7 +175,7 @@
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
typeHasTime: {
|
||||
hasTime: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
@@ -184,14 +191,6 @@
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
left: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
right: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
checkHover: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
@@ -210,6 +209,10 @@
|
||||
fulldate: ''
|
||||
}
|
||||
}
|
||||
},
|
||||
defaultValue: {
|
||||
type: [String, Object, Array],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -217,7 +220,7 @@
|
||||
show: false,
|
||||
weeks: [],
|
||||
calendar: {},
|
||||
nowDate: '',
|
||||
nowDate: {},
|
||||
aniMaskShow: false,
|
||||
firstEnter: true,
|
||||
time: '',
|
||||
@@ -229,7 +232,8 @@
|
||||
tempRange: {
|
||||
before: '',
|
||||
after: ''
|
||||
}
|
||||
},
|
||||
isPhone: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -260,7 +264,7 @@
|
||||
if(!this.cale){
|
||||
return
|
||||
}
|
||||
this.cale.resetSatrtDate(val)
|
||||
this.cale.setStartDate(val)
|
||||
this.cale.setDate(this.nowDate.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
@@ -269,7 +273,7 @@
|
||||
if(!this.cale){
|
||||
return
|
||||
}
|
||||
this.cale.resetEndDate(val)
|
||||
this.cale.setEndDate(val)
|
||||
this.cale.setDate(this.nowDate.fullDate)
|
||||
this.weeks = this.cale.weeks
|
||||
},
|
||||
@@ -312,10 +316,10 @@
|
||||
}
|
||||
|
||||
this.cale.setDefaultMultiple(before, after)
|
||||
if (which === 'left') {
|
||||
if (which === 'left' && before) {
|
||||
this.setDate(before)
|
||||
this.weeks = this.cale.weeks
|
||||
} else {
|
||||
} else if(after) {
|
||||
this.setDate(after)
|
||||
this.weeks = this.cale.weeks
|
||||
}
|
||||
@@ -326,15 +330,13 @@
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
reactStartTime() {
|
||||
timepickerStartTime() {
|
||||
const activeDate = this.range ? this.tempRange.before : this.calendar.fullDate
|
||||
const res = activeDate === this.startDate ? this.selectableTimes.start : ''
|
||||
return res
|
||||
return activeDate === this.startDate ? this.selectableTimes.start : ''
|
||||
},
|
||||
reactEndTime() {
|
||||
timepickerEndTime() {
|
||||
const activeDate = this.range ? this.tempRange.after : this.calendar.fullDate
|
||||
const res = activeDate === this.endDate ? this.selectableTimes.end : ''
|
||||
return res
|
||||
return activeDate === this.endDate ? this.selectableTimes.end : ''
|
||||
},
|
||||
/**
|
||||
* for i18n
|
||||
@@ -393,6 +395,14 @@
|
||||
// 选中某一天
|
||||
this.init(this.date)
|
||||
},
|
||||
mounted(){
|
||||
if(typeof navigator !== "undefined"){
|
||||
this.isPhone = navigator.userAgent.toLowerCase().indexOf('mobile') !== -1
|
||||
return
|
||||
}
|
||||
const { windowWidth } = uni.getSystemInfoSync()
|
||||
this.isPhone = windowWidth <= 500
|
||||
},
|
||||
methods: {
|
||||
leaveCale() {
|
||||
this.firstEnter = true
|
||||
@@ -420,14 +430,9 @@
|
||||
const [yearB, monthB] = B.split('-')
|
||||
return yearA === yearB && monthA === monthB
|
||||
},
|
||||
|
||||
// 取消穿透
|
||||
clean() {
|
||||
this.close()
|
||||
},
|
||||
|
||||
// 蒙版点击事件
|
||||
maskClick() {
|
||||
this.close()
|
||||
this.$emit('maskClose')
|
||||
},
|
||||
|
||||
@@ -446,21 +451,48 @@
|
||||
this.tempSingleDate = ''
|
||||
}
|
||||
this.calendar.fullDate = ''
|
||||
this.setDate()
|
||||
this.setDate(new Date())
|
||||
},
|
||||
|
||||
bindDateChange(e) {
|
||||
const value = e.detail.value + '-1'
|
||||
this.init(value)
|
||||
this.setDate(value)
|
||||
},
|
||||
/**
|
||||
* 初始化日期显示
|
||||
* @param {Object} date
|
||||
*/
|
||||
init(date) {
|
||||
this.cale.setDate(date)
|
||||
// 字节小程序 watch 早于 created
|
||||
if(!this.cale){
|
||||
return
|
||||
}
|
||||
this.cale.setDate(date || new Date())
|
||||
this.weeks = this.cale.weeks
|
||||
this.nowDate = this.calendar = this.cale.getInfo(date)
|
||||
this.nowDate = this.cale.getInfo(date)
|
||||
this.calendar = {...this.nowDate}
|
||||
if(!date){
|
||||
// 优化date为空默认不选中今天
|
||||
this.calendar.fullDate = ''
|
||||
if(this.defaultValue && !this.range){
|
||||
// 暂时只支持移动端非范围选择
|
||||
const defaultDate = new Date(this.defaultValue)
|
||||
const fullDate = getDate(defaultDate)
|
||||
const year = defaultDate.getFullYear()
|
||||
const month = defaultDate.getMonth()+1
|
||||
const date = defaultDate.getDate()
|
||||
const day = defaultDate.getDay()
|
||||
this.calendar = {
|
||||
fullDate,
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
day
|
||||
},
|
||||
this.tempSingleDate = fullDate
|
||||
this.time = getTime(defaultDate, this.hideSecond)
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 打开日历弹窗
|
||||
@@ -469,7 +501,6 @@
|
||||
// 弹窗模式并且清理数据
|
||||
if (this.clearDate && !this.insert) {
|
||||
this.cale.cleanMultipleStatus()
|
||||
// this.cale.setDate(this.date)
|
||||
this.init(this.date)
|
||||
}
|
||||
this.show = true
|
||||
@@ -523,12 +554,20 @@
|
||||
* @param {Object} name
|
||||
*/
|
||||
setEmit(name) {
|
||||
if(!this.range){
|
||||
if(!this.calendar.fullDate){
|
||||
this.calendar = this.cale.getInfo(new Date())
|
||||
this.tempSingleDate = this.calendar.fullDate
|
||||
}
|
||||
if(this.hasTime && !this.time) {
|
||||
this.time = getTime(new Date(), this.hideSecond)
|
||||
}
|
||||
}
|
||||
let {
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
fullDate,
|
||||
lunar,
|
||||
extraInfo
|
||||
} = this.calendar
|
||||
this.$emit(name, {
|
||||
@@ -539,7 +578,6 @@
|
||||
time: this.time,
|
||||
timeRange: this.timeRange,
|
||||
fulldate: fullDate,
|
||||
lunar,
|
||||
extraInfo: extraInfo || {}
|
||||
})
|
||||
},
|
||||
@@ -557,7 +595,8 @@
|
||||
this.tempSingleDate = this.calendar.fullDate
|
||||
const beforeDate = new Date(this.cale.multipleStatus.before).getTime()
|
||||
const afterDate = new Date(this.cale.multipleStatus.after).getTime()
|
||||
if (beforeDate > afterDate && afterDate) {
|
||||
// 这里返回的 before after 为什么要做替换?导致PC端如果开始结束日期都是今天,第一次选择开始日期早于今天,开始日期不更新
|
||||
if (beforeDate > afterDate && afterDate && !this.isPhone) {
|
||||
this.tempRange.before = this.cale.multipleStatus.after
|
||||
this.tempRange.after = this.cale.multipleStatus.before
|
||||
} else {
|
||||
@@ -566,44 +605,15 @@
|
||||
}
|
||||
this.change()
|
||||
},
|
||||
/**
|
||||
* 回到今天
|
||||
*/
|
||||
backtoday() {
|
||||
let date = this.cale.getDate(new Date()).fullDate
|
||||
// this.cale.setDate(date)
|
||||
this.init(date)
|
||||
this.change()
|
||||
},
|
||||
/**
|
||||
* 比较时间大小
|
||||
*/
|
||||
dateCompare(startDate, endDate) {
|
||||
// 计算截止时间
|
||||
startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
|
||||
if (startDate <= endDate) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
changeMonth(type) {
|
||||
let newDate
|
||||
if(type === 'pre') {
|
||||
newDate = this.cale.getPreMonthObj(this.nowDate.fullDate).fullDate
|
||||
} else if(type === 'next') {
|
||||
newDate = this.cale.getNextMonthObj(this.nowDate.fullDate).fullDate
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 上个月
|
||||
*/
|
||||
pre() {
|
||||
const preDate = this.cale.getDate(this.nowDate.fullDate, -1, 'month').fullDate
|
||||
this.setDate(preDate)
|
||||
this.monthSwitch()
|
||||
|
||||
},
|
||||
/**
|
||||
* 下个月
|
||||
*/
|
||||
next() {
|
||||
const nextDate = this.cale.getDate(this.nowDate.fullDate, +1, 'month').fullDate
|
||||
this.setDate(nextDate)
|
||||
this.setDate(newDate)
|
||||
this.monthSwitch()
|
||||
},
|
||||
/**
|
||||
@@ -863,6 +873,9 @@
|
||||
.uni-date-changed--time-date {
|
||||
color: #999;
|
||||
line-height: 50px;
|
||||
/* #ifdef MP-TOUTIAO */
|
||||
font-size: 16px;
|
||||
/* #endif */
|
||||
margin-right: 5px;
|
||||
// opacity: 0.6;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"uni-datetime-picker.selectDate": "select date",
|
||||
"uni-datetime-picker.selectTime": "select time",
|
||||
"uni-datetime-picker.selectDateTime": "select datetime",
|
||||
"uni-datetime-picker.selectDateTime": "select date and time",
|
||||
"uni-datetime-picker.startDate": "start date",
|
||||
"uni-datetime-picker.endDate": "end date",
|
||||
"uni-datetime-picker.startTime": "start time",
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
import { initVueI18n } from '@dcloudio/uni-i18n'
|
||||
import i18nMessages from './i18n/index.js'
|
||||
const { t } = initVueI18n(i18nMessages)
|
||||
import { fixIosDateFormat } from './util'
|
||||
|
||||
/**
|
||||
* DatetimePicker 时间选择器
|
||||
@@ -176,7 +177,7 @@
|
||||
value: {
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
this.parseValue(this.fixIosDateFormat(newVal)) //兼容 iOS、safari 日期格式
|
||||
this.parseValue(fixIosDateFormat(newVal))
|
||||
this.initTime(false)
|
||||
} else {
|
||||
this.time = ''
|
||||
@@ -190,7 +191,7 @@
|
||||
modelValue: {
|
||||
handler(newVal) {
|
||||
if (newVal) {
|
||||
this.parseValue(this.fixIosDateFormat(newVal)) //兼容 iOS、safari 日期格式
|
||||
this.parseValue(fixIosDateFormat(newVal))
|
||||
this.initTime(false)
|
||||
} else {
|
||||
this.time = ''
|
||||
@@ -220,13 +221,13 @@
|
||||
},
|
||||
start: {
|
||||
handler(newVal) {
|
||||
this.parseDatetimeRange(this.fixIosDateFormat(newVal), 'start') //兼容 iOS、safari 日期格式
|
||||
this.parseDatetimeRange(fixIosDateFormat(newVal), 'start')
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
end: {
|
||||
handler(newVal) {
|
||||
this.parseDatetimeRange(this.fixIosDateFormat(newVal), 'end') //兼容 iOS、safari 日期格式
|
||||
this.parseDatetimeRange(fixIosDateFormat(newVal), 'end')
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
@@ -739,7 +740,7 @@
|
||||
*/
|
||||
initTimePicker() {
|
||||
if (this.disabled) return
|
||||
const value = this.fixIosDateFormat(this.time)
|
||||
const value = fixIosDateFormat(this.time)
|
||||
this.initPickerValue(value)
|
||||
this.visible = !this.visible
|
||||
},
|
||||
|
||||
@@ -8,19 +8,16 @@
|
||||
>
|
||||
<view v-if="!isRange" class="uni-date-x uni-date-single">
|
||||
<uni-icons class="icon-calendar" type="calendar" color="#c0c4cc" size="22"></uni-icons>
|
||||
<input class="uni-date__x-input" type="text" v-model="displayValue"
|
||||
:placeholder="singlePlaceholderText" :disabled="true" />
|
||||
<view class="uni-date__x-input">{{ displayValue || singlePlaceholderText }}</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="uni-date-x uni-date-range">
|
||||
<uni-icons class="icon-calendar" type="calendar" color="#c0c4cc" size="22"></uni-icons>
|
||||
<input class="uni-date__x-input t-c" type="text" v-model="range.startDate"
|
||||
:placeholder="startPlaceholderText" :disabled="true" />
|
||||
<view class="uni-date__x-input text-center">{{ displayRangeValue.startDate || startPlaceholderText }}</view>
|
||||
|
||||
<view class="range-separator">{{rangeSeparator}}</view>
|
||||
|
||||
<input class="uni-date__x-input t-c" type="text" v-model="range.endDate"
|
||||
:placeholder="endPlaceholderText" :disabled="true" />
|
||||
<view class="uni-date__x-input text-center">{{ displayRangeValue.endDate || endPlaceholderText }}</view>
|
||||
</view>
|
||||
|
||||
<view v-if="showClearIcon" class="uni-date__icon-clear" @click.stop="clear">
|
||||
@@ -33,37 +30,38 @@
|
||||
<view v-show="pickerVisible" class="uni-date-mask--pc" @click="close"></view>
|
||||
|
||||
<view v-if="!isPhone" v-show="pickerVisible" ref="datePicker" class="uni-date-picker__container">
|
||||
<view v-if="!isRange" class="uni-date-single--x" :style="popover">
|
||||
<view v-if="!isRange" class="uni-date-single--x" :style="pickerPositionStyle">
|
||||
<view class="uni-popper__arrow"></view>
|
||||
|
||||
<view v-if="hasTime" class="uni-date-changed popup-x-header">
|
||||
<input class="uni-date__input t-c" type="text" v-model="inputDate"
|
||||
<input class="uni-date__input text-center" type="text" v-model="inputDate"
|
||||
:placeholder="selectDateText" />
|
||||
|
||||
<time-picker type="time" v-model="pickerTime" :border="false" :disabled="!inputDate"
|
||||
:start="reactStartTime" :end="reactEndTime" :hideSecond="hideSecond" style="width: 100%;">
|
||||
<input class="uni-date__input t-c" type="text" v-model="pickerTime" :placeholder="selectTimeText"
|
||||
:start="timepickerStartTime" :end="timepickerEndTime" :hideSecond="hideSecond" style="width: 100%;">
|
||||
<input class="uni-date__input text-center" type="text" v-model="pickerTime" :placeholder="selectTimeText"
|
||||
:disabled="!inputDate" />
|
||||
</time-picker>
|
||||
</view>
|
||||
|
||||
<calendar ref="pcSingle" :showMonth="false" :start-date="caleRange.startDate"
|
||||
:end-date="caleRange.endDate" :date="calendarDate" @change="singleChange"
|
||||
<Calendar ref="pcSingle" :showMonth="false" :start-date="calendarRange.startDate"
|
||||
:end-date="calendarRange.endDate" :date="calendarDate" @change="singleChange"
|
||||
:default-value="defaultValue"
|
||||
style="padding: 0 8px;" />
|
||||
|
||||
<view v-if="hasTime" class="popup-x-footer">
|
||||
<text class="confirm" @click="confirmSingleChange">{{okText}}</text>
|
||||
<text class="confirm-text" @click="confirmSingleChange">{{okText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="uni-date-range--x" :style="popover">
|
||||
<view v-else class="uni-date-range--x" :style="pickerPositionStyle">
|
||||
<view class="uni-popper__arrow"></view>
|
||||
<view v-if="hasTime" class="popup-x-header uni-date-changed">
|
||||
<view class="popup-x-header--datetime">
|
||||
<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.startDate"
|
||||
:placeholder="startDateText" />
|
||||
|
||||
<time-picker type="time" v-model="tempRange.startTime" :start="reactStartTime" :border="false"
|
||||
<time-picker type="time" v-model="tempRange.startTime" :start="timepickerStartTime" :border="false"
|
||||
:disabled="!tempRange.startDate" :hideSecond="hideSecond">
|
||||
<input class="uni-date__input uni-date-range__input" type="text"
|
||||
v-model="tempRange.startTime" :placeholder="startTimeText"
|
||||
@@ -77,7 +75,7 @@
|
||||
<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endDate"
|
||||
:placeholder="endDateText" />
|
||||
|
||||
<time-picker type="time" v-model="tempRange.endTime" :end="reactEndTime" :border="false"
|
||||
<time-picker type="time" v-model="tempRange.endTime" :end="timepickerEndTime" :border="false"
|
||||
:disabled="!tempRange.endDate" :hideSecond="hideSecond">
|
||||
<input class="uni-date__input uni-date-range__input" type="text" v-model="tempRange.endTime"
|
||||
:placeholder="endTimeText" :disabled="!tempRange.endDate" />
|
||||
@@ -86,26 +84,27 @@
|
||||
</view>
|
||||
|
||||
<view class="popup-x-body">
|
||||
<calendar ref="left" :showMonth="false" :start-date="caleRange.startDate"
|
||||
:end-date="caleRange.endDate" :range="true" @change="leftChange" :pleStatus="endMultipleStatus"
|
||||
@firstEnterCale="updateRightCale" style="padding: 0 8px;" />
|
||||
<calendar ref="right" :showMonth="false" :start-date="caleRange.startDate"
|
||||
:end-date="caleRange.endDate" :range="true" @change="rightChange"
|
||||
<Calendar ref="left" :showMonth="false" :start-date="calendarRange.startDate"
|
||||
:end-date="calendarRange.endDate" :range="true" :pleStatus="endMultipleStatus"
|
||||
@change="leftChange" @firstEnterCale="updateRightCale" style="padding: 0 8px;" />
|
||||
<Calendar ref="right" :showMonth="false" :start-date="calendarRange.startDate"
|
||||
:end-date="calendarRange.endDate" :range="true" @change="rightChange"
|
||||
:pleStatus="startMultipleStatus" @firstEnterCale="updateLeftCale"
|
||||
style="padding: 0 8px;border-left: 1px solid #F1F1F1;" />
|
||||
</view>
|
||||
|
||||
<view v-if="hasTime" class="popup-x-footer">
|
||||
<text class="" @click="clear">{{clearText}}</text>
|
||||
<text class="confirm" @click="confirmRangeChange">{{okText}}</text>
|
||||
<text @click="clear">{{clearText}}</text>
|
||||
<text class="confirm-text" @click="confirmRangeChange">{{okText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<calendar v-if="isPhone" ref="mobile" :clearDate="false" :date="calendarDate" :defTime="reactMobDefTime"
|
||||
:start-date="caleRange.startDate" :end-date="caleRange.endDate" :selectableTimes="mobSelectableTime"
|
||||
<Calendar v-if="isPhone" ref="mobile" :clearDate="false" :date="calendarDate" :defTime="mobileCalendarTime"
|
||||
:start-date="calendarRange.startDate" :end-date="calendarRange.endDate" :selectableTimes="mobSelectableTime"
|
||||
:startPlaceholder="startPlaceholder" :endPlaceholder="endPlaceholder"
|
||||
:pleStatus="endMultipleStatus" :showMonth="false" :range="isRange" :typeHasTime="hasTime" :insert="false"
|
||||
:default-value="defaultValue"
|
||||
:pleStatus="endMultipleStatus" :showMonth="false" :range="isRange" :hasTime="hasTime" :insert="false"
|
||||
:hideSecond="hideSecond" @confirm="mobileChange" @maskClose="close" />
|
||||
</view>
|
||||
</template>
|
||||
@@ -125,16 +124,18 @@
|
||||
* @property {Boolean} border = [true|false] 是否有边框
|
||||
* @property {Boolean} disabled = [true|false] 是否禁用
|
||||
* @property {Boolean} clearIcon = [true|false] 是否显示清除按钮(仅PC端适用)
|
||||
* @property {[String} defaultValue 选择器打开时默认显示的时间
|
||||
* @event {Function} change 确定日期时触发的事件
|
||||
* @event {Function} maskClick 点击遮罩层触发的事件
|
||||
* @event {Function} show 打开弹出层
|
||||
* @event {Function} close 关闭弹出层
|
||||
* @event {Function} clear 清除上次选中的状态和值
|
||||
**/
|
||||
import calendar from './calendar.vue'
|
||||
import timePicker from './time-picker.vue'
|
||||
import Calendar from './calendar.vue'
|
||||
import TimePicker from './time-picker.vue'
|
||||
import { initVueI18n } from '@dcloudio/uni-i18n'
|
||||
import i18nMessages from './i18n/index.js'
|
||||
import { getDateTime, getDate, getTime, getDefaultSecond, dateCompare, checkDate, fixIosDateFormat } from './util'
|
||||
|
||||
export default {
|
||||
name: 'UniDatetimePicker',
|
||||
@@ -142,8 +143,8 @@
|
||||
virtualHost: true
|
||||
},
|
||||
components: {
|
||||
calendar,
|
||||
timePicker
|
||||
Calendar,
|
||||
TimePicker
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -153,14 +154,13 @@
|
||||
inputDate: '',
|
||||
calendarDate: '',
|
||||
pickerTime: '',
|
||||
// 范围选
|
||||
caleRange: {
|
||||
calendarRange: {
|
||||
startDate: '',
|
||||
startTime: '',
|
||||
endDate: '',
|
||||
endTime: ''
|
||||
},
|
||||
range: {
|
||||
displayRangeValue: {
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
},
|
||||
@@ -184,7 +184,7 @@
|
||||
fulldate: ''
|
||||
},
|
||||
pickerVisible: false,
|
||||
popover: null,
|
||||
pickerPositionStyle: null,
|
||||
isEmitValue: false,
|
||||
isPhone: false,
|
||||
isFirstShow: true,
|
||||
@@ -247,6 +247,10 @@
|
||||
hideSecond: {
|
||||
type: [Boolean],
|
||||
default: false
|
||||
},
|
||||
defaultValue: {
|
||||
type: [String, Object, Array],
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -285,13 +289,9 @@
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
if (!newVal) return
|
||||
const {
|
||||
defDate,
|
||||
defTime
|
||||
} = this.parseDate(newVal)
|
||||
this.caleRange.startDate = defDate
|
||||
this.calendarRange.startDate = getDate(newVal)
|
||||
if (this.hasTime) {
|
||||
this.caleRange.startTime = defTime
|
||||
this.calendarRange.startTime = getTime(newVal)
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -299,39 +299,33 @@
|
||||
immediate: true,
|
||||
handler(newVal) {
|
||||
if (!newVal) return
|
||||
const {
|
||||
defDate,
|
||||
defTime
|
||||
} = this.parseDate(newVal)
|
||||
this.caleRange.endDate = defDate
|
||||
this.calendarRange.endDate = getDate(newVal)
|
||||
if (this.hasTime) {
|
||||
this.caleRange.endTime = defTime
|
||||
this.calendarRange.endTime = getTime(newVal, this.hideSecond)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
reactStartTime() {
|
||||
timepickerStartTime() {
|
||||
const activeDate = this.isRange ? this.tempRange.startDate : this.inputDate
|
||||
const res = activeDate === this.caleRange.startDate ? this.caleRange.startTime : ''
|
||||
return res
|
||||
return activeDate === this.calendarRange.startDate ? this.calendarRange.startTime : ''
|
||||
},
|
||||
reactEndTime() {
|
||||
timepickerEndTime() {
|
||||
const activeDate = this.isRange ? this.tempRange.endDate : this.inputDate
|
||||
const res = activeDate === this.caleRange.endDate ? this.caleRange.endTime : ''
|
||||
return res
|
||||
return activeDate === this.calendarRange.endDate ? this.calendarRange.endTime : ''
|
||||
},
|
||||
reactMobDefTime() {
|
||||
const times = {
|
||||
mobileCalendarTime() {
|
||||
const timeRange = {
|
||||
start: this.tempRange.startTime,
|
||||
end: this.tempRange.endTime
|
||||
}
|
||||
return this.isRange ? times : this.pickerTime
|
||||
return this.isRange ? timeRange : this.pickerTime
|
||||
},
|
||||
mobSelectableTime() {
|
||||
return {
|
||||
start: this.caleRange.startTime,
|
||||
end: this.caleRange.endTime
|
||||
start: this.calendarRange.startTime,
|
||||
end: this.calendarRange.endTime
|
||||
}
|
||||
},
|
||||
datePopupWidth() {
|
||||
@@ -379,7 +373,7 @@
|
||||
return this.i18nT("uni-datetime-picker.clear")
|
||||
},
|
||||
showClearIcon() {
|
||||
return this.clearIcon && !this.disabled && (this.displayValue || (this.range.startDate && this.range.endDate))
|
||||
return this.clearIcon && !this.disabled && (this.displayValue || (this.displayRangeValue.startDate && this.displayRangeValue.endDate))
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@@ -392,7 +386,7 @@
|
||||
this.i18nT = vueI18n.t
|
||||
},
|
||||
initPicker(newVal) {
|
||||
if (!newVal || Array.isArray(newVal) && !newVal.length) {
|
||||
if ((!newVal && !this.defaultValue) || Array.isArray(newVal) && !newVal.length) {
|
||||
this.$nextTick(() => {
|
||||
this.clear(false)
|
||||
})
|
||||
@@ -400,36 +394,40 @@
|
||||
}
|
||||
|
||||
if (!Array.isArray(newVal) && !this.isRange) {
|
||||
const {
|
||||
defDate,
|
||||
defTime
|
||||
} = this.parseDate(newVal)
|
||||
this.displayValue = defDate
|
||||
this.inputDate = defDate
|
||||
this.calendarDate = defDate
|
||||
if(newVal){
|
||||
this.displayValue = this.inputDate = this.calendarDate = getDate(newVal)
|
||||
if (this.hasTime) {
|
||||
this.displayValue = defDate + ' ' + defTime
|
||||
this.pickerTime = defTime
|
||||
this.pickerTime = getTime(newVal, this.hideSecond)
|
||||
this.displayValue = `${this.displayValue} ${this.pickerTime}`
|
||||
}
|
||||
}else if(this.defaultValue){
|
||||
this.inputDate = this.calendarDate = getDate(this.defaultValue)
|
||||
if(this.hasTime){
|
||||
this.pickerTime = getTime(this.defaultValue, this.hideSecond)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const [before, after] = newVal
|
||||
if (!before && !after) return
|
||||
const defBefore = this.parseDate(before)
|
||||
const defAfter = this.parseDate(after)
|
||||
const startDate = defBefore.defDate
|
||||
const endDate = defAfter.defDate
|
||||
this.range.startDate = this.tempRange.startDate = startDate
|
||||
this.range.endDate = this.tempRange.endDate = endDate
|
||||
const beforeDate = getDate(before)
|
||||
const beforeTime = getTime(before, this.hideSecond)
|
||||
|
||||
const afterDate = getDate(after)
|
||||
const afterTime = getTime(after, this.hideSecond)
|
||||
const startDate = beforeDate
|
||||
const endDate = afterDate
|
||||
this.displayRangeValue.startDate = this.tempRange.startDate = startDate
|
||||
this.displayRangeValue.endDate = this.tempRange.endDate = endDate
|
||||
|
||||
if (this.hasTime) {
|
||||
this.range.startDate = defBefore.defDate + ' ' + defBefore.defTime
|
||||
this.range.endDate = defAfter.defDate + ' ' + defAfter.defTime
|
||||
this.tempRange.startTime = defBefore.defTime
|
||||
this.tempRange.endTime = defAfter.defTime
|
||||
this.displayRangeValue.startDate = `${beforeDate} ${beforeTime}`
|
||||
this.displayRangeValue.endDate = `${afterDate} ${afterTime}`
|
||||
this.tempRange.startTime = beforeTime
|
||||
this.tempRange.endTime = afterTime
|
||||
}
|
||||
const defaultRange = {
|
||||
before: defBefore.defDate,
|
||||
after: defAfter.defDate
|
||||
before: beforeDate,
|
||||
after: afterDate
|
||||
}
|
||||
this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, defaultRange, {
|
||||
which: 'right'
|
||||
@@ -452,6 +450,10 @@
|
||||
right.setDate(this.$refs.right.nowDate.fullDate)
|
||||
},
|
||||
platform() {
|
||||
if(typeof navigator !== "undefined"){
|
||||
this.isPhone = navigator.userAgent.toLowerCase().indexOf('mobile') !== -1
|
||||
return
|
||||
}
|
||||
const { windowWidth } = uni.getSystemInfoSync()
|
||||
this.isPhone = windowWidth <= 500
|
||||
this.windowWidth = windowWidth
|
||||
@@ -462,16 +464,18 @@
|
||||
}
|
||||
this.platform()
|
||||
if (this.isPhone) {
|
||||
setTimeout(() => {
|
||||
this.$refs.mobile.open()
|
||||
}, 0);
|
||||
return
|
||||
}
|
||||
this.popover = {
|
||||
this.pickerPositionStyle = {
|
||||
top: '10px'
|
||||
}
|
||||
const dateEditor = uni.createSelectorQuery().in(this).select(".uni-date-editor")
|
||||
dateEditor.boundingClientRect(rect => {
|
||||
if (this.windowWidth - rect.left < this.datePopupWidth) {
|
||||
this.popover.right = 0
|
||||
this.pickerPositionStyle.right = 0
|
||||
}
|
||||
}).exec()
|
||||
setTimeout(() => {
|
||||
@@ -481,13 +485,13 @@
|
||||
const {
|
||||
startDate,
|
||||
endDate
|
||||
} = this.range
|
||||
} = this.calendarRange
|
||||
if (startDate && endDate) {
|
||||
if (this.diffDate(startDate, endDate) < 30) {
|
||||
this.$refs.right.next()
|
||||
this.$refs.right.changeMonth('pre')
|
||||
}
|
||||
} else {
|
||||
this.$refs.right.next()
|
||||
this.$refs.right.changeMonth('next')
|
||||
this.$refs.right.cale.lastHover = false
|
||||
}
|
||||
}
|
||||
@@ -525,13 +529,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
this.$emit('change', value)
|
||||
this.$emit('input', value)
|
||||
this.$emit('update:modelValue', value)
|
||||
this.$emit('input', value)
|
||||
this.$emit('change', value)
|
||||
this.isEmitValue = true
|
||||
},
|
||||
createTimestamp(date) {
|
||||
date = this.fixIosDateFormat(date)
|
||||
date = fixIosDateFormat(date)
|
||||
return Date.parse(new Date(date))
|
||||
},
|
||||
singleChange(e) {
|
||||
@@ -540,12 +544,10 @@
|
||||
this.confirmSingleChange()
|
||||
},
|
||||
confirmSingleChange() {
|
||||
if (!this.inputDate) {
|
||||
this.pickerVisible = false
|
||||
return
|
||||
}
|
||||
if(!this.checkDate(this.inputDate)){
|
||||
this.inputDate = this.getDate(Date.now())
|
||||
if(!checkDate(this.inputDate)){
|
||||
const now = new Date()
|
||||
this.calendarDate = this.inputDate = getDate(now)
|
||||
this.pickerTime = getTime(now, this.hideSecond)
|
||||
}
|
||||
|
||||
let startLaterInputDate = false
|
||||
@@ -553,10 +555,10 @@
|
||||
if(this.start) {
|
||||
let startString = this.start
|
||||
if(typeof this.start === 'number'){
|
||||
startString = this.getDateTime(this.start)
|
||||
startString = getDateTime(this.start, this.hideSecond)
|
||||
}
|
||||
[startDate, startTime] = startString.split(' ')
|
||||
if(this.start && !this.dateCompare(startDate, this.inputDate)) {
|
||||
if(this.start && !dateCompare(startDate, this.inputDate)) {
|
||||
startLaterInputDate = true
|
||||
this.inputDate = startDate
|
||||
}
|
||||
@@ -567,23 +569,23 @@
|
||||
if(this.end) {
|
||||
let endString = this.end
|
||||
if(typeof this.end === 'number'){
|
||||
endString = this.getDateTime(this.end)
|
||||
endString = getDateTime(this.end, this.hideSecond)
|
||||
}
|
||||
[endDate, endTime] = endString.split(' ')
|
||||
if(this.end && !this.dateCompare(this.inputDate, endDate)) {
|
||||
if(this.end && !dateCompare(this.inputDate, endDate)) {
|
||||
endEarlierInputDate = true
|
||||
this.inputDate = endDate
|
||||
}
|
||||
}
|
||||
if (this.hasTime) {
|
||||
if(startLaterInputDate){
|
||||
this.pickerTime = startTime || this.getDefaultSecond()
|
||||
this.pickerTime = startTime || getDefaultSecond(this.hideSecond)
|
||||
}
|
||||
if(endEarlierInputDate){
|
||||
this.pickerTime = endTime || this.getDefaultSecond()
|
||||
this.pickerTime = endTime || getDefaultSecond(this.hideSecond)
|
||||
}
|
||||
if(!this.pickerTime){
|
||||
this.pickerTime = this.getTime(Date.now())
|
||||
this.pickerTime = getTime(Date.now(), this.hideSecond)
|
||||
}
|
||||
this.displayValue = `${this.inputDate} ${this.pickerTime}`
|
||||
} else {
|
||||
@@ -659,11 +661,11 @@
|
||||
this.pickerVisible = false
|
||||
return
|
||||
}
|
||||
if(!this.checkDate(this.tempRange.startDate)){
|
||||
this.tempRange.startDate = this.getDate(Date.now())
|
||||
if(!checkDate(this.tempRange.startDate)){
|
||||
this.tempRange.startDate = getDate(Date.now())
|
||||
}
|
||||
if(!this.checkDate(this.tempRange.endDate)){
|
||||
this.tempRange.endDate = this.getDate(Date.now())
|
||||
if(!checkDate(this.tempRange.endDate)){
|
||||
this.tempRange.endDate = getDate(Date.now())
|
||||
}
|
||||
|
||||
let start, end
|
||||
@@ -674,14 +676,14 @@
|
||||
if(this.start) {
|
||||
let startString = this.start
|
||||
if(typeof this.start === 'number'){
|
||||
startString = this.getDateTime(this.start)
|
||||
startString = getDateTime(this.start, this.hideSecond)
|
||||
}
|
||||
[startDate,startTime] = startString.split(' ')
|
||||
if(this.start && !this.dateCompare(this.start, this.tempRange.startDate)) {
|
||||
if(this.start && !dateCompare(this.start, this.tempRange.startDate)) {
|
||||
startDateLaterRangeStartDate = true
|
||||
this.tempRange.startDate = startDate
|
||||
}
|
||||
if(this.start && !this.dateCompare(this.start, this.tempRange.endDate)) {
|
||||
if(this.start && !dateCompare(this.start, this.tempRange.endDate)) {
|
||||
startDateLaterRangeEndDate = true
|
||||
this.tempRange.endDate = startDate
|
||||
}
|
||||
@@ -692,48 +694,48 @@
|
||||
if(this.end) {
|
||||
let endString = this.end
|
||||
if(typeof this.end === 'number'){
|
||||
endString = this.getDateTime(this.end)
|
||||
endString = getDateTime(this.end, this.hideSecond)
|
||||
}
|
||||
[endDate,endTime] = endString.split(' ')
|
||||
|
||||
if(this.end && !this.dateCompare(this.tempRange.startDate, this.end)) {
|
||||
if(this.end && !dateCompare(this.tempRange.startDate, this.end)) {
|
||||
endDateEarlierRangeStartDate = true
|
||||
this.tempRange.startDate = endDate
|
||||
}
|
||||
if(this.end && !this.dateCompare(this.tempRange.endDate, this.end)) {
|
||||
if(this.end && !dateCompare(this.tempRange.endDate, this.end)) {
|
||||
endDateEarlierRangeEndDate = true
|
||||
this.tempRange.endDate = endDate
|
||||
}
|
||||
}
|
||||
if (!this.hasTime) {
|
||||
start = this.range.startDate = this.tempRange.startDate
|
||||
end = this.range.endDate = this.tempRange.endDate
|
||||
start = this.displayRangeValue.startDate = this.tempRange.startDate
|
||||
end = this.displayRangeValue.endDate = this.tempRange.endDate
|
||||
} else {
|
||||
if(startDateLaterRangeStartDate){
|
||||
this.tempRange.startTime = startTime || this.getDefaultSecond()
|
||||
this.tempRange.startTime = startTime || getDefaultSecond(this.hideSecond)
|
||||
}else if(endDateEarlierRangeStartDate){
|
||||
this.tempRange.startTime = endTime || this.getDefaultSecond()
|
||||
this.tempRange.startTime = endTime || getDefaultSecond(this.hideSecond)
|
||||
}
|
||||
if(!this.tempRange.startTime){
|
||||
this.tempRange.startTime = this.getTime(Date.now())
|
||||
this.tempRange.startTime = getTime(Date.now(), this.hideSecond)
|
||||
}
|
||||
|
||||
if(startDateLaterRangeEndDate){
|
||||
this.tempRange.endTime = startTime || this.getDefaultSecond()
|
||||
this.tempRange.endTime = startTime || getDefaultSecond(this.hideSecond)
|
||||
}else if(endDateEarlierRangeEndDate){
|
||||
this.tempRange.endTime = endTime || this.getDefaultSecond()
|
||||
this.tempRange.endTime = endTime || getDefaultSecond(this.hideSecond)
|
||||
}
|
||||
if(!this.tempRange.endTime){
|
||||
this.tempRange.endTime = this.getTime(Date.now())
|
||||
this.tempRange.endTime = getTime(Date.now(), this.hideSecond)
|
||||
}
|
||||
start = this.range.startDate = `${this.tempRange.startDate} ${this.tempRange.startTime}`
|
||||
end = this.range.endDate = `${this.tempRange.endDate} ${this.tempRange.endTime}`
|
||||
start = this.displayRangeValue.startDate = `${this.tempRange.startDate} ${this.tempRange.startTime}`
|
||||
end = this.displayRangeValue.endDate = `${this.tempRange.endDate} ${this.tempRange.endTime}`
|
||||
}
|
||||
if(!this.dateCompare(start,end)){
|
||||
if(!dateCompare(start,end)){
|
||||
[start, end] = [end, start]
|
||||
}
|
||||
this.range.startDate = start
|
||||
this.range.endDate = end
|
||||
this.displayRangeValue.startDate = start
|
||||
this.displayRangeValue.endDate = end
|
||||
const displayRange = [start, end]
|
||||
this.setEmit(displayRange)
|
||||
this.pickerVisible = false
|
||||
@@ -742,7 +744,7 @@
|
||||
if (!(before && after)) return
|
||||
|
||||
const type = temp ? 'tempRange' : 'range'
|
||||
const isStartEarlierEnd = this.dateCompare(before, after)
|
||||
const isStartEarlierEnd = dateCompare(before, after)
|
||||
this[type].startDate = isStartEarlierEnd ? before : after
|
||||
this[type].endDate = isStartEarlierEnd ? after : before
|
||||
},
|
||||
@@ -785,8 +787,8 @@
|
||||
this.$emit('update:modelValue', '')
|
||||
}
|
||||
} else {
|
||||
this.range.startDate = ''
|
||||
this.range.endDate = ''
|
||||
this.displayRangeValue.startDate = ''
|
||||
this.displayRangeValue.endDate = ''
|
||||
this.tempRange.startDate = ''
|
||||
this.tempRange.startTime = ''
|
||||
this.tempRange.endDate = ''
|
||||
@@ -796,7 +798,7 @@
|
||||
} else {
|
||||
this.$refs.left && this.$refs.left.clearCalender()
|
||||
this.$refs.right && this.$refs.right.clearCalender()
|
||||
this.$refs.right && this.$refs.right.next()
|
||||
this.$refs.right && this.$refs.right.changeMonth('next')
|
||||
}
|
||||
if (needEmit) {
|
||||
this.$emit('change', [])
|
||||
@@ -804,65 +806,6 @@
|
||||
this.$emit('update:modelValue', [])
|
||||
}
|
||||
}
|
||||
},
|
||||
parseDate(date) {
|
||||
date = this.fixIosDateFormat(date)
|
||||
const defVal = new Date(date)
|
||||
const year = defVal.getFullYear()
|
||||
const month = defVal.getMonth() + 1
|
||||
const day = defVal.getDate()
|
||||
const hour = defVal.getHours()
|
||||
const minute = defVal.getMinutes()
|
||||
const second = defVal.getSeconds()
|
||||
const defDate = year + '-' + this.lessTen(month) + '-' + this.lessTen(day)
|
||||
const defTime = this.lessTen(hour) + ':' + this.lessTen(minute) + (this.hideSecond ? '' : (':' + this
|
||||
.lessTen(second)))
|
||||
return {
|
||||
defDate,
|
||||
defTime
|
||||
}
|
||||
},
|
||||
lessTen(item) {
|
||||
return item < 10 ? '0' + item : item
|
||||
},
|
||||
//兼容 iOS、safari 日期格式
|
||||
fixIosDateFormat(value) {
|
||||
// #ifndef MP
|
||||
if (typeof value === 'string') {
|
||||
value = value.replace(/-/g, '/')
|
||||
}
|
||||
// #endif
|
||||
return value
|
||||
},
|
||||
checkDate(date){
|
||||
const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g
|
||||
return date.match(dateReg)
|
||||
},
|
||||
getDateTime(date){
|
||||
return `${this.getDate(date)} ${this.getTime(date)}`
|
||||
},
|
||||
getDate(date){
|
||||
date = new Date(date)
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth()+1
|
||||
const day = date.getDate()
|
||||
return `${year}-${this.addZero(month)}-${this.addZero(day)}`
|
||||
},
|
||||
getTime(date){
|
||||
date = new Date(date)
|
||||
const hour = date.getHours()
|
||||
const minute = date.getMinutes()
|
||||
const second = date.getSeconds()
|
||||
return this.hideSecond ? `${this.addZero(hour)}:${this.addZero(minute)}` : `${this.addZero(hour)}:${this.addZero(minute)}:${this.addZero(second)}`
|
||||
},
|
||||
addZero(num) {
|
||||
if(num < 10){
|
||||
num = `0${num}`
|
||||
}
|
||||
return num
|
||||
},
|
||||
getDefaultSecond() {
|
||||
return this.hideSecond ? '00:00' : '00:00:00'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -890,7 +833,11 @@
|
||||
padding-left: 3px;
|
||||
}
|
||||
.range-separator{
|
||||
height: 35px;
|
||||
/* #ifndef MP */
|
||||
padding: 0 2px;
|
||||
/* #endif */
|
||||
line-height: 35px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -917,15 +864,18 @@
|
||||
|
||||
.uni-date__x-input {
|
||||
width: auto;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
line-height: 1;
|
||||
font-size: 14px;
|
||||
height: 35px;
|
||||
/* #ifndef MP */
|
||||
padding-left: 5px;
|
||||
/* #endif */
|
||||
position: relative;
|
||||
flex: 1;
|
||||
line-height: 35px;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.t-c {
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -962,7 +912,7 @@
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
border: 1px solid #EBEEF5;
|
||||
box-shadow: 0px 0px 3px 0px rgba(0, 82, 79, 0.65);
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@@ -972,7 +922,7 @@
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
border: 1px solid #EBEEF5;
|
||||
box-shadow: 0px 0px 3px 0px rgba(0, 82, 79, 0.65);
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
@@ -1023,7 +973,7 @@
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.popup-x-footer .confirm {
|
||||
.popup-x-footer .confirm-text {
|
||||
margin-left: 20px;
|
||||
color: $uni-primary;
|
||||
}
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
class Calendar {
|
||||
constructor({
|
||||
date,
|
||||
selected,
|
||||
startDate,
|
||||
endDate,
|
||||
range,
|
||||
// multipleStatus
|
||||
} = {}) {
|
||||
// 当前日期
|
||||
this.date = this.getDate(new Date()) // 当前初入日期
|
||||
this.date = this.getDateObj(new Date()) // 当前初入日期
|
||||
// 打点信息
|
||||
this.selected = selected || [];
|
||||
// 范围开始
|
||||
// 起始时间
|
||||
this.startDate = startDate
|
||||
// 范围结束
|
||||
// 终止时间
|
||||
this.endDate = endDate
|
||||
// 是否范围选择
|
||||
this.range = range
|
||||
// 多选状态
|
||||
this.cleanMultipleStatus()
|
||||
// 每周日期
|
||||
this.weeks = {}
|
||||
// this._getWeek(this.date.fullDate)
|
||||
// this.multipleStatus = multipleStatus
|
||||
this.lastHover = false
|
||||
}
|
||||
/**
|
||||
@@ -29,8 +26,8 @@ class Calendar {
|
||||
* @param {Object} date
|
||||
*/
|
||||
setDate(date) {
|
||||
this.selectDate = this.getDate(date)
|
||||
this._getWeek(this.selectDate.fullDate)
|
||||
const selectDate = this.getDateObj(date)
|
||||
this.getWeeks(selectDate.fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,103 +41,82 @@ class Calendar {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置开始日期
|
||||
*/
|
||||
resetSatrtDate(startDate) {
|
||||
// 范围开始
|
||||
setStartDate(startDate) {
|
||||
this.startDate = startDate
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置结束日期
|
||||
*/
|
||||
resetEndDate(endDate) {
|
||||
// 范围结束
|
||||
setEndDate(endDate) {
|
||||
this.endDate = endDate
|
||||
}
|
||||
|
||||
getPreMonthObj(date){
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
|
||||
const oldMonth = date.getMonth()
|
||||
date.setMonth(oldMonth - 1)
|
||||
const newMonth = date.getMonth()
|
||||
if(oldMonth !== 0 && newMonth - oldMonth === 0){
|
||||
date.setMonth(newMonth - 1)
|
||||
}
|
||||
return this.getDateObj(date)
|
||||
}
|
||||
getNextMonthObj(date){
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
|
||||
const oldMonth = date.getMonth()
|
||||
date.setMonth(oldMonth + 1)
|
||||
const newMonth = date.getMonth()
|
||||
if(newMonth - oldMonth > 1){
|
||||
date.setMonth(newMonth - 1)
|
||||
}
|
||||
return this.getDateObj(date)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任意时间
|
||||
* 获取指定格式Date对象
|
||||
*/
|
||||
getDate(date, AddDayCount = 0, str = 'day') {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
if (typeof date !== 'object') {
|
||||
date = date.replace(/-/g, '/')
|
||||
}
|
||||
const dd = new Date(date)
|
||||
switch (str) {
|
||||
case 'day':
|
||||
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break
|
||||
case 'month':
|
||||
if (dd.getDate() === 31 && AddDayCount>0) {
|
||||
dd.setDate(dd.getDate() + AddDayCount)
|
||||
} else {
|
||||
const preMonth = dd.getMonth()
|
||||
dd.setMonth(preMonth + AddDayCount) // 获取AddDayCount天后的日期
|
||||
const nextMonth = dd.getMonth()
|
||||
// 处理 pre 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
|
||||
if(AddDayCount<0 && preMonth!==0 && nextMonth-preMonth>AddDayCount){
|
||||
dd.setMonth(nextMonth+(nextMonth-preMonth+AddDayCount))
|
||||
}
|
||||
// 处理 next 切换月份目标月份为2月没有当前日(30 31) 切换错误问题
|
||||
if(AddDayCount>0 && nextMonth-preMonth>AddDayCount){
|
||||
dd.setMonth(nextMonth-(nextMonth-preMonth-AddDayCount))
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'year':
|
||||
dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break
|
||||
}
|
||||
const y = dd.getFullYear()
|
||||
const m = dd.getMonth() + 1 < 10 ? '0' + (dd.getMonth() + 1) : dd.getMonth() + 1 // 获取当前月份的日期,不足10补0
|
||||
const d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
|
||||
getDateObj(date) {
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
|
||||
return {
|
||||
fullDate: y + '-' + m + '-' + d,
|
||||
year: y,
|
||||
month: m,
|
||||
date: d,
|
||||
day: dd.getDay()
|
||||
fullDate: getDate(date),
|
||||
year: date.getFullYear(),
|
||||
month: addZero(date.getMonth() + 1),
|
||||
date: addZero(date.getDate()),
|
||||
day: date.getDay()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取上月剩余天数
|
||||
* 获取上一个月日期集合
|
||||
*/
|
||||
_getLastMonthDays(firstDay, full) {
|
||||
let dateArr = []
|
||||
for (let i = firstDay; i > 0; i--) {
|
||||
const beforeDate = new Date(full.year, full.month - 1, -i + 1).getDate()
|
||||
dateArr.push({
|
||||
date: beforeDate,
|
||||
month: full.month - 1,
|
||||
getPreMonthDays(amount, dateObj) {
|
||||
const result = []
|
||||
for (let i = amount - 1; i >= 0; i--) {
|
||||
const month = dateObj.month - 1
|
||||
result.push({
|
||||
date: new Date(dateObj.year, month, -i).getDate(),
|
||||
month,
|
||||
disable: true
|
||||
})
|
||||
}
|
||||
return dateArr
|
||||
return result
|
||||
}
|
||||
/**
|
||||
* 获取本月天数
|
||||
* 获取本月日期集合
|
||||
*/
|
||||
_currentMonthDys(dateData, full) {
|
||||
let dateArr = []
|
||||
let fullDate = this.date.fullDate
|
||||
for (let i = 1; i <= dateData; i++) {
|
||||
let isinfo = false
|
||||
let nowDate = full.year + '-' + (full.month < 10 ?
|
||||
full.month : full.month) + '-' + (i < 10 ?
|
||||
'0' + i : i)
|
||||
// 是否今天
|
||||
let isDay = fullDate === nowDate
|
||||
getCurrentMonthDays(amount, dateObj) {
|
||||
const result = []
|
||||
const fullDate = this.date.fullDate
|
||||
for (let i = 1; i <= amount; i++) {
|
||||
const currentDate = `${dateObj.year}-${dateObj.month}-${addZero(i)}`
|
||||
const isToday = fullDate === currentDate
|
||||
// 获取打点信息
|
||||
let info = this.selected && this.selected.find((item) => {
|
||||
if (this.dateEqual(nowDate, item.date)) {
|
||||
const info = this.selected && this.selected.find((item) => {
|
||||
if (this.dateEqual(currentDate, item.date)) {
|
||||
return item
|
||||
}
|
||||
})
|
||||
@@ -149,62 +125,52 @@ class Calendar {
|
||||
let disableBefore = true
|
||||
let disableAfter = true
|
||||
if (this.startDate) {
|
||||
// let dateCompBefore = this.dateCompare(this.startDate, fullDate)
|
||||
// disableBefore = this.dateCompare(dateCompBefore ? this.startDate : fullDate, nowDate)
|
||||
disableBefore = this.dateCompare(this.startDate, nowDate)
|
||||
disableBefore = dateCompare(this.startDate, currentDate)
|
||||
}
|
||||
|
||||
if (this.endDate) {
|
||||
// let dateCompAfter = this.dateCompare(fullDate, this.endDate)
|
||||
// disableAfter = this.dateCompare(nowDate, dateCompAfter ? this.endDate : fullDate)
|
||||
disableAfter = this.dateCompare(nowDate, this.endDate)
|
||||
}
|
||||
let multiples = this.multipleStatus.data
|
||||
let checked = false
|
||||
let multiplesStatus = -1
|
||||
if (this.range) {
|
||||
if (multiples) {
|
||||
multiplesStatus = multiples.findIndex((item) => {
|
||||
return this.dateEqual(item, nowDate)
|
||||
})
|
||||
}
|
||||
if (multiplesStatus !== -1) {
|
||||
checked = true
|
||||
}
|
||||
}
|
||||
let data = {
|
||||
fullDate: nowDate,
|
||||
year: full.year,
|
||||
date: i,
|
||||
multiple: this.range ? checked : false,
|
||||
beforeMultiple: this.isLogicBefore(nowDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
afterMultiple: this.isLogicAfter(nowDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
month: full.month,
|
||||
disable: !(disableBefore && disableAfter),
|
||||
isDay,
|
||||
userChecked: false
|
||||
}
|
||||
if (info) {
|
||||
data.extraInfo = info
|
||||
disableAfter = dateCompare(currentDate, this.endDate)
|
||||
}
|
||||
|
||||
dateArr.push(data)
|
||||
let multiples = this.multipleStatus.data
|
||||
let multiplesStatus = -1
|
||||
if (this.range && multiples) {
|
||||
multiplesStatus = multiples.findIndex((item) => {
|
||||
return this.dateEqual(item, currentDate)
|
||||
})
|
||||
}
|
||||
return dateArr
|
||||
const checked = multiplesStatus !== -1
|
||||
|
||||
result.push({
|
||||
fullDate: currentDate,
|
||||
year: dateObj.year,
|
||||
date: i,
|
||||
multiple: this.range ? checked : false,
|
||||
beforeMultiple: this.isLogicBefore(currentDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
afterMultiple: this.isLogicAfter(currentDate, this.multipleStatus.before, this.multipleStatus.after),
|
||||
month: dateObj.month,
|
||||
disable: (this.startDate && !dateCompare(this.startDate, currentDate)) || (this.endDate && !dateCompare(currentDate,this.endDate)),
|
||||
isToday,
|
||||
userChecked: false,
|
||||
extraInfo: info
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
/**
|
||||
* 获取下月天数
|
||||
* 获取下一个月日期集合
|
||||
*/
|
||||
_getNextMonthDays(surplus, full) {
|
||||
let dateArr = []
|
||||
for (let i = 1; i < surplus + 1; i++) {
|
||||
dateArr.push({
|
||||
_getNextMonthDays(amount, dateObj) {
|
||||
const result = []
|
||||
const month = dateObj.month + 1
|
||||
for (let i = 1; i <= amount; i++) {
|
||||
result.push({
|
||||
date: i,
|
||||
month: Number(full.month) + 1,
|
||||
month,
|
||||
disable: true
|
||||
})
|
||||
}
|
||||
return dateArr
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,58 +181,37 @@ class Calendar {
|
||||
if (!date) {
|
||||
date = new Date()
|
||||
}
|
||||
const dateInfo = this.canlender.find(item => item.fullDate === this.getDate(date).fullDate)
|
||||
return dateInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较时间大小
|
||||
*/
|
||||
dateCompare(startDate, endDate) {
|
||||
// 计算截止时间
|
||||
startDate = new Date(startDate.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
endDate = new Date(endDate.replace('-', '/').replace('-', '/'))
|
||||
if (startDate <= endDate) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return this.calendar.find(item => item.fullDate === this.getDateObj(date).fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较时间是否相等
|
||||
*/
|
||||
dateEqual(before, after) {
|
||||
// 计算截止时间
|
||||
before = new Date(before.replace('-', '/').replace('-', '/'))
|
||||
// 计算详细项的截止时间
|
||||
after = new Date(after.replace('-', '/').replace('-', '/'))
|
||||
if (before.getTime() - after.getTime() === 0) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
before = new Date(fixIosDateFormat(before))
|
||||
after = new Date(fixIosDateFormat(after))
|
||||
return before.valueOf() === after.valueOf()
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较真实起始日期
|
||||
*/
|
||||
|
||||
isLogicBefore(currentDay, before, after) {
|
||||
isLogicBefore(currentDate, before, after) {
|
||||
let logicBefore = before
|
||||
if (before && after) {
|
||||
logicBefore = this.dateCompare(before, after) ? before : after
|
||||
logicBefore = dateCompare(before, after) ? before : after
|
||||
}
|
||||
return this.dateEqual(logicBefore, currentDay)
|
||||
return this.dateEqual(logicBefore, currentDate)
|
||||
}
|
||||
|
||||
isLogicAfter(currentDay, before, after) {
|
||||
isLogicAfter(currentDate, before, after) {
|
||||
let logicAfter = after
|
||||
if (before && after) {
|
||||
logicAfter = this.dateCompare(before, after) ? after : before
|
||||
logicAfter = dateCompare(before, after) ? after : before
|
||||
}
|
||||
return this.dateEqual(logicAfter, currentDay)
|
||||
return this.dateEqual(logicAfter, currentDate)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -286,7 +231,7 @@ class Calendar {
|
||||
var unixDe = de.getTime() - 24 * 60 * 60 * 1000
|
||||
for (var k = unixDb; k <= unixDe;) {
|
||||
k = k + 24 * 60 * 60 * 1000
|
||||
arr.push(this.getDate(new Date(parseInt(k))).fullDate)
|
||||
arr.push(this.getDateObj(new Date(parseInt(k))).fullDate)
|
||||
}
|
||||
return arr
|
||||
}
|
||||
@@ -295,11 +240,12 @@ class Calendar {
|
||||
* 获取多选状态
|
||||
*/
|
||||
setMultiple(fullDate) {
|
||||
if (!this.range) return
|
||||
|
||||
let {
|
||||
before,
|
||||
after
|
||||
} = this.multipleStatus
|
||||
if (!this.range) return
|
||||
if (before && after) {
|
||||
if (!this.lastHover) {
|
||||
this.lastHover = true
|
||||
@@ -316,7 +262,7 @@ class Calendar {
|
||||
this.lastHover = false
|
||||
} else {
|
||||
this.multipleStatus.after = fullDate
|
||||
if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||||
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus
|
||||
.after);
|
||||
} else {
|
||||
@@ -326,32 +272,28 @@ class Calendar {
|
||||
this.lastHover = true
|
||||
}
|
||||
}
|
||||
this._getWeek(fullDate)
|
||||
this.getWeeks(fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
* 鼠标 hover 更新多选状态
|
||||
*/
|
||||
setHoverMultiple(fullDate) {
|
||||
let {
|
||||
before,
|
||||
after
|
||||
} = this.multipleStatus
|
||||
if (!this.range || this.lastHover) return
|
||||
|
||||
if (!this.range) return
|
||||
if (this.lastHover) return
|
||||
const { before } = this.multipleStatus
|
||||
|
||||
if (!before) {
|
||||
this.multipleStatus.before = fullDate
|
||||
} else {
|
||||
this.multipleStatus.after = fullDate
|
||||
if (this.dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||||
if (dateCompare(this.multipleStatus.before, this.multipleStatus.after)) {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.before, this.multipleStatus.after);
|
||||
} else {
|
||||
this.multipleStatus.data = this.geDateAll(this.multipleStatus.after, this.multipleStatus.before);
|
||||
}
|
||||
}
|
||||
this._getWeek(fullDate)
|
||||
this.getWeeks(fullDate)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -361,12 +303,12 @@ class Calendar {
|
||||
this.multipleStatus.before = before
|
||||
this.multipleStatus.after = after
|
||||
if (before && after) {
|
||||
if (this.dateCompare(before, after)) {
|
||||
if (dateCompare(before, after)) {
|
||||
this.multipleStatus.data = this.geDateAll(before, after);
|
||||
this._getWeek(after)
|
||||
this.getWeeks(after)
|
||||
} else {
|
||||
this.multipleStatus.data = this.geDateAll(after, before);
|
||||
this._getWeek(before)
|
||||
this.getWeeks(before)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,46 +317,87 @@ class Calendar {
|
||||
* 获取每周数据
|
||||
* @param {Object} dateData
|
||||
*/
|
||||
_getWeek(dateData) {
|
||||
getWeeks(dateData) {
|
||||
const {
|
||||
fullDate,
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
day
|
||||
} = this.getDate(dateData)
|
||||
let firstDay = new Date(year, month - 1, 1).getDay()
|
||||
let currentDay = new Date(year, month, 0).getDate()
|
||||
let dates = {
|
||||
lastMonthDays: this._getLastMonthDays(firstDay, this.getDate(dateData)), // 上个月末尾几天
|
||||
currentMonthDys: this._currentMonthDys(currentDay, this.getDate(dateData)), // 本月天数
|
||||
nextMonthDays: [], // 下个月开始几天
|
||||
weeks: []
|
||||
} = this.getDateObj(dateData)
|
||||
|
||||
const preMonthDayAmount = new Date(year, month - 1, 1).getDay()
|
||||
const preMonthDays = this.getPreMonthDays(preMonthDayAmount, this.getDateObj(dateData))
|
||||
|
||||
const currentMonthDayAmount = new Date(year, month, 0).getDate()
|
||||
const currentMonthDays = this.getCurrentMonthDays(currentMonthDayAmount, this.getDateObj(dateData))
|
||||
|
||||
const nextMonthDayAmount = 42 - preMonthDayAmount - currentMonthDayAmount
|
||||
const nextMonthDays = this._getNextMonthDays(nextMonthDayAmount, this.getDateObj(dateData))
|
||||
|
||||
const calendarDays = [...preMonthDays, ...currentMonthDays, ...nextMonthDays]
|
||||
|
||||
const weeks = new Array(6)
|
||||
for (let i = 0; i < calendarDays.length; i++) {
|
||||
const index = Math.floor(i / 7)
|
||||
if(!weeks[index]){
|
||||
weeks[index] = new Array(7)
|
||||
}
|
||||
let canlender = []
|
||||
const surplus = 42 - (dates.lastMonthDays.length + dates.currentMonthDys.length)
|
||||
dates.nextMonthDays = this._getNextMonthDays(surplus, this.getDate(dateData))
|
||||
canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
|
||||
let weeks = {}
|
||||
// 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
|
||||
for (let i = 0; i < canlender.length; i++) {
|
||||
if (i % 7 === 0) {
|
||||
weeks[parseInt(i / 7)] = new Array(7)
|
||||
weeks[index][i % 7] = calendarDays[i]
|
||||
}
|
||||
weeks[parseInt(i / 7)][i % 7] = canlender[i]
|
||||
}
|
||||
this.canlender = canlender
|
||||
|
||||
this.calendar = calendarDays
|
||||
this.weeks = weeks
|
||||
}
|
||||
|
||||
//静态方法
|
||||
// static init(date) {
|
||||
// if (!this.instance) {
|
||||
// this.instance = new Calendar(date);
|
||||
// }
|
||||
// return this.instance;
|
||||
// }
|
||||
}
|
||||
|
||||
function getDateTime(date, hideSecond){
|
||||
return `${getDate(date)} ${getTime(date, hideSecond)}`
|
||||
}
|
||||
|
||||
export default Calendar
|
||||
function getDate(date) {
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth()+1
|
||||
const day = date.getDate()
|
||||
return `${year}-${addZero(month)}-${addZero(day)}`
|
||||
}
|
||||
|
||||
function getTime(date, hideSecond){
|
||||
date = fixIosDateFormat(date)
|
||||
date = new Date(date)
|
||||
const hour = date.getHours()
|
||||
const minute = date.getMinutes()
|
||||
const second = date.getSeconds()
|
||||
return hideSecond ? `${addZero(hour)}:${addZero(minute)}` : `${addZero(hour)}:${addZero(minute)}:${addZero(second)}`
|
||||
}
|
||||
|
||||
function addZero(num) {
|
||||
if(num < 10){
|
||||
num = `0${num}`
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
function getDefaultSecond(hideSecond) {
|
||||
return hideSecond ? '00:00' : '00:00:00'
|
||||
}
|
||||
|
||||
function dateCompare(startDate, endDate) {
|
||||
startDate = new Date(fixIosDateFormat(startDate))
|
||||
endDate = new Date(fixIosDateFormat(endDate))
|
||||
return startDate <= endDate
|
||||
}
|
||||
|
||||
function checkDate(date){
|
||||
const dateReg = /((19|20)\d{2})(-|\/)\d{1,2}(-|\/)\d{1,2}/g
|
||||
return date.match(dateReg)
|
||||
}
|
||||
|
||||
const dateTimeReg = /^\d{4}-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])( [0-5]?[0-9]:[0-5]?[0-9]:[0-5]?[0-9])?$/
|
||||
function fixIosDateFormat(value) {
|
||||
if (typeof value === 'string' && dateTimeReg.test(value)) {
|
||||
value = value.replace(/-/g, '/')
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
export {Calendar, getDateTime, getDate, getTime, addZero, getDefaultSecond, dateCompare, checkDate, fixIosDateFormat}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-datetime-picker",
|
||||
"displayName": "uni-datetime-picker 日期选择器",
|
||||
"version": "2.2.19",
|
||||
"version": "2.2.23",
|
||||
"description": "uni-datetime-picker 日期时间选择器,支持日历,支持范围选择",
|
||||
"keywords": [
|
||||
"uni-datetime-picker",
|
||||
|
||||
@@ -1,53 +1,97 @@
|
||||
## 1.1.3(2022-09-22)
|
||||
- 修复,引入 uni.scss 引入默认主题色报错的问题
|
||||
## 1.1.2(2022-09-22)
|
||||
- 增加主题色 primaryColor 配置选项
|
||||
## 1.1.1(2022-09-19)
|
||||
- 修复,输入后回车,change 事件触发两次,[详情](https://ask.dcloud.net.cn/question/152149)
|
||||
## 1.1.9(2023-04-11)
|
||||
- 修复 vue3 下 keyboardheightchange 事件报错的bug
|
||||
## 1.1.8(2023-03-29)
|
||||
- 优化 trim 属性默认值
|
||||
## 1.1.7(2023-03-29)
|
||||
- 新增 cursor-spacing 属性
|
||||
## 1.1.6(2023-01-28)
|
||||
- 新增 keyboardheightchange 事件,可监听键盘高度变化
|
||||
## 1.1.5(2022-11-29)
|
||||
- 优化 主题样式
|
||||
## 1.1.4(2022-10-27)
|
||||
- 修复 props 中背景颜色无默认值的bug
|
||||
## 1.1.0(2022-06-30)
|
||||
|
||||
- 新增 在 uni-forms 1.4.0 中使用可以在 blur 时校验内容
|
||||
- 新增 clear 事件,点击右侧叉号图标触发
|
||||
- 新增 change 事件 ,仅在输入框失去焦点或用户按下回车时触发
|
||||
- 优化 组件样式,组件获取焦点时高亮显示,图标颜色调整等
|
||||
-
|
||||
|
||||
## 1.0.5(2022-06-07)
|
||||
|
||||
- 优化 clearable 显示策略
|
||||
|
||||
## 1.0.4(2022-06-07)
|
||||
|
||||
- 优化 clearable 显示策略
|
||||
|
||||
## 1.0.3(2022-05-20)
|
||||
|
||||
- 修复 关闭图标某些情况下无法取消的 bug
|
||||
|
||||
## 1.0.2(2022-04-12)
|
||||
|
||||
- 修复 默认值不生效的 bug
|
||||
|
||||
## 1.0.1(2022-04-02)
|
||||
|
||||
- 修复 value 不能为 0 的 bug
|
||||
|
||||
## 1.0.0(2021-11-19)
|
||||
|
||||
- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
|
||||
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-easyinput](https://uniapp.dcloud.io/component/uniui/uni-easyinput)
|
||||
|
||||
## 0.1.4(2021-08-20)
|
||||
|
||||
- 修复 在 uni-forms 的动态表单中默认值校验不通过的 bug
|
||||
|
||||
## 0.1.3(2021-08-11)
|
||||
|
||||
- 修复 在 uni-forms 中重置表单,错误信息无法清除的问题
|
||||
|
||||
## 0.1.2(2021-07-30)
|
||||
|
||||
- 优化 vue3 下事件警告的问题
|
||||
|
||||
## 0.1.1
|
||||
|
||||
- 优化 errorMessage 属性支持 Boolean 类型
|
||||
|
||||
## 0.1.0(2021-07-13)
|
||||
|
||||
- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
|
||||
|
||||
## 0.0.16(2021-06-29)
|
||||
|
||||
- 修复 confirmType 属性(仅 type="text" 生效)导致多行文本框无法换行的 bug
|
||||
|
||||
## 0.0.15(2021-06-21)
|
||||
|
||||
- 修复 passwordIcon 属性拼写错误的 bug
|
||||
|
||||
## 0.0.14(2021-06-18)
|
||||
|
||||
- 新增 passwordIcon 属性,当 type=password 时是否显示小眼睛图标
|
||||
- 修复 confirmType 属性不生效的问题
|
||||
|
||||
## 0.0.13(2021-06-04)
|
||||
|
||||
- 修复 disabled 状态可清出内容的 bug
|
||||
|
||||
## 0.0.12(2021-05-12)
|
||||
|
||||
- 新增 组件示例地址
|
||||
|
||||
## 0.0.11(2021-05-07)
|
||||
|
||||
- 修复 input-border 属性不生效的问题
|
||||
|
||||
## 0.0.10(2021-04-30)
|
||||
|
||||
- 修复 ios 遮挡文字、显示一半的问题
|
||||
|
||||
## 0.0.9(2021-02-05)
|
||||
|
||||
- 调整为 uni_modules 目录规范
|
||||
- 优化 兼容 nvue 页面
|
||||
|
||||
@@ -1,34 +1,74 @@
|
||||
<template>
|
||||
<view class="uni-easyinput" :class="{ 'uni-easyinput-error': msg }" :style="boxStyle">
|
||||
<view class="uni-easyinput__content" :class="inputContentClass" :style="inputContentStyle">
|
||||
<uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc"
|
||||
@click="onClickIcon('prefix')" size="22"></uni-icons>
|
||||
<textarea v-if="type === 'textarea'" class="uni-easyinput__content-textarea"
|
||||
:class="{'input-padding':inputBorder}" :name="name" :value="val" :placeholder="placeholder"
|
||||
:placeholderStyle="placeholderStyle" :disabled="disabled"
|
||||
placeholder-class="uni-easyinput__placeholder-class" :maxlength="inputMaxlength" :focus="focused"
|
||||
:autoHeight="autoHeight" @input="onInput" @blur="_Blur" @focus="_Focus" @confirm="onConfirm"></textarea>
|
||||
<input v-else :type="type === 'password'?'text':type" class="uni-easyinput__content-input"
|
||||
:style="inputStyle" :name="name" :value="val" :password="!showPassword && type === 'password'"
|
||||
:placeholder="placeholder" :placeholderStyle="placeholderStyle"
|
||||
placeholder-class="uni-easyinput__placeholder-class" :disabled="disabled" :maxlength="inputMaxlength"
|
||||
:focus="focused" :confirmType="confirmType" @focus="_Focus" @blur="_Blur" @input="onInput"
|
||||
@confirm="onConfirm" />
|
||||
<uni-icons v-if="prefixIcon" class="content-clear-icon" :type="prefixIcon" color="#c0c4cc" @click="onClickIcon('prefix')" size="22"></uni-icons>
|
||||
<textarea
|
||||
v-if="type === 'textarea'"
|
||||
class="uni-easyinput__content-textarea"
|
||||
:class="{ 'input-padding': inputBorder }"
|
||||
:name="name"
|
||||
:value="val"
|
||||
:placeholder="placeholder"
|
||||
:placeholderStyle="placeholderStyle"
|
||||
:disabled="disabled"
|
||||
placeholder-class="uni-easyinput__placeholder-class"
|
||||
:maxlength="inputMaxlength"
|
||||
:focus="focused"
|
||||
:autoHeight="autoHeight"
|
||||
:cursor-spacing="cursorSpacing"
|
||||
@input="onInput"
|
||||
@blur="_Blur"
|
||||
@focus="_Focus"
|
||||
@confirm="onConfirm"
|
||||
@keyboardheightchange="onkeyboardheightchange"
|
||||
></textarea>
|
||||
<input
|
||||
v-else
|
||||
:type="type === 'password' ? 'text' : type"
|
||||
class="uni-easyinput__content-input"
|
||||
:style="inputStyle"
|
||||
:name="name"
|
||||
:value="val"
|
||||
:password="!showPassword && type === 'password'"
|
||||
:placeholder="placeholder"
|
||||
:placeholderStyle="placeholderStyle"
|
||||
placeholder-class="uni-easyinput__placeholder-class"
|
||||
:disabled="disabled"
|
||||
:maxlength="inputMaxlength"
|
||||
:focus="focused"
|
||||
:confirmType="confirmType"
|
||||
:cursor-spacing="cursorSpacing"
|
||||
@focus="_Focus"
|
||||
@blur="_Blur"
|
||||
@input="onInput"
|
||||
@confirm="onConfirm"
|
||||
@keyboardheightchange="onkeyboardheightchange"
|
||||
/>
|
||||
<template v-if="type === 'password' && passwordIcon">
|
||||
<!-- 开启密码时显示小眼睛 -->
|
||||
<uni-icons v-if="isVal" class="content-clear-icon" :class="{'is-textarea-icon':type==='textarea'}"
|
||||
:type="showPassword?'eye-slash-filled':'eye-filled'" :size="22"
|
||||
:color="focusShow ? primaryColor :'#c0c4cc'" @click="onEyes">
|
||||
</uni-icons>
|
||||
<uni-icons
|
||||
v-if="isVal"
|
||||
class="content-clear-icon"
|
||||
:class="{ 'is-textarea-icon': type === 'textarea' }"
|
||||
:type="showPassword ? 'eye-slash-filled' : 'eye-filled'"
|
||||
:size="22"
|
||||
:color="focusShow ? primaryColor : '#c0c4cc'"
|
||||
@click="onEyes"
|
||||
></uni-icons>
|
||||
</template>
|
||||
<template v-else-if="suffixIcon">
|
||||
<uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc"
|
||||
@click="onClickIcon('suffix')" size="22"></uni-icons>
|
||||
<uni-icons v-if="suffixIcon" class="content-clear-icon" :type="suffixIcon" color="#c0c4cc" @click="onClickIcon('suffix')" size="22"></uni-icons>
|
||||
</template>
|
||||
<template v-else>
|
||||
<uni-icons v-if="clearable && isVal && !disabled && type !== 'textarea'" class="content-clear-icon"
|
||||
:class="{'is-textarea-icon':type==='textarea'}" type="clear" :size="clearSize"
|
||||
:color="msg?'#dd524d':(focusShow? primaryColor :'#c0c4cc')" @click="onClear"></uni-icons>
|
||||
<uni-icons
|
||||
v-if="clearable && isVal && !disabled && type !== 'textarea'"
|
||||
class="content-clear-icon"
|
||||
:class="{ 'is-textarea-icon': type === 'textarea' }"
|
||||
type="clear"
|
||||
:size="clearSize"
|
||||
:color="msg ? '#dd524d' : focusShow ? primaryColor : '#c0c4cc'"
|
||||
@click="onClear"
|
||||
></uni-icons>
|
||||
</template>
|
||||
<slot name="right"></slot>
|
||||
</view>
|
||||
@@ -61,6 +101,7 @@
|
||||
* @property {String} suffixIcon 输入框尾部图标
|
||||
* @property {String} primaryColor 设置主题色(默认#2979ff)
|
||||
* @property {Boolean} trim 是否自动去除两端的空格
|
||||
* @property {Boolean} cursorSpacing 指定光标与键盘的距离,单位 px
|
||||
* @value both 去除两端空格
|
||||
* @value left 去除左侧空格
|
||||
* @value right 去除右侧空格
|
||||
@@ -79,27 +120,27 @@
|
||||
* @example <uni-easyinput v-model="mobile"></uni-easyinput>
|
||||
*/
|
||||
function obj2strClass(obj) {
|
||||
let classess = ''
|
||||
let classess = '';
|
||||
for (let key in obj) {
|
||||
const val = obj[key]
|
||||
const val = obj[key];
|
||||
if (val) {
|
||||
classess += `${key} `
|
||||
classess += `${key} `;
|
||||
}
|
||||
}
|
||||
return classess
|
||||
return classess;
|
||||
}
|
||||
|
||||
function obj2strStyle(obj) {
|
||||
let style = ''
|
||||
let style = '';
|
||||
for (let key in obj) {
|
||||
const val = obj[key]
|
||||
style += `${key}:${val};`
|
||||
const val = obj[key];
|
||||
style += `${key}:${val};`;
|
||||
}
|
||||
return style
|
||||
return style;
|
||||
}
|
||||
export default {
|
||||
name: 'uni-easyinput',
|
||||
emits: ['click', 'iconClick', 'update:modelValue', 'input', 'focus', 'blur', 'confirm', 'clear', 'eyes', 'change'],
|
||||
emits: ['click', 'iconClick', 'update:modelValue', 'input', 'focus', 'blur', 'confirm', 'clear', 'eyes', 'change', 'keyboardheightchange'],
|
||||
model: {
|
||||
prop: 'modelValue',
|
||||
event: 'update:modelValue'
|
||||
@@ -115,7 +156,7 @@
|
||||
formItem: {
|
||||
from: 'uniFormItem',
|
||||
default: null
|
||||
},
|
||||
}
|
||||
},
|
||||
props: {
|
||||
name: String,
|
||||
@@ -172,7 +213,11 @@
|
||||
},
|
||||
trim: {
|
||||
type: [Boolean, String],
|
||||
default: true
|
||||
default: false
|
||||
},
|
||||
cursorSpacing: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
passwordIcon: {
|
||||
type: Boolean,
|
||||
@@ -187,9 +232,10 @@
|
||||
default() {
|
||||
return {
|
||||
color: '#333',
|
||||
backgroundColor: '#fff',
|
||||
disableColor: '#F7F6F6',
|
||||
borderColor: '#e5e5e5'
|
||||
}
|
||||
};
|
||||
}
|
||||
},
|
||||
errorMessage: {
|
||||
@@ -214,12 +260,12 @@
|
||||
computed: {
|
||||
// 输入框内是否有值
|
||||
isVal() {
|
||||
const val = this.val
|
||||
const val = this.val;
|
||||
// fixed by mehaotian 处理值为0的情况,字符串0不在处理范围
|
||||
if (val || val === 0) {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
},
|
||||
|
||||
msg() {
|
||||
@@ -228,7 +274,7 @@
|
||||
// return this.errorMessage || this.formItem.errMsg;
|
||||
// }
|
||||
// TODO 处理头条 formItem 中 errMsg 不更新的问题
|
||||
return this.localMsg || this.errorMessage
|
||||
return this.localMsg || this.errorMessage;
|
||||
},
|
||||
// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,用户可以传入字符串数值
|
||||
inputMaxlength() {
|
||||
@@ -237,7 +283,7 @@
|
||||
|
||||
// 处理外层样式的style
|
||||
boxStyle() {
|
||||
return `color:${this.inputBorder && this.msg?'#e43d33':this.styles.color};`
|
||||
return `color:${this.inputBorder && this.msg ? '#e43d33' : this.styles.color};`;
|
||||
},
|
||||
// input 内容的类和样式处理
|
||||
inputContentClass() {
|
||||
@@ -245,54 +291,55 @@
|
||||
'is-input-border': this.inputBorder,
|
||||
'is-input-error-border': this.inputBorder && this.msg,
|
||||
'is-textarea': this.type === 'textarea',
|
||||
'is-disabled': this.disabled
|
||||
})
|
||||
'is-disabled': this.disabled,
|
||||
'is-focused': this.focusShow
|
||||
});
|
||||
},
|
||||
inputContentStyle() {
|
||||
const focusColor = this.focusShow ? this.primaryColor : this.styles.borderColor
|
||||
const borderColor = this.inputBorder && this.msg ? '#dd524d' : focusColor
|
||||
const focusColor = this.focusShow ? this.primaryColor : this.styles.borderColor;
|
||||
const borderColor = this.inputBorder && this.msg ? '#dd524d' : focusColor;
|
||||
return obj2strStyle({
|
||||
'border-color': borderColor || '#e5e5e5',
|
||||
'background-color': this.disabled ? this.styles.disableColor : '#fff'
|
||||
})
|
||||
'background-color': this.disabled ? this.styles.disableColor : this.styles.backgroundColor
|
||||
});
|
||||
},
|
||||
// input右侧样式
|
||||
inputStyle() {
|
||||
const paddingRight = this.type === 'password' || this.clearable || this.prefixIcon ? '' : '10px'
|
||||
const paddingRight = this.type === 'password' || this.clearable || this.prefixIcon ? '' : '10px';
|
||||
return obj2strStyle({
|
||||
'padding-right': paddingRight,
|
||||
'padding-left': this.prefixIcon ? '' : '10px'
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(newVal) {
|
||||
this.val = newVal
|
||||
this.val = newVal;
|
||||
},
|
||||
modelValue(newVal) {
|
||||
this.val = newVal
|
||||
this.val = newVal;
|
||||
},
|
||||
focus(newVal) {
|
||||
this.$nextTick(() => {
|
||||
this.focused = this.focus
|
||||
this.focusShow = this.focus
|
||||
})
|
||||
this.focused = this.focus;
|
||||
this.focusShow = this.focus;
|
||||
});
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
this.init();
|
||||
// TODO 处理头条vue3 computed 不监听 inject 更改的问题(formItem.errMsg)
|
||||
if (this.form && this.formItem) {
|
||||
this.$watch('formItem.errMsg', (newVal) => {
|
||||
this.localMsg = newVal
|
||||
})
|
||||
this.$watch('formItem.errMsg', newVal => {
|
||||
this.localMsg = newVal;
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$nextTick(() => {
|
||||
this.focused = this.focus
|
||||
this.focusShow = this.focus
|
||||
})
|
||||
this.focused = this.focus;
|
||||
this.focusShow = this.focus;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
@@ -300,11 +347,11 @@
|
||||
*/
|
||||
init() {
|
||||
if (this.value || this.value === 0) {
|
||||
this.val = this.value
|
||||
} else if (this.modelValue || this.modelValue === 0) {
|
||||
this.val = this.modelValue
|
||||
this.val = this.value;
|
||||
} else if (this.modelValue || this.modelValue === 0 || this.modelValue === '') {
|
||||
this.val = this.modelValue;
|
||||
} else {
|
||||
this.val = null
|
||||
this.val = null;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -313,15 +360,15 @@
|
||||
* @param {Object} type
|
||||
*/
|
||||
onClickIcon(type) {
|
||||
this.$emit('iconClick', type)
|
||||
this.$emit('iconClick', type);
|
||||
},
|
||||
|
||||
/**
|
||||
* 显示隐藏内容,密码框时生效
|
||||
*/
|
||||
onEyes() {
|
||||
this.showPassword = !this.showPassword
|
||||
this.$emit('eyes', this.showPassword)
|
||||
this.showPassword = !this.showPassword;
|
||||
this.$emit('eyes', this.showPassword);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -332,19 +379,19 @@
|
||||
let value = event.detail.value;
|
||||
// 判断是否去除空格
|
||||
if (this.trim) {
|
||||
if (typeof(this.trim) === 'boolean' && this.trim) {
|
||||
value = this.trimStr(value)
|
||||
if (typeof this.trim === 'boolean' && this.trim) {
|
||||
value = this.trimStr(value);
|
||||
}
|
||||
if (typeof(this.trim) === 'string') {
|
||||
value = this.trimStr(value, this.trim)
|
||||
if (typeof this.trim === 'string') {
|
||||
value = this.trimStr(value, this.trim);
|
||||
}
|
||||
};
|
||||
if (this.errMsg) this.errMsg = ''
|
||||
this.val = value
|
||||
}
|
||||
if (this.errMsg) this.errMsg = '';
|
||||
this.val = value;
|
||||
// TODO 兼容 vue2
|
||||
this.$emit('input', value);
|
||||
// TODO 兼容 vue3
|
||||
this.$emit('update:modelValue', value)
|
||||
this.$emit('update:modelValue', value);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -354,13 +401,13 @@
|
||||
*/
|
||||
onFocus() {
|
||||
this.$nextTick(() => {
|
||||
this.focused = true
|
||||
})
|
||||
this.focused = true;
|
||||
});
|
||||
this.$emit('focus', null);
|
||||
},
|
||||
|
||||
_Focus(event) {
|
||||
this.focusShow = true
|
||||
this.focusShow = true;
|
||||
this.$emit('focus', event);
|
||||
},
|
||||
|
||||
@@ -370,24 +417,22 @@
|
||||
* @param {Object} event
|
||||
*/
|
||||
onBlur() {
|
||||
this.focused = false
|
||||
this.focused = false;
|
||||
this.$emit('focus', null);
|
||||
},
|
||||
_Blur(event) {
|
||||
let value = event.detail.value;
|
||||
this.focusShow = false
|
||||
this.focusShow = false;
|
||||
this.$emit('blur', event);
|
||||
// 根据类型返回值,在event中获取的值理论上讲都是string
|
||||
if (this.isEnter === false) {
|
||||
this.$emit('change', this.val)
|
||||
this.$emit('change', this.val);
|
||||
}
|
||||
// 失去焦点时参与表单校验
|
||||
if (this.form && this.formItem) {
|
||||
const {
|
||||
validateTrigger
|
||||
} = this.form
|
||||
const { validateTrigger } = this.form;
|
||||
if (validateTrigger === 'blur') {
|
||||
this.formItem.onFieldChange()
|
||||
this.formItem.onFieldChange();
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -399,10 +444,10 @@
|
||||
onConfirm(e) {
|
||||
this.$emit('confirm', this.val);
|
||||
this.isEnter = true;
|
||||
this.$emit('change', this.val)
|
||||
this.$emit('change', this.val);
|
||||
this.$nextTick(() => {
|
||||
this.isEnter = false
|
||||
})
|
||||
this.isEnter = false;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -415,9 +460,18 @@
|
||||
this.$emit('input', '');
|
||||
// TODO 兼容 vue2
|
||||
// TODO 兼容 vue3
|
||||
this.$emit('update:modelValue', '')
|
||||
this.$emit('update:modelValue', '');
|
||||
// 点击叉号触发
|
||||
this.$emit('clear')
|
||||
this.$emit('clear');
|
||||
},
|
||||
|
||||
/**
|
||||
* 键盘高度发生变化的时候触发此事件
|
||||
* 兼容性:微信小程序2.7.0+、App 3.1.0+
|
||||
* @param {Object} event
|
||||
*/
|
||||
onkeyboardheightchange(event) {
|
||||
this.$emit("keyboardheightchange",event);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -431,9 +485,9 @@
|
||||
} else if (pos === 'right') {
|
||||
return str.trimRight();
|
||||
} else if (pos === 'start') {
|
||||
return str.trimStart()
|
||||
return str.trimStart();
|
||||
} else if (pos === 'end') {
|
||||
return str.trimEnd()
|
||||
return str.trimEnd();
|
||||
} else if (pos === 'all') {
|
||||
return str.replace(/\s+/g, '');
|
||||
} else if (pos === 'none') {
|
||||
@@ -447,7 +501,7 @@
|
||||
|
||||
<style lang="scss">
|
||||
$uni-error: #e43d33;
|
||||
$uni-border-1: #DCDFE6 !default;
|
||||
$uni-border-1: #dcdfe6 !default;
|
||||
|
||||
.uni-easyinput {
|
||||
/* #ifndef APP-NVUE */
|
||||
@@ -491,7 +545,7 @@
|
||||
|
||||
.uni-easyinput__placeholder-class {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
font-size: 12px;
|
||||
// font-weight: 200;
|
||||
}
|
||||
|
||||
@@ -568,11 +622,9 @@
|
||||
|
||||
.uni-easyinput__placeholder-class {
|
||||
color: mix(#fff, $uni-error, 50%);
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.uni-easyinput--border {
|
||||
margin-bottom: 0;
|
||||
padding: 10px 15px;
|
||||
@@ -594,12 +646,12 @@
|
||||
}
|
||||
|
||||
.is-disabled {
|
||||
background-color: #F7F6F6;
|
||||
color: #D5D5D5;
|
||||
background-color: #f7f6f6;
|
||||
color: #d5d5d5;
|
||||
|
||||
.uni-easyinput__placeholder-class {
|
||||
color: #D5D5D5;
|
||||
font-size: 14px;
|
||||
color: #d5d5d5;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-easyinput",
|
||||
"displayName": "uni-easyinput 增强输入框",
|
||||
"version": "1.1.3",
|
||||
"version": "1.1.9",
|
||||
"description": "Easyinput 组件是对原生input组件的增强",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
## 1.2.5(2023-03-29)
|
||||
- 新增 pattern.icon 属性,可自定义图标
|
||||
## 1.2.4(2022-09-07)
|
||||
小程序端由于 style 使用了对象导致报错,[详情](https://ask.dcloud.net.cn/question/152790?item_id=211778&rf=false)
|
||||
## 1.2.3(2022-09-05)
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
'uni-fab__circle--rightTop': rightTop,
|
||||
'uni-fab__content--other-platform': !isAndroidNvue
|
||||
}" class="uni-fab__circle uni-fab__plus" :style="{ 'background-color': styles.buttonColor, 'bottom': nvueBottom }" @click="_onClick">
|
||||
<uni-icons class="fab-circle-icon" type="plusempty" :color="styles.iconColor" size="32"
|
||||
<uni-icons class="fab-circle-icon" :type="styles.icon" :color="styles.iconColor" size="32"
|
||||
:class="{'uni-fab__plus--active': isShow && content.length > 0}"></uni-icons>
|
||||
<!-- <view class="fab-circle-v" :class="{'uni-fab__plus--active': isShow && content.length > 0}"></view>
|
||||
<view class="fab-circle-h" :class="{'uni-fab__plus--active': isShow && content.length > 0}"></view> -->
|
||||
@@ -115,7 +115,8 @@
|
||||
selectedColor: '#007AFF',
|
||||
backgroundColor: '#fff',
|
||||
buttonColor: '#007AFF',
|
||||
iconColor: '#fff'
|
||||
iconColor: '#fff',
|
||||
icon: 'plusempty'
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -206,6 +207,9 @@
|
||||
* 按钮点击事件
|
||||
*/
|
||||
_onItemClick(index, item) {
|
||||
if (!this.isShow) {
|
||||
return
|
||||
}
|
||||
this.$emit('trigger', {
|
||||
index,
|
||||
item
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-fab",
|
||||
"displayName": "uni-fab 悬浮按钮",
|
||||
"version": "1.2.4",
|
||||
"version": "1.2.5",
|
||||
"description": "悬浮按钮 fab button ,点击可展开一个图标按钮菜单。",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
## 1.0.3(2022-12-21)
|
||||
## 1.0.4(2023-03-29)
|
||||
- 修复 手动上传删除一个文件后不能再上传的bug
|
||||
## 1.0.3(2022-12-19)
|
||||
- 新增 sourceType 属性, 可以自定义图片和视频选择的来源
|
||||
## 1.0.2(2022-07-04)
|
||||
- 修复 在uni-forms下样式不生效的bug
|
||||
|
||||
@@ -583,7 +583,11 @@
|
||||
path: v.path,
|
||||
size: v.size,
|
||||
fileID:v.fileID,
|
||||
url: v.url
|
||||
url: v.url,
|
||||
// 修改删除一个文件后不能再上传的bug, #694
|
||||
uuid: v.uuid,
|
||||
status: v.status,
|
||||
cloudPath: v.cloudPath
|
||||
})
|
||||
})
|
||||
return newFilesData
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-file-picker",
|
||||
"displayName": "uni-file-picker 文件选择上传",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
@@ -17,10 +17,6 @@
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
@@ -37,7 +33,8 @@
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": ["uni-scss"],
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
## 1.4.9(2023-02-10)
|
||||
- 修复 required 参数无法动态绑定
|
||||
## 1.4.8(2022-08-23)
|
||||
- 优化 根据 rules 自动添加 required 的问题
|
||||
## 1.4.7(2022-08-22)
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<view class="uni-forms-item"
|
||||
:class="['is-direction-' + localLabelPos ,border?'uni-forms-item--border':'' ,border && isFirstBorder?'is-first-border':'']">
|
||||
<slot name="label">
|
||||
<view class="uni-forms-item__label" :class="{'no-label':!label && !isRequired}"
|
||||
<view class="uni-forms-item__label" :class="{'no-label':!label && !required}"
|
||||
:style="{width:localLabelWidth,justifyContent: localLabelAlign}">
|
||||
<text v-if="isRequired" class="is-required">*</text>
|
||||
<text v-if="required" class="is-required">*</text>
|
||||
<text>{{label}}</text>
|
||||
</view>
|
||||
</slot>
|
||||
@@ -126,7 +126,6 @@
|
||||
data() {
|
||||
return {
|
||||
errMsg: '',
|
||||
isRequired: false,
|
||||
userRules: null,
|
||||
localLabelAlign: 'left',
|
||||
localLabelWidth: '65px',
|
||||
@@ -315,7 +314,6 @@
|
||||
this.localLabelWidth = this._labelWidthUnit(labelWidth)
|
||||
// 标签位置
|
||||
this.localLabelPos = this._labelPosition()
|
||||
this.isRequired = this.required
|
||||
// 将需要校验的子组件加入form 队列
|
||||
this.form && type && childrens.push(this)
|
||||
|
||||
@@ -351,8 +349,6 @@
|
||||
this.validator = validator
|
||||
// 默认值赋予
|
||||
this.itemSetValue(_getDataValue(this.name, localData))
|
||||
this.isRequired = this._isRequired()
|
||||
|
||||
},
|
||||
unInit() {
|
||||
if (this.form) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-forms",
|
||||
"displayName": "uni-forms 表单",
|
||||
"version": "1.4.8",
|
||||
"version": "1.4.9",
|
||||
"description": "由输入框、选择器、单选框、多选框等控件组成,用以收集、校验、提交数据",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
## 2.0.10(2024-06-07)
|
||||
- 优化 uni-app x 中,size 属性的类型
|
||||
## 2.0.9(2024-01-12)
|
||||
fix: 修复图标大小默认值错误的问题
|
||||
## 2.0.8(2023-12-14)
|
||||
- 修复 项目未使用 ts 情况下,打包报错的bug
|
||||
## 2.0.7(2023-12-14)
|
||||
- 修复 size 属性为 string 时,不加单位导致尺寸异常的bug
|
||||
## 2.0.6(2023-12-11)
|
||||
- 优化 兼容老版本icon类型,如 top ,bottom 等
|
||||
## 2.0.5(2023-12-11)
|
||||
- 优化 兼容老版本icon类型,如 top ,bottom 等
|
||||
## 2.0.4(2023-12-06)
|
||||
- 优化 uni-app x 下示例项目图标排序
|
||||
## 2.0.3(2023-12-06)
|
||||
- 修复 nvue下引入组件报错的bug
|
||||
## 2.0.2(2023-12-05)
|
||||
-优化 size 属性支持单位
|
||||
## 2.0.1(2023-12-05)
|
||||
- 新增 uni-app x 支持定义图标
|
||||
## 1.3.5(2022-01-24)
|
||||
- 优化 size 属性可以传入不带单位的字符串数值
|
||||
## 1.3.4(2022-01-24)
|
||||
|
||||
91
uni_modules/uni-icons/components/uni-icons/uni-icons.uvue
Normal file
91
uni_modules/uni-icons/components/uni-icons/uni-icons.uvue
Normal file
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<text class="uni-icons" :style="styleObj">
|
||||
<slot>{{unicode}}</slot>
|
||||
</text>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { fontData, IconsDataItem } from './uniicons_file'
|
||||
|
||||
/**
|
||||
* Icons 图标
|
||||
* @description 用于展示 icon 图标
|
||||
* @tutorial https://ext.dcloud.net.cn/plugin?id=28
|
||||
* @property {Number,String} size 图标大小
|
||||
* @property {String} type 图标图案,参考示例
|
||||
* @property {String} color 图标颜色
|
||||
* @property {String} customPrefix 自定义图标
|
||||
* @event {Function} click 点击 Icon 触发事件
|
||||
*/
|
||||
export default {
|
||||
name: "uni-icons",
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#333333'
|
||||
},
|
||||
size: {
|
||||
type: [Number, String],
|
||||
default: 16
|
||||
},
|
||||
fontFamily: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
computed: {
|
||||
unicode() : string {
|
||||
let codes = fontData.find((item : IconsDataItem) : boolean => { return item.font_class == this.type })
|
||||
if (codes !== null) {
|
||||
return codes.unicode
|
||||
}
|
||||
return ''
|
||||
},
|
||||
iconSize() : string {
|
||||
const size = this.size
|
||||
if (typeof size == 'string') {
|
||||
const reg = /^[0-9]*$/g
|
||||
return reg.test(size as string) ? '' + size + 'px' : '' + size;
|
||||
// return '' + this.size
|
||||
}
|
||||
return this.getFontSize(size as number)
|
||||
},
|
||||
styleObj() : UTSJSONObject {
|
||||
if (this.fontFamily !== '') {
|
||||
return { color: this.color, fontSize: this.iconSize, fontFamily: this.fontFamily }
|
||||
}
|
||||
return { color: this.color, fontSize: this.iconSize }
|
||||
}
|
||||
},
|
||||
created() { },
|
||||
methods: {
|
||||
/**
|
||||
* 字体大小
|
||||
*/
|
||||
getFontSize(size : number) : string {
|
||||
return size + 'px';
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@font-face {
|
||||
font-family: UniIconsFontFamily;
|
||||
src: url('./uniicons.ttf');
|
||||
}
|
||||
|
||||
.uni-icons {
|
||||
font-family: UniIconsFontFamily;
|
||||
font-size: 18px;
|
||||
font-style: normal;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
@@ -1,18 +1,22 @@
|
||||
<template>
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" @click="_onClick">{{unicode}}</text>
|
||||
<text :style="styleObj" class="uni-icons" @click="_onClick">{{unicode}}</text>
|
||||
<!-- #endif -->
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<text :style="{ color: color, 'font-size': iconSize }" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick"></text>
|
||||
<text :style="styleObj" class="uni-icons" :class="['uniui-'+type,customPrefix,customPrefix?type:'']" @click="_onClick">
|
||||
<slot></slot>
|
||||
</text>
|
||||
<!-- #endif -->
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import icons from './icons.js';
|
||||
import { fontData } from './uniicons_file_vue.js';
|
||||
|
||||
const getVal = (val) => {
|
||||
const reg = /^[0-9]*$/g
|
||||
return (typeof val === 'number' || reg.test(val) )? val + 'px' : val;
|
||||
return (typeof val === 'number' || reg.test(val)) ? val + 'px' : val;
|
||||
}
|
||||
|
||||
// #ifdef APP-NVUE
|
||||
var domModule = weex.requireModule('dom');
|
||||
import iconUrl from './uniicons.ttf'
|
||||
@@ -51,23 +55,33 @@
|
||||
customPrefix: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
fontFamily: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
icons: icons.glyphs
|
||||
icons: fontData
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
unicode() {
|
||||
let code = this.icons.find(v => v.font_class === this.type)
|
||||
if (code) {
|
||||
return unescape(`%u${code.unicode}`)
|
||||
return code.unicode
|
||||
}
|
||||
return ''
|
||||
},
|
||||
iconSize() {
|
||||
return getVal(this.size)
|
||||
},
|
||||
styleObj() {
|
||||
if (this.fontFamily !== '') {
|
||||
return `color: ${this.color}; font-size: ${this.iconSize}; font-family: ${this.fontFamily};`
|
||||
}
|
||||
return `color: ${this.color}; font-size: ${this.iconSize};`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -81,9 +95,10 @@
|
||||
<style lang="scss">
|
||||
/* #ifndef APP-NVUE */
|
||||
@import './uniicons.css';
|
||||
|
||||
@font-face {
|
||||
font-family: uniicons;
|
||||
src: url('./uniicons.ttf') format('truetype');
|
||||
src: url('./uniicons.ttf');
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
@@ -92,5 +107,4 @@
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
|
||||
.uniui-cart-filled:before {
|
||||
content: "\e6d0";
|
||||
}
|
||||
|
||||
.uniui-gift-filled:before {
|
||||
content: "\e6c4";
|
||||
}
|
||||
|
||||
.uniui-color:before {
|
||||
content: "\e6cf";
|
||||
}
|
||||
@@ -58,10 +67,6 @@
|
||||
content: "\e6c3";
|
||||
}
|
||||
|
||||
.uniui-gift-filled:before {
|
||||
content: "\e6c4";
|
||||
}
|
||||
|
||||
.uniui-fire-filled:before {
|
||||
content: "\e6c5";
|
||||
}
|
||||
@@ -82,6 +87,18 @@
|
||||
content: "\e698";
|
||||
}
|
||||
|
||||
.uniui-arrowthinleft:before {
|
||||
content: "\e6d2";
|
||||
}
|
||||
|
||||
.uniui-arrowthinup:before {
|
||||
content: "\e6d3";
|
||||
}
|
||||
|
||||
.uniui-arrowthindown:before {
|
||||
content: "\e6d4";
|
||||
}
|
||||
|
||||
.uniui-back:before {
|
||||
content: "\e6b9";
|
||||
}
|
||||
@@ -94,55 +111,43 @@
|
||||
content: "\e6bb";
|
||||
}
|
||||
|
||||
.uniui-arrowthinright:before {
|
||||
content: "\e6bb";
|
||||
}
|
||||
|
||||
.uniui-arrow-left:before {
|
||||
content: "\e6bc";
|
||||
}
|
||||
|
||||
.uniui-arrowthinleft:before {
|
||||
content: "\e6bc";
|
||||
}
|
||||
|
||||
.uniui-arrow-up:before {
|
||||
content: "\e6bd";
|
||||
}
|
||||
|
||||
.uniui-arrowthinup:before {
|
||||
content: "\e6bd";
|
||||
}
|
||||
|
||||
.uniui-arrow-down:before {
|
||||
content: "\e6be";
|
||||
}
|
||||
|
||||
.uniui-arrowthindown:before {
|
||||
content: "\e6be";
|
||||
.uniui-arrowthinright:before {
|
||||
content: "\e6d1";
|
||||
}
|
||||
|
||||
.uniui-down:before {
|
||||
content: "\e6b8";
|
||||
}
|
||||
|
||||
.uniui-bottom:before {
|
||||
content: "\e6b8";
|
||||
}
|
||||
|
||||
.uniui-arrowdown:before {
|
||||
content: "\e6b8";
|
||||
.uniui-arrowright:before {
|
||||
content: "\e6d5";
|
||||
}
|
||||
|
||||
.uniui-right:before {
|
||||
content: "\e6b5";
|
||||
}
|
||||
|
||||
.uniui-arrowright:before {
|
||||
content: "\e6b5";
|
||||
}
|
||||
|
||||
.uniui-top:before {
|
||||
.uniui-up:before {
|
||||
content: "\e6b6";
|
||||
}
|
||||
|
||||
.uniui-arrowup:before {
|
||||
.uniui-top:before {
|
||||
content: "\e6b6";
|
||||
}
|
||||
|
||||
@@ -150,8 +155,8 @@
|
||||
content: "\e6b7";
|
||||
}
|
||||
|
||||
.uniui-arrowleft:before {
|
||||
content: "\e6b7";
|
||||
.uniui-arrowup:before {
|
||||
content: "\e6d6";
|
||||
}
|
||||
|
||||
.uniui-eye:before {
|
||||
@@ -638,10 +643,6 @@
|
||||
content: "\e627";
|
||||
}
|
||||
|
||||
.uniui-cart-filled:before {
|
||||
content: "\e629";
|
||||
}
|
||||
|
||||
.uniui-checkbox:before {
|
||||
content: "\e62b";
|
||||
}
|
||||
|
||||
Binary file not shown.
664
uni_modules/uni-icons/components/uni-icons/uniicons_file.ts
Normal file
664
uni_modules/uni-icons/components/uni-icons/uniicons_file.ts
Normal file
@@ -0,0 +1,664 @@
|
||||
|
||||
export type IconsData = {
|
||||
id : string
|
||||
name : string
|
||||
font_family : string
|
||||
css_prefix_text : string
|
||||
description : string
|
||||
glyphs : Array<IconsDataItem>
|
||||
}
|
||||
|
||||
export type IconsDataItem = {
|
||||
font_class : string
|
||||
unicode : string
|
||||
}
|
||||
|
||||
|
||||
export const fontData = [
|
||||
{
|
||||
"font_class": "arrow-down",
|
||||
"unicode": "\ue6be"
|
||||
},
|
||||
{
|
||||
"font_class": "arrow-left",
|
||||
"unicode": "\ue6bc"
|
||||
},
|
||||
{
|
||||
"font_class": "arrow-right",
|
||||
"unicode": "\ue6bb"
|
||||
},
|
||||
{
|
||||
"font_class": "arrow-up",
|
||||
"unicode": "\ue6bd"
|
||||
},
|
||||
{
|
||||
"font_class": "auth",
|
||||
"unicode": "\ue6ab"
|
||||
},
|
||||
{
|
||||
"font_class": "auth-filled",
|
||||
"unicode": "\ue6cc"
|
||||
},
|
||||
{
|
||||
"font_class": "back",
|
||||
"unicode": "\ue6b9"
|
||||
},
|
||||
{
|
||||
"font_class": "bars",
|
||||
"unicode": "\ue627"
|
||||
},
|
||||
{
|
||||
"font_class": "calendar",
|
||||
"unicode": "\ue6a0"
|
||||
},
|
||||
{
|
||||
"font_class": "calendar-filled",
|
||||
"unicode": "\ue6c0"
|
||||
},
|
||||
{
|
||||
"font_class": "camera",
|
||||
"unicode": "\ue65a"
|
||||
},
|
||||
{
|
||||
"font_class": "camera-filled",
|
||||
"unicode": "\ue658"
|
||||
},
|
||||
{
|
||||
"font_class": "cart",
|
||||
"unicode": "\ue631"
|
||||
},
|
||||
{
|
||||
"font_class": "cart-filled",
|
||||
"unicode": "\ue6d0"
|
||||
},
|
||||
{
|
||||
"font_class": "chat",
|
||||
"unicode": "\ue65d"
|
||||
},
|
||||
{
|
||||
"font_class": "chat-filled",
|
||||
"unicode": "\ue659"
|
||||
},
|
||||
{
|
||||
"font_class": "chatboxes",
|
||||
"unicode": "\ue696"
|
||||
},
|
||||
{
|
||||
"font_class": "chatboxes-filled",
|
||||
"unicode": "\ue692"
|
||||
},
|
||||
{
|
||||
"font_class": "chatbubble",
|
||||
"unicode": "\ue697"
|
||||
},
|
||||
{
|
||||
"font_class": "chatbubble-filled",
|
||||
"unicode": "\ue694"
|
||||
},
|
||||
{
|
||||
"font_class": "checkbox",
|
||||
"unicode": "\ue62b"
|
||||
},
|
||||
{
|
||||
"font_class": "checkbox-filled",
|
||||
"unicode": "\ue62c"
|
||||
},
|
||||
{
|
||||
"font_class": "checkmarkempty",
|
||||
"unicode": "\ue65c"
|
||||
},
|
||||
{
|
||||
"font_class": "circle",
|
||||
"unicode": "\ue65b"
|
||||
},
|
||||
{
|
||||
"font_class": "circle-filled",
|
||||
"unicode": "\ue65e"
|
||||
},
|
||||
{
|
||||
"font_class": "clear",
|
||||
"unicode": "\ue66d"
|
||||
},
|
||||
{
|
||||
"font_class": "close",
|
||||
"unicode": "\ue673"
|
||||
},
|
||||
{
|
||||
"font_class": "closeempty",
|
||||
"unicode": "\ue66c"
|
||||
},
|
||||
{
|
||||
"font_class": "cloud-download",
|
||||
"unicode": "\ue647"
|
||||
},
|
||||
{
|
||||
"font_class": "cloud-download-filled",
|
||||
"unicode": "\ue646"
|
||||
},
|
||||
{
|
||||
"font_class": "cloud-upload",
|
||||
"unicode": "\ue645"
|
||||
},
|
||||
{
|
||||
"font_class": "cloud-upload-filled",
|
||||
"unicode": "\ue648"
|
||||
},
|
||||
{
|
||||
"font_class": "color",
|
||||
"unicode": "\ue6cf"
|
||||
},
|
||||
{
|
||||
"font_class": "color-filled",
|
||||
"unicode": "\ue6c9"
|
||||
},
|
||||
{
|
||||
"font_class": "compose",
|
||||
"unicode": "\ue67f"
|
||||
},
|
||||
{
|
||||
"font_class": "contact",
|
||||
"unicode": "\ue693"
|
||||
},
|
||||
{
|
||||
"font_class": "contact-filled",
|
||||
"unicode": "\ue695"
|
||||
},
|
||||
{
|
||||
"font_class": "down",
|
||||
"unicode": "\ue6b8"
|
||||
},
|
||||
{
|
||||
"font_class": "bottom",
|
||||
"unicode": "\ue6b8"
|
||||
},
|
||||
{
|
||||
"font_class": "download",
|
||||
"unicode": "\ue68d"
|
||||
},
|
||||
{
|
||||
"font_class": "download-filled",
|
||||
"unicode": "\ue681"
|
||||
},
|
||||
{
|
||||
"font_class": "email",
|
||||
"unicode": "\ue69e"
|
||||
},
|
||||
{
|
||||
"font_class": "email-filled",
|
||||
"unicode": "\ue69a"
|
||||
},
|
||||
{
|
||||
"font_class": "eye",
|
||||
"unicode": "\ue651"
|
||||
},
|
||||
{
|
||||
"font_class": "eye-filled",
|
||||
"unicode": "\ue66a"
|
||||
},
|
||||
{
|
||||
"font_class": "eye-slash",
|
||||
"unicode": "\ue6b3"
|
||||
},
|
||||
{
|
||||
"font_class": "eye-slash-filled",
|
||||
"unicode": "\ue6b4"
|
||||
},
|
||||
{
|
||||
"font_class": "fire",
|
||||
"unicode": "\ue6a1"
|
||||
},
|
||||
{
|
||||
"font_class": "fire-filled",
|
||||
"unicode": "\ue6c5"
|
||||
},
|
||||
{
|
||||
"font_class": "flag",
|
||||
"unicode": "\ue65f"
|
||||
},
|
||||
{
|
||||
"font_class": "flag-filled",
|
||||
"unicode": "\ue660"
|
||||
},
|
||||
{
|
||||
"font_class": "folder-add",
|
||||
"unicode": "\ue6a9"
|
||||
},
|
||||
{
|
||||
"font_class": "folder-add-filled",
|
||||
"unicode": "\ue6c8"
|
||||
},
|
||||
{
|
||||
"font_class": "font",
|
||||
"unicode": "\ue6a3"
|
||||
},
|
||||
{
|
||||
"font_class": "forward",
|
||||
"unicode": "\ue6ba"
|
||||
},
|
||||
{
|
||||
"font_class": "gear",
|
||||
"unicode": "\ue664"
|
||||
},
|
||||
{
|
||||
"font_class": "gear-filled",
|
||||
"unicode": "\ue661"
|
||||
},
|
||||
{
|
||||
"font_class": "gift",
|
||||
"unicode": "\ue6a4"
|
||||
},
|
||||
{
|
||||
"font_class": "gift-filled",
|
||||
"unicode": "\ue6c4"
|
||||
},
|
||||
{
|
||||
"font_class": "hand-down",
|
||||
"unicode": "\ue63d"
|
||||
},
|
||||
{
|
||||
"font_class": "hand-down-filled",
|
||||
"unicode": "\ue63c"
|
||||
},
|
||||
{
|
||||
"font_class": "hand-up",
|
||||
"unicode": "\ue63f"
|
||||
},
|
||||
{
|
||||
"font_class": "hand-up-filled",
|
||||
"unicode": "\ue63e"
|
||||
},
|
||||
{
|
||||
"font_class": "headphones",
|
||||
"unicode": "\ue630"
|
||||
},
|
||||
{
|
||||
"font_class": "heart",
|
||||
"unicode": "\ue639"
|
||||
},
|
||||
{
|
||||
"font_class": "heart-filled",
|
||||
"unicode": "\ue641"
|
||||
},
|
||||
{
|
||||
"font_class": "help",
|
||||
"unicode": "\ue679"
|
||||
},
|
||||
{
|
||||
"font_class": "help-filled",
|
||||
"unicode": "\ue674"
|
||||
},
|
||||
{
|
||||
"font_class": "home",
|
||||
"unicode": "\ue662"
|
||||
},
|
||||
{
|
||||
"font_class": "home-filled",
|
||||
"unicode": "\ue663"
|
||||
},
|
||||
{
|
||||
"font_class": "image",
|
||||
"unicode": "\ue670"
|
||||
},
|
||||
{
|
||||
"font_class": "image-filled",
|
||||
"unicode": "\ue678"
|
||||
},
|
||||
{
|
||||
"font_class": "images",
|
||||
"unicode": "\ue650"
|
||||
},
|
||||
{
|
||||
"font_class": "images-filled",
|
||||
"unicode": "\ue64b"
|
||||
},
|
||||
{
|
||||
"font_class": "info",
|
||||
"unicode": "\ue669"
|
||||
},
|
||||
{
|
||||
"font_class": "info-filled",
|
||||
"unicode": "\ue649"
|
||||
},
|
||||
{
|
||||
"font_class": "left",
|
||||
"unicode": "\ue6b7"
|
||||
},
|
||||
{
|
||||
"font_class": "link",
|
||||
"unicode": "\ue6a5"
|
||||
},
|
||||
{
|
||||
"font_class": "list",
|
||||
"unicode": "\ue644"
|
||||
},
|
||||
{
|
||||
"font_class": "location",
|
||||
"unicode": "\ue6ae"
|
||||
},
|
||||
{
|
||||
"font_class": "location-filled",
|
||||
"unicode": "\ue6af"
|
||||
},
|
||||
{
|
||||
"font_class": "locked",
|
||||
"unicode": "\ue66b"
|
||||
},
|
||||
{
|
||||
"font_class": "locked-filled",
|
||||
"unicode": "\ue668"
|
||||
},
|
||||
{
|
||||
"font_class": "loop",
|
||||
"unicode": "\ue633"
|
||||
},
|
||||
{
|
||||
"font_class": "mail-open",
|
||||
"unicode": "\ue643"
|
||||
},
|
||||
{
|
||||
"font_class": "mail-open-filled",
|
||||
"unicode": "\ue63a"
|
||||
},
|
||||
{
|
||||
"font_class": "map",
|
||||
"unicode": "\ue667"
|
||||
},
|
||||
{
|
||||
"font_class": "map-filled",
|
||||
"unicode": "\ue666"
|
||||
},
|
||||
{
|
||||
"font_class": "map-pin",
|
||||
"unicode": "\ue6ad"
|
||||
},
|
||||
{
|
||||
"font_class": "map-pin-ellipse",
|
||||
"unicode": "\ue6ac"
|
||||
},
|
||||
{
|
||||
"font_class": "medal",
|
||||
"unicode": "\ue6a2"
|
||||
},
|
||||
{
|
||||
"font_class": "medal-filled",
|
||||
"unicode": "\ue6c3"
|
||||
},
|
||||
{
|
||||
"font_class": "mic",
|
||||
"unicode": "\ue671"
|
||||
},
|
||||
{
|
||||
"font_class": "mic-filled",
|
||||
"unicode": "\ue677"
|
||||
},
|
||||
{
|
||||
"font_class": "micoff",
|
||||
"unicode": "\ue67e"
|
||||
},
|
||||
{
|
||||
"font_class": "micoff-filled",
|
||||
"unicode": "\ue6b0"
|
||||
},
|
||||
{
|
||||
"font_class": "minus",
|
||||
"unicode": "\ue66f"
|
||||
},
|
||||
{
|
||||
"font_class": "minus-filled",
|
||||
"unicode": "\ue67d"
|
||||
},
|
||||
{
|
||||
"font_class": "more",
|
||||
"unicode": "\ue64d"
|
||||
},
|
||||
{
|
||||
"font_class": "more-filled",
|
||||
"unicode": "\ue64e"
|
||||
},
|
||||
{
|
||||
"font_class": "navigate",
|
||||
"unicode": "\ue66e"
|
||||
},
|
||||
{
|
||||
"font_class": "navigate-filled",
|
||||
"unicode": "\ue67a"
|
||||
},
|
||||
{
|
||||
"font_class": "notification",
|
||||
"unicode": "\ue6a6"
|
||||
},
|
||||
{
|
||||
"font_class": "notification-filled",
|
||||
"unicode": "\ue6c1"
|
||||
},
|
||||
{
|
||||
"font_class": "paperclip",
|
||||
"unicode": "\ue652"
|
||||
},
|
||||
{
|
||||
"font_class": "paperplane",
|
||||
"unicode": "\ue672"
|
||||
},
|
||||
{
|
||||
"font_class": "paperplane-filled",
|
||||
"unicode": "\ue675"
|
||||
},
|
||||
{
|
||||
"font_class": "person",
|
||||
"unicode": "\ue699"
|
||||
},
|
||||
{
|
||||
"font_class": "person-filled",
|
||||
"unicode": "\ue69d"
|
||||
},
|
||||
{
|
||||
"font_class": "personadd",
|
||||
"unicode": "\ue69f"
|
||||
},
|
||||
{
|
||||
"font_class": "personadd-filled",
|
||||
"unicode": "\ue698"
|
||||
},
|
||||
{
|
||||
"font_class": "personadd-filled-copy",
|
||||
"unicode": "\ue6d1"
|
||||
},
|
||||
{
|
||||
"font_class": "phone",
|
||||
"unicode": "\ue69c"
|
||||
},
|
||||
{
|
||||
"font_class": "phone-filled",
|
||||
"unicode": "\ue69b"
|
||||
},
|
||||
{
|
||||
"font_class": "plus",
|
||||
"unicode": "\ue676"
|
||||
},
|
||||
{
|
||||
"font_class": "plus-filled",
|
||||
"unicode": "\ue6c7"
|
||||
},
|
||||
{
|
||||
"font_class": "plusempty",
|
||||
"unicode": "\ue67b"
|
||||
},
|
||||
{
|
||||
"font_class": "pulldown",
|
||||
"unicode": "\ue632"
|
||||
},
|
||||
{
|
||||
"font_class": "pyq",
|
||||
"unicode": "\ue682"
|
||||
},
|
||||
{
|
||||
"font_class": "qq",
|
||||
"unicode": "\ue680"
|
||||
},
|
||||
{
|
||||
"font_class": "redo",
|
||||
"unicode": "\ue64a"
|
||||
},
|
||||
{
|
||||
"font_class": "redo-filled",
|
||||
"unicode": "\ue655"
|
||||
},
|
||||
{
|
||||
"font_class": "refresh",
|
||||
"unicode": "\ue657"
|
||||
},
|
||||
{
|
||||
"font_class": "refresh-filled",
|
||||
"unicode": "\ue656"
|
||||
},
|
||||
{
|
||||
"font_class": "refreshempty",
|
||||
"unicode": "\ue6bf"
|
||||
},
|
||||
{
|
||||
"font_class": "reload",
|
||||
"unicode": "\ue6b2"
|
||||
},
|
||||
{
|
||||
"font_class": "right",
|
||||
"unicode": "\ue6b5"
|
||||
},
|
||||
{
|
||||
"font_class": "scan",
|
||||
"unicode": "\ue62a"
|
||||
},
|
||||
{
|
||||
"font_class": "search",
|
||||
"unicode": "\ue654"
|
||||
},
|
||||
{
|
||||
"font_class": "settings",
|
||||
"unicode": "\ue653"
|
||||
},
|
||||
{
|
||||
"font_class": "settings-filled",
|
||||
"unicode": "\ue6ce"
|
||||
},
|
||||
{
|
||||
"font_class": "shop",
|
||||
"unicode": "\ue62f"
|
||||
},
|
||||
{
|
||||
"font_class": "shop-filled",
|
||||
"unicode": "\ue6cd"
|
||||
},
|
||||
{
|
||||
"font_class": "smallcircle",
|
||||
"unicode": "\ue67c"
|
||||
},
|
||||
{
|
||||
"font_class": "smallcircle-filled",
|
||||
"unicode": "\ue665"
|
||||
},
|
||||
{
|
||||
"font_class": "sound",
|
||||
"unicode": "\ue684"
|
||||
},
|
||||
{
|
||||
"font_class": "sound-filled",
|
||||
"unicode": "\ue686"
|
||||
},
|
||||
{
|
||||
"font_class": "spinner-cycle",
|
||||
"unicode": "\ue68a"
|
||||
},
|
||||
{
|
||||
"font_class": "staff",
|
||||
"unicode": "\ue6a7"
|
||||
},
|
||||
{
|
||||
"font_class": "staff-filled",
|
||||
"unicode": "\ue6cb"
|
||||
},
|
||||
{
|
||||
"font_class": "star",
|
||||
"unicode": "\ue688"
|
||||
},
|
||||
{
|
||||
"font_class": "star-filled",
|
||||
"unicode": "\ue68f"
|
||||
},
|
||||
{
|
||||
"font_class": "starhalf",
|
||||
"unicode": "\ue683"
|
||||
},
|
||||
{
|
||||
"font_class": "trash",
|
||||
"unicode": "\ue687"
|
||||
},
|
||||
{
|
||||
"font_class": "trash-filled",
|
||||
"unicode": "\ue685"
|
||||
},
|
||||
{
|
||||
"font_class": "tune",
|
||||
"unicode": "\ue6aa"
|
||||
},
|
||||
{
|
||||
"font_class": "tune-filled",
|
||||
"unicode": "\ue6ca"
|
||||
},
|
||||
{
|
||||
"font_class": "undo",
|
||||
"unicode": "\ue64f"
|
||||
},
|
||||
{
|
||||
"font_class": "undo-filled",
|
||||
"unicode": "\ue64c"
|
||||
},
|
||||
{
|
||||
"font_class": "up",
|
||||
"unicode": "\ue6b6"
|
||||
},
|
||||
{
|
||||
"font_class": "top",
|
||||
"unicode": "\ue6b6"
|
||||
},
|
||||
{
|
||||
"font_class": "upload",
|
||||
"unicode": "\ue690"
|
||||
},
|
||||
{
|
||||
"font_class": "upload-filled",
|
||||
"unicode": "\ue68e"
|
||||
},
|
||||
{
|
||||
"font_class": "videocam",
|
||||
"unicode": "\ue68c"
|
||||
},
|
||||
{
|
||||
"font_class": "videocam-filled",
|
||||
"unicode": "\ue689"
|
||||
},
|
||||
{
|
||||
"font_class": "vip",
|
||||
"unicode": "\ue6a8"
|
||||
},
|
||||
{
|
||||
"font_class": "vip-filled",
|
||||
"unicode": "\ue6c6"
|
||||
},
|
||||
{
|
||||
"font_class": "wallet",
|
||||
"unicode": "\ue6b1"
|
||||
},
|
||||
{
|
||||
"font_class": "wallet-filled",
|
||||
"unicode": "\ue6c2"
|
||||
},
|
||||
{
|
||||
"font_class": "weibo",
|
||||
"unicode": "\ue68b"
|
||||
},
|
||||
{
|
||||
"font_class": "weixin",
|
||||
"unicode": "\ue691"
|
||||
}
|
||||
] as IconsDataItem[]
|
||||
|
||||
// export const fontData = JSON.parse<IconsDataItem>(fontDataJson)
|
||||
649
uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js
Normal file
649
uni_modules/uni-icons/components/uni-icons/uniicons_file_vue.js
Normal file
@@ -0,0 +1,649 @@
|
||||
|
||||
export const fontData = [
|
||||
{
|
||||
"font_class": "arrow-down",
|
||||
"unicode": "\ue6be"
|
||||
},
|
||||
{
|
||||
"font_class": "arrow-left",
|
||||
"unicode": "\ue6bc"
|
||||
},
|
||||
{
|
||||
"font_class": "arrow-right",
|
||||
"unicode": "\ue6bb"
|
||||
},
|
||||
{
|
||||
"font_class": "arrow-up",
|
||||
"unicode": "\ue6bd"
|
||||
},
|
||||
{
|
||||
"font_class": "auth",
|
||||
"unicode": "\ue6ab"
|
||||
},
|
||||
{
|
||||
"font_class": "auth-filled",
|
||||
"unicode": "\ue6cc"
|
||||
},
|
||||
{
|
||||
"font_class": "back",
|
||||
"unicode": "\ue6b9"
|
||||
},
|
||||
{
|
||||
"font_class": "bars",
|
||||
"unicode": "\ue627"
|
||||
},
|
||||
{
|
||||
"font_class": "calendar",
|
||||
"unicode": "\ue6a0"
|
||||
},
|
||||
{
|
||||
"font_class": "calendar-filled",
|
||||
"unicode": "\ue6c0"
|
||||
},
|
||||
{
|
||||
"font_class": "camera",
|
||||
"unicode": "\ue65a"
|
||||
},
|
||||
{
|
||||
"font_class": "camera-filled",
|
||||
"unicode": "\ue658"
|
||||
},
|
||||
{
|
||||
"font_class": "cart",
|
||||
"unicode": "\ue631"
|
||||
},
|
||||
{
|
||||
"font_class": "cart-filled",
|
||||
"unicode": "\ue6d0"
|
||||
},
|
||||
{
|
||||
"font_class": "chat",
|
||||
"unicode": "\ue65d"
|
||||
},
|
||||
{
|
||||
"font_class": "chat-filled",
|
||||
"unicode": "\ue659"
|
||||
},
|
||||
{
|
||||
"font_class": "chatboxes",
|
||||
"unicode": "\ue696"
|
||||
},
|
||||
{
|
||||
"font_class": "chatboxes-filled",
|
||||
"unicode": "\ue692"
|
||||
},
|
||||
{
|
||||
"font_class": "chatbubble",
|
||||
"unicode": "\ue697"
|
||||
},
|
||||
{
|
||||
"font_class": "chatbubble-filled",
|
||||
"unicode": "\ue694"
|
||||
},
|
||||
{
|
||||
"font_class": "checkbox",
|
||||
"unicode": "\ue62b"
|
||||
},
|
||||
{
|
||||
"font_class": "checkbox-filled",
|
||||
"unicode": "\ue62c"
|
||||
},
|
||||
{
|
||||
"font_class": "checkmarkempty",
|
||||
"unicode": "\ue65c"
|
||||
},
|
||||
{
|
||||
"font_class": "circle",
|
||||
"unicode": "\ue65b"
|
||||
},
|
||||
{
|
||||
"font_class": "circle-filled",
|
||||
"unicode": "\ue65e"
|
||||
},
|
||||
{
|
||||
"font_class": "clear",
|
||||
"unicode": "\ue66d"
|
||||
},
|
||||
{
|
||||
"font_class": "close",
|
||||
"unicode": "\ue673"
|
||||
},
|
||||
{
|
||||
"font_class": "closeempty",
|
||||
"unicode": "\ue66c"
|
||||
},
|
||||
{
|
||||
"font_class": "cloud-download",
|
||||
"unicode": "\ue647"
|
||||
},
|
||||
{
|
||||
"font_class": "cloud-download-filled",
|
||||
"unicode": "\ue646"
|
||||
},
|
||||
{
|
||||
"font_class": "cloud-upload",
|
||||
"unicode": "\ue645"
|
||||
},
|
||||
{
|
||||
"font_class": "cloud-upload-filled",
|
||||
"unicode": "\ue648"
|
||||
},
|
||||
{
|
||||
"font_class": "color",
|
||||
"unicode": "\ue6cf"
|
||||
},
|
||||
{
|
||||
"font_class": "color-filled",
|
||||
"unicode": "\ue6c9"
|
||||
},
|
||||
{
|
||||
"font_class": "compose",
|
||||
"unicode": "\ue67f"
|
||||
},
|
||||
{
|
||||
"font_class": "contact",
|
||||
"unicode": "\ue693"
|
||||
},
|
||||
{
|
||||
"font_class": "contact-filled",
|
||||
"unicode": "\ue695"
|
||||
},
|
||||
{
|
||||
"font_class": "down",
|
||||
"unicode": "\ue6b8"
|
||||
},
|
||||
{
|
||||
"font_class": "bottom",
|
||||
"unicode": "\ue6b8"
|
||||
},
|
||||
{
|
||||
"font_class": "download",
|
||||
"unicode": "\ue68d"
|
||||
},
|
||||
{
|
||||
"font_class": "download-filled",
|
||||
"unicode": "\ue681"
|
||||
},
|
||||
{
|
||||
"font_class": "email",
|
||||
"unicode": "\ue69e"
|
||||
},
|
||||
{
|
||||
"font_class": "email-filled",
|
||||
"unicode": "\ue69a"
|
||||
},
|
||||
{
|
||||
"font_class": "eye",
|
||||
"unicode": "\ue651"
|
||||
},
|
||||
{
|
||||
"font_class": "eye-filled",
|
||||
"unicode": "\ue66a"
|
||||
},
|
||||
{
|
||||
"font_class": "eye-slash",
|
||||
"unicode": "\ue6b3"
|
||||
},
|
||||
{
|
||||
"font_class": "eye-slash-filled",
|
||||
"unicode": "\ue6b4"
|
||||
},
|
||||
{
|
||||
"font_class": "fire",
|
||||
"unicode": "\ue6a1"
|
||||
},
|
||||
{
|
||||
"font_class": "fire-filled",
|
||||
"unicode": "\ue6c5"
|
||||
},
|
||||
{
|
||||
"font_class": "flag",
|
||||
"unicode": "\ue65f"
|
||||
},
|
||||
{
|
||||
"font_class": "flag-filled",
|
||||
"unicode": "\ue660"
|
||||
},
|
||||
{
|
||||
"font_class": "folder-add",
|
||||
"unicode": "\ue6a9"
|
||||
},
|
||||
{
|
||||
"font_class": "folder-add-filled",
|
||||
"unicode": "\ue6c8"
|
||||
},
|
||||
{
|
||||
"font_class": "font",
|
||||
"unicode": "\ue6a3"
|
||||
},
|
||||
{
|
||||
"font_class": "forward",
|
||||
"unicode": "\ue6ba"
|
||||
},
|
||||
{
|
||||
"font_class": "gear",
|
||||
"unicode": "\ue664"
|
||||
},
|
||||
{
|
||||
"font_class": "gear-filled",
|
||||
"unicode": "\ue661"
|
||||
},
|
||||
{
|
||||
"font_class": "gift",
|
||||
"unicode": "\ue6a4"
|
||||
},
|
||||
{
|
||||
"font_class": "gift-filled",
|
||||
"unicode": "\ue6c4"
|
||||
},
|
||||
{
|
||||
"font_class": "hand-down",
|
||||
"unicode": "\ue63d"
|
||||
},
|
||||
{
|
||||
"font_class": "hand-down-filled",
|
||||
"unicode": "\ue63c"
|
||||
},
|
||||
{
|
||||
"font_class": "hand-up",
|
||||
"unicode": "\ue63f"
|
||||
},
|
||||
{
|
||||
"font_class": "hand-up-filled",
|
||||
"unicode": "\ue63e"
|
||||
},
|
||||
{
|
||||
"font_class": "headphones",
|
||||
"unicode": "\ue630"
|
||||
},
|
||||
{
|
||||
"font_class": "heart",
|
||||
"unicode": "\ue639"
|
||||
},
|
||||
{
|
||||
"font_class": "heart-filled",
|
||||
"unicode": "\ue641"
|
||||
},
|
||||
{
|
||||
"font_class": "help",
|
||||
"unicode": "\ue679"
|
||||
},
|
||||
{
|
||||
"font_class": "help-filled",
|
||||
"unicode": "\ue674"
|
||||
},
|
||||
{
|
||||
"font_class": "home",
|
||||
"unicode": "\ue662"
|
||||
},
|
||||
{
|
||||
"font_class": "home-filled",
|
||||
"unicode": "\ue663"
|
||||
},
|
||||
{
|
||||
"font_class": "image",
|
||||
"unicode": "\ue670"
|
||||
},
|
||||
{
|
||||
"font_class": "image-filled",
|
||||
"unicode": "\ue678"
|
||||
},
|
||||
{
|
||||
"font_class": "images",
|
||||
"unicode": "\ue650"
|
||||
},
|
||||
{
|
||||
"font_class": "images-filled",
|
||||
"unicode": "\ue64b"
|
||||
},
|
||||
{
|
||||
"font_class": "info",
|
||||
"unicode": "\ue669"
|
||||
},
|
||||
{
|
||||
"font_class": "info-filled",
|
||||
"unicode": "\ue649"
|
||||
},
|
||||
{
|
||||
"font_class": "left",
|
||||
"unicode": "\ue6b7"
|
||||
},
|
||||
{
|
||||
"font_class": "link",
|
||||
"unicode": "\ue6a5"
|
||||
},
|
||||
{
|
||||
"font_class": "list",
|
||||
"unicode": "\ue644"
|
||||
},
|
||||
{
|
||||
"font_class": "location",
|
||||
"unicode": "\ue6ae"
|
||||
},
|
||||
{
|
||||
"font_class": "location-filled",
|
||||
"unicode": "\ue6af"
|
||||
},
|
||||
{
|
||||
"font_class": "locked",
|
||||
"unicode": "\ue66b"
|
||||
},
|
||||
{
|
||||
"font_class": "locked-filled",
|
||||
"unicode": "\ue668"
|
||||
},
|
||||
{
|
||||
"font_class": "loop",
|
||||
"unicode": "\ue633"
|
||||
},
|
||||
{
|
||||
"font_class": "mail-open",
|
||||
"unicode": "\ue643"
|
||||
},
|
||||
{
|
||||
"font_class": "mail-open-filled",
|
||||
"unicode": "\ue63a"
|
||||
},
|
||||
{
|
||||
"font_class": "map",
|
||||
"unicode": "\ue667"
|
||||
},
|
||||
{
|
||||
"font_class": "map-filled",
|
||||
"unicode": "\ue666"
|
||||
},
|
||||
{
|
||||
"font_class": "map-pin",
|
||||
"unicode": "\ue6ad"
|
||||
},
|
||||
{
|
||||
"font_class": "map-pin-ellipse",
|
||||
"unicode": "\ue6ac"
|
||||
},
|
||||
{
|
||||
"font_class": "medal",
|
||||
"unicode": "\ue6a2"
|
||||
},
|
||||
{
|
||||
"font_class": "medal-filled",
|
||||
"unicode": "\ue6c3"
|
||||
},
|
||||
{
|
||||
"font_class": "mic",
|
||||
"unicode": "\ue671"
|
||||
},
|
||||
{
|
||||
"font_class": "mic-filled",
|
||||
"unicode": "\ue677"
|
||||
},
|
||||
{
|
||||
"font_class": "micoff",
|
||||
"unicode": "\ue67e"
|
||||
},
|
||||
{
|
||||
"font_class": "micoff-filled",
|
||||
"unicode": "\ue6b0"
|
||||
},
|
||||
{
|
||||
"font_class": "minus",
|
||||
"unicode": "\ue66f"
|
||||
},
|
||||
{
|
||||
"font_class": "minus-filled",
|
||||
"unicode": "\ue67d"
|
||||
},
|
||||
{
|
||||
"font_class": "more",
|
||||
"unicode": "\ue64d"
|
||||
},
|
||||
{
|
||||
"font_class": "more-filled",
|
||||
"unicode": "\ue64e"
|
||||
},
|
||||
{
|
||||
"font_class": "navigate",
|
||||
"unicode": "\ue66e"
|
||||
},
|
||||
{
|
||||
"font_class": "navigate-filled",
|
||||
"unicode": "\ue67a"
|
||||
},
|
||||
{
|
||||
"font_class": "notification",
|
||||
"unicode": "\ue6a6"
|
||||
},
|
||||
{
|
||||
"font_class": "notification-filled",
|
||||
"unicode": "\ue6c1"
|
||||
},
|
||||
{
|
||||
"font_class": "paperclip",
|
||||
"unicode": "\ue652"
|
||||
},
|
||||
{
|
||||
"font_class": "paperplane",
|
||||
"unicode": "\ue672"
|
||||
},
|
||||
{
|
||||
"font_class": "paperplane-filled",
|
||||
"unicode": "\ue675"
|
||||
},
|
||||
{
|
||||
"font_class": "person",
|
||||
"unicode": "\ue699"
|
||||
},
|
||||
{
|
||||
"font_class": "person-filled",
|
||||
"unicode": "\ue69d"
|
||||
},
|
||||
{
|
||||
"font_class": "personadd",
|
||||
"unicode": "\ue69f"
|
||||
},
|
||||
{
|
||||
"font_class": "personadd-filled",
|
||||
"unicode": "\ue698"
|
||||
},
|
||||
{
|
||||
"font_class": "personadd-filled-copy",
|
||||
"unicode": "\ue6d1"
|
||||
},
|
||||
{
|
||||
"font_class": "phone",
|
||||
"unicode": "\ue69c"
|
||||
},
|
||||
{
|
||||
"font_class": "phone-filled",
|
||||
"unicode": "\ue69b"
|
||||
},
|
||||
{
|
||||
"font_class": "plus",
|
||||
"unicode": "\ue676"
|
||||
},
|
||||
{
|
||||
"font_class": "plus-filled",
|
||||
"unicode": "\ue6c7"
|
||||
},
|
||||
{
|
||||
"font_class": "plusempty",
|
||||
"unicode": "\ue67b"
|
||||
},
|
||||
{
|
||||
"font_class": "pulldown",
|
||||
"unicode": "\ue632"
|
||||
},
|
||||
{
|
||||
"font_class": "pyq",
|
||||
"unicode": "\ue682"
|
||||
},
|
||||
{
|
||||
"font_class": "qq",
|
||||
"unicode": "\ue680"
|
||||
},
|
||||
{
|
||||
"font_class": "redo",
|
||||
"unicode": "\ue64a"
|
||||
},
|
||||
{
|
||||
"font_class": "redo-filled",
|
||||
"unicode": "\ue655"
|
||||
},
|
||||
{
|
||||
"font_class": "refresh",
|
||||
"unicode": "\ue657"
|
||||
},
|
||||
{
|
||||
"font_class": "refresh-filled",
|
||||
"unicode": "\ue656"
|
||||
},
|
||||
{
|
||||
"font_class": "refreshempty",
|
||||
"unicode": "\ue6bf"
|
||||
},
|
||||
{
|
||||
"font_class": "reload",
|
||||
"unicode": "\ue6b2"
|
||||
},
|
||||
{
|
||||
"font_class": "right",
|
||||
"unicode": "\ue6b5"
|
||||
},
|
||||
{
|
||||
"font_class": "scan",
|
||||
"unicode": "\ue62a"
|
||||
},
|
||||
{
|
||||
"font_class": "search",
|
||||
"unicode": "\ue654"
|
||||
},
|
||||
{
|
||||
"font_class": "settings",
|
||||
"unicode": "\ue653"
|
||||
},
|
||||
{
|
||||
"font_class": "settings-filled",
|
||||
"unicode": "\ue6ce"
|
||||
},
|
||||
{
|
||||
"font_class": "shop",
|
||||
"unicode": "\ue62f"
|
||||
},
|
||||
{
|
||||
"font_class": "shop-filled",
|
||||
"unicode": "\ue6cd"
|
||||
},
|
||||
{
|
||||
"font_class": "smallcircle",
|
||||
"unicode": "\ue67c"
|
||||
},
|
||||
{
|
||||
"font_class": "smallcircle-filled",
|
||||
"unicode": "\ue665"
|
||||
},
|
||||
{
|
||||
"font_class": "sound",
|
||||
"unicode": "\ue684"
|
||||
},
|
||||
{
|
||||
"font_class": "sound-filled",
|
||||
"unicode": "\ue686"
|
||||
},
|
||||
{
|
||||
"font_class": "spinner-cycle",
|
||||
"unicode": "\ue68a"
|
||||
},
|
||||
{
|
||||
"font_class": "staff",
|
||||
"unicode": "\ue6a7"
|
||||
},
|
||||
{
|
||||
"font_class": "staff-filled",
|
||||
"unicode": "\ue6cb"
|
||||
},
|
||||
{
|
||||
"font_class": "star",
|
||||
"unicode": "\ue688"
|
||||
},
|
||||
{
|
||||
"font_class": "star-filled",
|
||||
"unicode": "\ue68f"
|
||||
},
|
||||
{
|
||||
"font_class": "starhalf",
|
||||
"unicode": "\ue683"
|
||||
},
|
||||
{
|
||||
"font_class": "trash",
|
||||
"unicode": "\ue687"
|
||||
},
|
||||
{
|
||||
"font_class": "trash-filled",
|
||||
"unicode": "\ue685"
|
||||
},
|
||||
{
|
||||
"font_class": "tune",
|
||||
"unicode": "\ue6aa"
|
||||
},
|
||||
{
|
||||
"font_class": "tune-filled",
|
||||
"unicode": "\ue6ca"
|
||||
},
|
||||
{
|
||||
"font_class": "undo",
|
||||
"unicode": "\ue64f"
|
||||
},
|
||||
{
|
||||
"font_class": "undo-filled",
|
||||
"unicode": "\ue64c"
|
||||
},
|
||||
{
|
||||
"font_class": "up",
|
||||
"unicode": "\ue6b6"
|
||||
},
|
||||
{
|
||||
"font_class": "top",
|
||||
"unicode": "\ue6b6"
|
||||
},
|
||||
{
|
||||
"font_class": "upload",
|
||||
"unicode": "\ue690"
|
||||
},
|
||||
{
|
||||
"font_class": "upload-filled",
|
||||
"unicode": "\ue68e"
|
||||
},
|
||||
{
|
||||
"font_class": "videocam",
|
||||
"unicode": "\ue68c"
|
||||
},
|
||||
{
|
||||
"font_class": "videocam-filled",
|
||||
"unicode": "\ue689"
|
||||
},
|
||||
{
|
||||
"font_class": "vip",
|
||||
"unicode": "\ue6a8"
|
||||
},
|
||||
{
|
||||
"font_class": "vip-filled",
|
||||
"unicode": "\ue6c6"
|
||||
},
|
||||
{
|
||||
"font_class": "wallet",
|
||||
"unicode": "\ue6b1"
|
||||
},
|
||||
{
|
||||
"font_class": "wallet-filled",
|
||||
"unicode": "\ue6c2"
|
||||
},
|
||||
{
|
||||
"font_class": "weibo",
|
||||
"unicode": "\ue68b"
|
||||
},
|
||||
{
|
||||
"font_class": "weixin",
|
||||
"unicode": "\ue691"
|
||||
}
|
||||
]
|
||||
|
||||
// export const fontData = JSON.parse<IconsDataItem>(fontDataJson)
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-icons",
|
||||
"displayName": "uni-icons 图标",
|
||||
"version": "1.3.5",
|
||||
"version": "2.0.10",
|
||||
"description": "图标组件,用于展示移动端常见的图标,可自定义颜色、大小。",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
@@ -17,10 +17,6 @@
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
@@ -37,7 +33,8 @@
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": ["uni-scss"],
|
||||
@@ -45,12 +42,14 @@
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y"
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "y"
|
||||
"app-nvue": "y",
|
||||
"app-uvue": "y"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
@@ -70,11 +69,15 @@
|
||||
"阿里": "y",
|
||||
"百度": "y",
|
||||
"字节跳动": "y",
|
||||
"QQ": "y"
|
||||
"QQ": "y",
|
||||
"钉钉": "y",
|
||||
"快手": "y",
|
||||
"飞书": "y",
|
||||
"京东": "y"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
"华为": "y",
|
||||
"联盟": "y"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
## 1.0.18(2024-07-08)
|
||||
- checkToken时如果传入的token为空则返回uni-id-check-token-failed错误码以便uniIdRouter能正常跳转
|
||||
## 1.0.17(2024-04-26)
|
||||
- 兼容uni-app-x对客户端uniPlatform的调整(uni-app-x内uniPlatform区分app-android、app-ios)
|
||||
## 1.0.16(2023-04-25)
|
||||
- 新增maxTokenLength配置,用于限制数据库用户记录token数组的最大长度
|
||||
## 1.0.15(2023-04-06)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-id-common",
|
||||
"displayName": "uni-id-common",
|
||||
"version": "1.0.18",
|
||||
"version": "1.0.16",
|
||||
"description": "包含uni-id token生成、校验、刷新功能的云函数公共模块",
|
||||
"keywords": [
|
||||
"uni-id-common",
|
||||
@@ -11,14 +11,15 @@
|
||||
],
|
||||
"repository": "https://gitcode.net/dcloud/uni-id-common",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": 0
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": 0
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
@@ -38,8 +39,7 @@
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
"aliyun": "y"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,20 +1,16 @@
|
||||
{
|
||||
"name": "uni-id-common",
|
||||
"version": "1.0.18",
|
||||
"version": "1.0.16",
|
||||
"description": "uni-id token生成、校验、刷新",
|
||||
"main": "index.js",
|
||||
"homepage": "https:\/\/uniapp.dcloud.io\/uniCloud\/uni-id-common.html",
|
||||
"homepage": "https://uniapp.dcloud.io/uniCloud/uni-id-common.html",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https:\/\/gitee.com\/dcloud\/uni-id-common.git"
|
||||
"url": "git+https://gitee.com/dcloud/uni-id-common.git"
|
||||
},
|
||||
"author": "DCloud",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"uni-config-center": "file:..\/..\/..\/..\/..\/uni-config-center\/uniCloud\/cloudfunctions\/common\/uni-config-center"
|
||||
},
|
||||
"origin-plugin-dev-name": "uni-id-common",
|
||||
"origin-plugin-version": "1.0.18",
|
||||
"plugin-dev-name": "uni-id-common",
|
||||
"plugin-version": "1.0.18"
|
||||
"uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center"
|
||||
}
|
||||
}
|
||||
@@ -1,92 +1,3 @@
|
||||
## 3.3.29(2022-10-20)
|
||||
- 使用[uni-open-bridge-common](https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge.html#common)存储用户三方凭证,以便其他服务使用。
|
||||
## 3.3.28(2022-07-27)
|
||||
- 修复 app端微信登录返回的accessToken过期时间(expired)不正确的Bug
|
||||
## 3.3.27(2022-07-27)
|
||||
- 短信发送失败、微信登录失败等场景下输出原始错误方便排查错误
|
||||
## 3.3.26(2022-07-08)
|
||||
- 兼容配置放在uni-id下的逻辑,但是仍推荐使用uni-config-center
|
||||
## 3.3.25(2022-06-30)
|
||||
- 修复config文件不合法时未抛出具体错误的Bug
|
||||
## 3.3.24(2022-06-28)
|
||||
- 修复3.3.12引出的使用多应用配置时报错的Bug
|
||||
## 3.3.23(2022-06-13)
|
||||
- 修复上版本引出的部分依赖未找到的Bug
|
||||
## 3.3.22(2022-06-13)
|
||||
- 新增 preferedWebPlatform 配置用于解决HBuilderX 3.4.9版本起web端platform不一致的问题 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=prefered-web-platform)
|
||||
## 3.3.21(2022-05-24)
|
||||
- 修复createInstance传入clientInfo无效的Bug
|
||||
## 3.3.20(2022-05-19)
|
||||
- 调整以下错误码(账号已注册[uni-id-account-exists]、账号不存在[uni-id-account-not-exists]、账号已绑定[uni-id-account-bound])
|
||||
## 3.3.19(2022-05-19)
|
||||
- 修复 addUser 部分情况下会创建出重复账号的Bug
|
||||
## 3.3.18(2022-05-12)
|
||||
- 调整绑定、解绑邮箱手机号接口,只要传递code参数就进行验证码校验即使传递的值为undefined
|
||||
## 3.3.17(2022-05-09)
|
||||
- register_env内增加os_name字段用于区分注册时的客户端系统类型
|
||||
## 3.3.16(2022-05-09)
|
||||
- 修复 addUser接口添加的用户无法使用密码登录的Bug [详情](https://ask.dcloud.net.cn/question/144670)
|
||||
## 3.3.15(2022-05-08)
|
||||
- 修复config文件语法错误时报`this.t is not a function`的Bug 感谢@寒暄
|
||||
## 3.3.14(2022-05-08)
|
||||
- 新增 getWeixinUserInfo接口 用于获取app平台微信登录用户的用户信息 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id.html#get-weixin-user-info)
|
||||
- 新增 addUser接口 用于手动添加用户 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id.html#add-user)
|
||||
- 新增 resetPwdBySms接口 用于使用短信验证码重置密码 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id.html#reset-pwd-by-sms)
|
||||
- 新增 refreshToken接口 用于主动刷新用户token [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id.html#refresh-token)
|
||||
- 调整 用户注册时记录用户注册环境到 register_env 字段 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id.html#user-table)
|
||||
- 调整 用户注册时将注册 ip 移至 register_env 内
|
||||
|
||||
## 3.3.13(2022-03-04)
|
||||
- createInstance方法支持传递clientInfo [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id.html#create-instance)
|
||||
- 修复`this.t is not a function`报错
|
||||
## 3.3.12(2022-01-15)
|
||||
- 新增 preferedAppPlatform 配置用于解决uni-app vue2版本vue3版本获取platform不一致的问题 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=prefered-app-platform)
|
||||
- 修复 checkToken 未返回自定义token内容的Bug
|
||||
## 3.3.11(2022-01-11)
|
||||
- 修复用户名密码登录时多个应用出现重复用户名登录报错的Bug
|
||||
## 3.3.10(2022-01-07)
|
||||
- 新增 自定义国际化语言支持 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=custom-i8n)
|
||||
- 修复 一键登录时未校验重复手机号是否已验证的Bug
|
||||
- 修复 Apple登录时用户邮箱为空时报错的Bug
|
||||
- 修复 登录接口未传username时错误提示不正确的Bug
|
||||
## 3.3.9(2021-11-09)
|
||||
- 去除重复的context.xxx未找到的提示语
|
||||
## 3.3.8(2021-10-28)
|
||||
- 新增 用户账户封禁接口 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=ban-account)
|
||||
- 新增 用户账户注销接口 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=close-account)
|
||||
- 修复 未传appid时用户重复注册的Bug
|
||||
## 3.3.7(2021-10-08)
|
||||
- 移除部分接口的废弃提示
|
||||
## 3.3.6(2021-09-08)
|
||||
- 修复 邀请码可能重复的Bug
|
||||
## 3.3.5(2021-08-10)
|
||||
- 修复版本号错误
|
||||
## 3.3.4(2021-08-10)
|
||||
- 微信、QQ、支付宝登录新增type参数用于指定当前是登录还是注册
|
||||
## 3.3.3(2021-08-04)
|
||||
- 修复使用数组形式的配置文件报错的Bug
|
||||
## 3.3.2(2021-08-03)
|
||||
- 修复上3.3.0版本引出的createInstance接口传入配置不生效的Bug 感谢[hmh](https://gitee.com/hmh)
|
||||
## 3.3.1(2021-07-30)
|
||||
- 修复 将设置用户允许登录的应用列表时传入空数组报错的Bug
|
||||
## 3.3.0(2021-07-30)
|
||||
- 新增 不同端应用配置隔离 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=isolate-config)
|
||||
- 新增 不同端用户隔离 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=isolate-user)
|
||||
+ 此版本升级需要开发者处理一下用户数据,请参考 [补齐用户dcloud_appid字段](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=makeup-dcloud-appid)
|
||||
- 新增 QQ登录、注册相关功能 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=qq)
|
||||
- 调整 不再支持绑定手机、邮箱时不填验证码直接绑定
|
||||
## 3.2.1(2021-07-09)
|
||||
- 撤销3.2.0版本所做的调整
|
||||
## 3.2.0(2021-07-09)
|
||||
- 【重要】支持不同端(管理端、用户端等)用户隔离 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=isolate-user)
|
||||
- 支持不同端(管理端、用户端等)配置文件隔离 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=isolate-config)
|
||||
## 3.1.3(2021-07-08)
|
||||
- 移除插件内误传的node_modules
|
||||
## 3.1.2(2021-07-08)
|
||||
- 修复 微信小程序绑定微信账号时报错的Bug
|
||||
## 3.1.1(2021-07-01)
|
||||
- 使用新的错误码规范,兼容旧版 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=errcode)
|
||||
- 修复微信登录、绑定时未返回用户accessToken的Bug
|
||||
## 3.1.0(2021-04-19)
|
||||
- 增加对用户名、邮箱、密码字段的两端去空格
|
||||
- 默认忽略用户名、邮箱的大小写 [详情](https://uniapp.dcloud.net.cn/uniCloud/uni-id?id=case-sensitive)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-id",
|
||||
"displayName": "uni-id",
|
||||
"version": "3.3.29",
|
||||
"version": "3.1.0",
|
||||
"description": "简单、统一、可扩展的用户中心",
|
||||
"keywords": [
|
||||
"uniid",
|
||||
@@ -15,6 +15,10 @@
|
||||
"HBuilderX": "^3.1.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"uniCloud",
|
||||
"云函数模板"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
@@ -31,11 +35,10 @@
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "",
|
||||
"type": "unicloud-template-function"
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": ["uni-config-center", "uni-open-bridge-common"],
|
||||
"dependencies": ["uni-config-center"],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
@@ -65,19 +68,11 @@
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
"QQ": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
},
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "uni-id",
|
||||
"version": "3.3.29",
|
||||
"version": "3.1.0",
|
||||
"description": "uni-id for uniCloud",
|
||||
"main": "index.js",
|
||||
"homepage": "https://uniapp.dcloud.io/uniCloud/uni-id",
|
||||
@@ -11,7 +11,6 @@
|
||||
"author": "",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center",
|
||||
"uni-open-bridge-common": "file:../../../../../uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common"
|
||||
"uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,11 @@
|
||||
## 1.8.3(2023-04-17)
|
||||
- 修复 uni-popup 重复打开时的 bug
|
||||
## 1.8.2(2023-02-02)
|
||||
- uni-popup-dialog 组件新增 inputType 属性
|
||||
## 1.8.1(2022-12-01)
|
||||
- 修复 nvue 下 v-show 报错
|
||||
## 1.8.0(2022-11-29)
|
||||
- 优化 主题样式
|
||||
## 1.7.9(2022-04-02)
|
||||
- 修复 弹出层内部无法滚动的bug
|
||||
## 1.7.8(2022-03-28)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
</view>
|
||||
<view v-else class="uni-dialog-content">
|
||||
<slot>
|
||||
<input class="uni-dialog-input" v-model="val" type="text" :placeholder="placeholderText" :focus="focus" >
|
||||
<input class="uni-dialog-input" v-model="val" :type="inputType" :placeholder="placeholderText" :focus="focus" >
|
||||
</slot>
|
||||
</view>
|
||||
<view class="uni-dialog-button-group">
|
||||
@@ -57,6 +57,10 @@
|
||||
mixins: [popup],
|
||||
emits:['confirm','close'],
|
||||
props: {
|
||||
inputType:{
|
||||
type: String,
|
||||
default: 'text'
|
||||
},
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
@@ -229,7 +233,7 @@
|
||||
}
|
||||
|
||||
.uni-border-left {
|
||||
border-left-color: #f5f5f5;
|
||||
border-left-color: #f0f0f0;
|
||||
border-left-style: solid;
|
||||
border-left-width: 1px;
|
||||
}
|
||||
|
||||
@@ -40,25 +40,25 @@
|
||||
data() {
|
||||
return {
|
||||
bottomData: [{
|
||||
text: '微信',
|
||||
text: '微信消息',
|
||||
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/c2b17470-50be-11eb-b680-7980c8a877b8.png',
|
||||
name: 'wx'
|
||||
},
|
||||
{
|
||||
text: '支付宝',
|
||||
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/d684ae40-50be-11eb-8ff1-d5dcf8779628.png',
|
||||
text: '朋友圈',
|
||||
icon: 'http://ehh-public-01.oss-cn-beijing.aliyuncs.com/image/20240626131115.png',
|
||||
name: 'wx'
|
||||
},
|
||||
{
|
||||
text: 'QQ',
|
||||
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/e7a79520-50be-11eb-b997-9918a5dda011.png',
|
||||
name: 'qq'
|
||||
},
|
||||
{
|
||||
text: '新浪',
|
||||
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/0dacdbe0-50bf-11eb-8ff1-d5dcf8779628.png',
|
||||
name: 'sina'
|
||||
},
|
||||
// {
|
||||
// text: 'QQ',
|
||||
// icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/e7a79520-50be-11eb-b997-9918a5dda011.png',
|
||||
// name: 'qq'
|
||||
// },
|
||||
// {
|
||||
// text: '新浪',
|
||||
// icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/0dacdbe0-50bf-11eb-8ff1-d5dcf8779628.png',
|
||||
// name: 'sina'
|
||||
// },
|
||||
// {
|
||||
// text: '百度',
|
||||
// icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/1ec6e920-50bf-11eb-8a36-ebb87efcf8c0.png',
|
||||
|
||||
@@ -269,8 +269,7 @@
|
||||
open(direction) {
|
||||
// fix by mehaotian 处理快速打开关闭的情况
|
||||
if (this.showPopup) {
|
||||
clearTimeout(this.timer)
|
||||
this.showPopup = false
|
||||
return
|
||||
}
|
||||
let innerType = ['top', 'center', 'bottom', 'left', 'right', 'message', 'dialog', 'share']
|
||||
if (!(direction && innerType.indexOf(direction) !== -1)) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-popup",
|
||||
"displayName": "uni-popup 弹出层",
|
||||
"version": "1.7.9",
|
||||
"version": "1.8.3",
|
||||
"description": " Popup 组件,提供常用的弹层",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
@@ -18,10 +18,6 @@
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
@@ -38,7 +34,8 @@
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
|
||||
95
uni_modules/uni-scss/manifest.json
Normal file
95
uni_modules/uni-scss/manifest.json
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"name" : "",
|
||||
"appid" : "",
|
||||
"description": "应用描述",
|
||||
"versionName": "1.0.0",
|
||||
"versionCode": "100",
|
||||
"transformPx": false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus": {
|
||||
"usingComponents": true,
|
||||
"splashscreen": {
|
||||
"alwaysShowBeforeRender": true,
|
||||
"waiting": true,
|
||||
"autoclose": true,
|
||||
"delay": 0
|
||||
},
|
||||
"modules": {
|
||||
"OAuth": {},
|
||||
"Payment": {},
|
||||
"Push": {},
|
||||
"Share": {},
|
||||
"Speech": {},
|
||||
"VideoPlayer": {}
|
||||
},
|
||||
/* 应用发布信息 */
|
||||
"distribute": {
|
||||
/* android打包配置 */
|
||||
"android": {
|
||||
"permissions": [
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_MOCK_LOCATION\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_TASKS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.INTERNET\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_SMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\"/>",
|
||||
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
|
||||
"<uses-permission android:name=\"android.permission.SEND_SMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.RECEIVE_USER_PRESENT\"/>"
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios": {
|
||||
"UIBackgroundModes": ["audio"]
|
||||
},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs": {
|
||||
"speech": {
|
||||
"ifly": {}
|
||||
}
|
||||
},
|
||||
"orientation": ["portrait-primary"]
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp": {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin": {
|
||||
"appid": "",
|
||||
"setting": {
|
||||
"urlCheck": false
|
||||
},
|
||||
"usingComponents": true
|
||||
},
|
||||
"h5": {
|
||||
"template": "template.h5.html",
|
||||
"router": {
|
||||
"mode": "history",
|
||||
"base": "/h5/"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
## 1.2.4(2023-05-09)
|
||||
- 修复 i18n 国际化不正确的 Bug
|
||||
## 1.2.3(2022-05-24)
|
||||
- 新增 readonly 属性,组件只读
|
||||
## 1.2.2(2022-05-06)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"uni-search-bar.cancel": "cancel",
|
||||
"uni-search-bar.cancel": "取消",
|
||||
"uni-search-bar.placeholder": "请输入搜索内容"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"uni-search-bar.cancel": "cancel",
|
||||
"uni-search-bar.cancel": "取消",
|
||||
"uni-search-bar.placeholder": "請輸入搜索內容"
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
},
|
||||
cancelText: {
|
||||
type: String,
|
||||
default: '取消'
|
||||
default: ""
|
||||
},
|
||||
bgColor: {
|
||||
type: String,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-search-bar",
|
||||
"displayName": "uni-search-bar 搜索栏",
|
||||
"version": "1.2.3",
|
||||
"version": "1.2.4",
|
||||
"description": "搜索栏组件,通常用于搜索商品、文章等",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
@@ -17,10 +17,6 @@
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
@@ -37,7 +33,8 @@
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
## 1.2.3(2023-03-28)
|
||||
- 修复 在vue3模式下可能会出现错误的问题
|
||||
## 1.2.2(2022-11-29)
|
||||
- 优化 主题样式
|
||||
## 1.2.1(2022-06-06)
|
||||
- 修复 微信小程序存在无使用组件的问题
|
||||
## 1.2.0(2021-11-19)
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
<!-- #ifdef H5 -->
|
||||
<table class="uni-table" border="0" cellpadding="0" cellspacing="0" :class="{ 'table--stripe': stripe }" :style="{ 'min-width': minWidth + 'px' }">
|
||||
<slot></slot>
|
||||
<view v-if="noData" class="uni-table-loading">
|
||||
<view class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</view>
|
||||
</view>
|
||||
<tr v-if="noData" class="uni-table-loading">
|
||||
<td class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</td>
|
||||
</tr>
|
||||
<view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view>
|
||||
</table>
|
||||
<!-- #endif -->
|
||||
@@ -125,7 +125,7 @@ export default {
|
||||
} else {
|
||||
startIndex = theadChildren.rowspan - 1
|
||||
}
|
||||
let isHaveData = this.data && this.data.length.length > 0
|
||||
let isHaveData = this.data && this.data.length > 0
|
||||
theadChildren.checked = true
|
||||
theadChildren.indeterminate = false
|
||||
this.trChildren.forEach((item, index) => {
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
padding: 8px 10px;
|
||||
font-size: 14px;
|
||||
border-bottom: 1px $border-color solid;
|
||||
font-weight: 600;
|
||||
font-weight: 400;
|
||||
color: #606266;
|
||||
line-height: 23px;
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -112,6 +112,12 @@
|
||||
value: 'value'
|
||||
}
|
||||
}
|
||||
},
|
||||
filterDefaultValue: {
|
||||
type: [Array,String],
|
||||
default () {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -157,7 +163,7 @@
|
||||
enabled: true,
|
||||
isOpened: false,
|
||||
dataList: [],
|
||||
filterValue: '',
|
||||
filterValue: this.filterDefaultValue,
|
||||
checkedValues: [],
|
||||
gtValue: '',
|
||||
ltValue: '',
|
||||
@@ -286,6 +292,8 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$uni-primary: #1890ff !default;
|
||||
|
||||
.flex-r {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -315,8 +323,8 @@
|
||||
}
|
||||
|
||||
.icon-select.active {
|
||||
background-color: #1890ff;
|
||||
border-top-color: #1890ff;
|
||||
background-color: $uni-primary;
|
||||
border-top-color: $uni-primary;
|
||||
}
|
||||
|
||||
.icon-search {
|
||||
@@ -343,11 +351,11 @@
|
||||
}
|
||||
|
||||
.icon-search.active .icon-search-0 {
|
||||
border-color: #1890ff;
|
||||
border-color: $uni-primary;
|
||||
}
|
||||
|
||||
.icon-search.active .icon-search-1 {
|
||||
background-color: #1890ff;
|
||||
background-color: $uni-primary;
|
||||
}
|
||||
|
||||
.icon-calendar {
|
||||
@@ -387,14 +395,14 @@
|
||||
}
|
||||
|
||||
.icon-calendar.active {
|
||||
color: #1890ff;
|
||||
color: $uni-primary;
|
||||
}
|
||||
|
||||
.icon-calendar.active .icon-calendar-0,
|
||||
.icon-calendar.active .icon-calendar-1,
|
||||
.icon-calendar.active .icon-calendar-0:before,
|
||||
.icon-calendar.active .icon-calendar-0:after {
|
||||
background-color: #1890ff;
|
||||
background-color: $uni-primary;
|
||||
}
|
||||
|
||||
.uni-filter-dropdown {
|
||||
@@ -440,7 +448,7 @@
|
||||
}
|
||||
|
||||
.list-item:hover {
|
||||
background-color: #f5f5f5;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.check {
|
||||
@@ -453,7 +461,7 @@
|
||||
|
||||
.search-input {
|
||||
font-size: 12px;
|
||||
border: 1px solid #f5f5f5;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 3px;
|
||||
padding: 2px 5px;
|
||||
min-width: 150px;
|
||||
@@ -467,7 +475,7 @@
|
||||
|
||||
.input {
|
||||
font-size: 12px;
|
||||
border: 1px solid #f5f5f5;
|
||||
border: 1px solid #f0f0f0;
|
||||
border-radius: 3px;
|
||||
margin: 10px;
|
||||
padding: 2px 5px;
|
||||
@@ -497,7 +505,7 @@
|
||||
}
|
||||
|
||||
.btn-submit {
|
||||
background-color: #1890ff;
|
||||
background-color: $uni-primary;
|
||||
color: #ffffff;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<text class="arrow down" :class="{ active: descending }" @click.stop="descendingFn"></text>
|
||||
</view>
|
||||
</view>
|
||||
<dropdown v-if="filterType || filterData.length" :filterData="filterData" :filterType="filterType" @change="ondropdown"></dropdown>
|
||||
<dropdown v-if="filterType || filterData.length" :filterDefaultValue="filterDefaultValue" :filterData="filterData" :filterType="filterType" @change="ondropdown"></dropdown>
|
||||
</view>
|
||||
</th>
|
||||
<!-- #endif -->
|
||||
@@ -79,6 +79,12 @@ export default {
|
||||
default () {
|
||||
return []
|
||||
}
|
||||
},
|
||||
filterDefaultValue: {
|
||||
type: [Array,String],
|
||||
default () {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -200,6 +206,7 @@ export default {
|
||||
|
||||
<style lang="scss">
|
||||
$border-color: #ebeef5;
|
||||
$uni-primary: #007aff !default;
|
||||
|
||||
.uni-table-th {
|
||||
padding: 12px 10px;
|
||||
@@ -254,7 +261,7 @@ $border-color: #ebeef5;
|
||||
}
|
||||
&.active {
|
||||
::after {
|
||||
background-color: #007aff;
|
||||
background-color: $uni-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,7 +278,7 @@ $border-color: #ebeef5;
|
||||
}
|
||||
&.active {
|
||||
::after {
|
||||
background-color: #007aff;
|
||||
background-color: $uni-primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
$checked-color: #007aff;
|
||||
$uni-primary: #007aff !default;
|
||||
$border-color: #DCDFE6;
|
||||
$disable:0.4;
|
||||
|
||||
@@ -125,8 +125,8 @@
|
||||
}
|
||||
|
||||
&.checkbox--indeterminate {
|
||||
border-color: $checked-color;
|
||||
background-color: $checked-color;
|
||||
border-color: $uni-primary;
|
||||
background-color: $uni-primary;
|
||||
|
||||
.checkbox__inner-icon {
|
||||
position: absolute;
|
||||
@@ -147,7 +147,7 @@
|
||||
}
|
||||
}
|
||||
&:hover{
|
||||
border-color: $checked-color;
|
||||
border-color: $uni-primary;
|
||||
}
|
||||
// 禁用
|
||||
&.is-disable {
|
||||
@@ -160,8 +160,8 @@
|
||||
|
||||
// 选中
|
||||
&.is-checked {
|
||||
border-color: $checked-color;
|
||||
background-color: $checked-color;
|
||||
border-color: $uni-primary;
|
||||
background-color: $uni-primary;
|
||||
|
||||
.checkbox__inner-icon {
|
||||
opacity: 1;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "uni-table",
|
||||
"displayName": "uni-table 表格",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.3",
|
||||
"description": "表格组件,多用于展示多条结构类似的数据,如",
|
||||
"keywords": [
|
||||
"uni-ui",
|
||||
@@ -17,10 +17,6 @@
|
||||
"example": "../../temps/example_temps"
|
||||
},
|
||||
"dcloudext": {
|
||||
"category": [
|
||||
"前端组件",
|
||||
"通用组件"
|
||||
],
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
@@ -37,7 +33,8 @@
|
||||
"data": "无",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
|
||||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
|
||||
"type": "component-vue"
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": ["uni-scss","uni-datetime-picker"],
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
## 1.3.2(2023-05-04)
|
||||
- 修复 NVUE 平台报错的问题
|
||||
## 1.3.1(2021-11-23)
|
||||
- 修复 init 方法初始化问题
|
||||
## 1.3.0(2021-11-19)
|
||||
|
||||
@@ -10,7 +10,10 @@ const nvueAnimation = uni.requireNativePlugin('animation')
|
||||
class MPAnimation {
|
||||
constructor(options, _this) {
|
||||
this.options = options
|
||||
this.animation = uni.createAnimation(options)
|
||||
// 在iOS10+QQ小程序平台下,传给原生的对象一定是个普通对象而不是Proxy对象,否则会报parameter should be Object instead of ProxyObject的错误
|
||||
this.animation = uni.createAnimation({
|
||||
...options
|
||||
})
|
||||
this.currentStepAnimates = {}
|
||||
this.next = 0
|
||||
this.$ = _this
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user