conmit message
commit
90db3fd233
|
@ -0,0 +1,16 @@
|
||||||
|
{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
|
||||||
|
// launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
|
||||||
|
"version": "0.0",
|
||||||
|
"configurations": [{
|
||||||
|
"default" :
|
||||||
|
{
|
||||||
|
"launchtype" : "local"
|
||||||
|
},
|
||||||
|
"mp-weixin" :
|
||||||
|
{
|
||||||
|
"launchtype" : "local"
|
||||||
|
},
|
||||||
|
"type" : "uniCloud"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
<script>
|
||||||
|
import toolAll from '@/jsFile/tools.js'
|
||||||
|
import {
|
||||||
|
postUserInfo,
|
||||||
|
getInfo
|
||||||
|
} from "@/api/index";
|
||||||
|
export default {
|
||||||
|
globalData:{
|
||||||
|
projectname:'', // 项目名称
|
||||||
|
lat:'', // 公司地址维度
|
||||||
|
lng:'' ,// 公司地址经度
|
||||||
|
|
||||||
|
hostapi:'https://water-mall-new.dev.scdxtc.cn' ,// 域名配置
|
||||||
|
code:'',//缓存code
|
||||||
|
},
|
||||||
|
|
||||||
|
onLaunch() {
|
||||||
|
let that = this;
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
this.globalData.hostapi = 'https://water-mall-new.dev.scdxtc.cn' //测试
|
||||||
|
} else {
|
||||||
|
this.globalData.hostapi = 'https://water-mall-new.dev.scdxtc.cn' //正式
|
||||||
|
}
|
||||||
|
|
||||||
|
//新版登录方式
|
||||||
|
uni.login({
|
||||||
|
provider: 'weixin',
|
||||||
|
success: (result)=> {
|
||||||
|
// 获取基本信息
|
||||||
|
getInfo().then(res => {
|
||||||
|
if (res.code == 0) {
|
||||||
|
uni.setStorageSync('baseInfo',res.data)//缓存用户基本信息
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let code = result.code; //result.code
|
||||||
|
that.$requst.post('/api.login/index',{code:code}).then(res => {
|
||||||
|
if(res.code == 0){
|
||||||
|
uni.setStorageSync('token',res.data.token) //缓存token
|
||||||
|
uni.setStorageSync('userInfo',res.data.baseInfo)//缓存用户信息
|
||||||
|
that.$isResolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "@/components/uview-ui/index.scss";
|
||||||
|
/* 阿里巴巴矢量图标库 start */
|
||||||
|
@import url("./commons/icon-font.css");
|
||||||
|
/* 阿里巴巴矢量图标库 end */
|
||||||
|
|
||||||
|
/* 项目页面样式 start */
|
||||||
|
@import url("./commons/common.css");
|
||||||
|
@import url("./commons/style.css");
|
||||||
|
/* 项目页面样式 end */
|
||||||
|
|
||||||
|
/* 加载中样式 start */
|
||||||
|
@import url("./commons/loading.css");
|
||||||
|
/* 加载中样式 end */
|
||||||
|
|
||||||
|
/* 共用样式 */
|
||||||
|
@import "@/jsFile/style.scss";
|
||||||
|
</style>
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
import request from '@/jsFile/requst.js'
|
||||||
|
|
||||||
|
// 基础配置
|
||||||
|
export function getInfo(params) {
|
||||||
|
return request.get('/api.base/config', params);
|
||||||
|
}
|
||||||
|
// 获取个人信息
|
||||||
|
export function postUserInfo(data) {
|
||||||
|
return request.post('/api.user/info', data);
|
||||||
|
}
|
||||||
|
// 修改个人信息
|
||||||
|
export function postEditInfo(data) {
|
||||||
|
return request.post('/api.user/update', data);
|
||||||
|
}
|
||||||
|
// 上传文件
|
||||||
|
export function postUpload(data) {
|
||||||
|
return request.upload('/api.upload/image', data);
|
||||||
|
}
|
||||||
|
// 绑定手机号
|
||||||
|
export function postBindPhone(data) {
|
||||||
|
return request.post('/api.user/bindPhone', data);
|
||||||
|
}
|
||||||
|
// 用户协议
|
||||||
|
export function getStatement(params) {
|
||||||
|
return request.get('/api.base/statement', params);
|
||||||
|
}
|
||||||
|
// 隐私协议
|
||||||
|
export function getAbout(params) {
|
||||||
|
return request.get('/api.base/about', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 首页banner
|
||||||
|
export function getBanner(params) {
|
||||||
|
return request.get('/api.base/banner', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 商品分类
|
||||||
|
export function getGoodsCategory(params) {
|
||||||
|
return request.get('/api.goods/category', params);
|
||||||
|
}
|
||||||
|
// 商品列表
|
||||||
|
export function getSpuList(params) {
|
||||||
|
return request.get('/api.goods/list', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 商品详情
|
||||||
|
export function getGoodsDetail(params) {
|
||||||
|
return request.get('/api.goods/detail', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 最近自提点列表
|
||||||
|
export function getNearestPoint(params) {
|
||||||
|
return request.get('/api.device/getNearestPoint', params);
|
||||||
|
}
|
||||||
|
// 地址列表
|
||||||
|
export function getAddress(params) {
|
||||||
|
return request.get('/api.address/index', params);
|
||||||
|
}
|
||||||
|
// 地址详情
|
||||||
|
export function getAddressInfo(params) {
|
||||||
|
return request.get('/api.address/info', params);
|
||||||
|
}
|
||||||
|
// 编辑地址
|
||||||
|
export function postAddressSave(data) {
|
||||||
|
return request.post('/api.address/save', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除地址
|
||||||
|
export function postAddressDel(data) {
|
||||||
|
return request.post('/api.address/del', data);
|
||||||
|
}
|
||||||
|
// 提交订单
|
||||||
|
export function postOrderCreate(data) {
|
||||||
|
return request.post('/api.order/create', data);
|
||||||
|
}
|
||||||
|
// 查询是否付款
|
||||||
|
export function postOrderCheck(data) {
|
||||||
|
return request.post('/api.order/check', data);
|
||||||
|
}
|
||||||
|
// 提交订单前的商品信息
|
||||||
|
export function postPrepare(data) {
|
||||||
|
return request.post('/api.order/prepare', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 获取订单状态
|
||||||
|
export function getOrderStatus(params) {
|
||||||
|
return request.get('/api.order/status', params);
|
||||||
|
}
|
||||||
|
// 订单列表
|
||||||
|
export function getOrderMy(params) {
|
||||||
|
return request.get('/api.order/my', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单详情
|
||||||
|
export function postOrderDetail(data) {
|
||||||
|
return request.post('/api.order/detail', data);
|
||||||
|
}
|
||||||
|
// 发起支付-基于订单编号
|
||||||
|
export function postOrderPay(data) {
|
||||||
|
return request.post('/api.order/pay', data);
|
||||||
|
}
|
||||||
|
// 确认收货
|
||||||
|
export function postOrderComplete(data) {
|
||||||
|
return request.post('/api.order/complete', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 获取服务商列表
|
||||||
|
export function getSaler(params) {
|
||||||
|
return request.get('/api.device/getSaler', params);
|
||||||
|
}
|
||||||
|
// 添加水卡--绑卡
|
||||||
|
export function postCardAdd(data) {
|
||||||
|
return request.post('/api.card/add', data);
|
||||||
|
}
|
||||||
|
// 获取水卡列表
|
||||||
|
export function getCardList(params) {
|
||||||
|
return request.get('/api.card/list', params);
|
||||||
|
}
|
||||||
|
// 卡片挂失
|
||||||
|
export function postCardLost(data) {
|
||||||
|
return request.post('/api.card/lost', data);
|
||||||
|
}
|
||||||
|
// 卡片删除
|
||||||
|
export function postCardDel(data) {
|
||||||
|
return request.post('/api.card/del', data);
|
||||||
|
}
|
||||||
|
// 获取礼品卡信息
|
||||||
|
export function getGiftInfo(params) {
|
||||||
|
return request.get('/api.gift/info', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用礼品卡
|
||||||
|
export function postGiftUse(data) {
|
||||||
|
return request.post('/api.gift/use', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取最近的设备点
|
||||||
|
export function getNearest(params) {
|
||||||
|
return request.get('/api.device/getNearest', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取服务商信息
|
||||||
|
export function getCardSaler(params) {
|
||||||
|
return request.get('/api.card/saler', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 隐藏接口
|
||||||
|
// 加入购物车
|
||||||
|
export function postCartAdd(data) {
|
||||||
|
return request.post('/api.cart/add', data);
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
import request from '@/jsFile/requst-water.js'
|
||||||
|
|
||||||
|
|
||||||
|
// 获取卡片列表
|
||||||
|
export function getCardList(params) {
|
||||||
|
return request.get('/card/getlist', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取卡片详情
|
||||||
|
export function getCardinfo(params) {
|
||||||
|
return request.get('/cardinfo', params);
|
||||||
|
}
|
||||||
|
// 卡片挂失
|
||||||
|
export function getLossreport(params) {
|
||||||
|
return request.get('/card/lossreport', params);
|
||||||
|
}
|
||||||
|
// 获取卡片充值记录
|
||||||
|
export function getaddvalue(params) {
|
||||||
|
return request.get('/getaddvalue', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取卡片消费记录
|
||||||
|
export function getconsume(params) {
|
||||||
|
return request.get('/getconsume', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取充值套餐与时效套餐列表
|
||||||
|
export function getproducts(params) {
|
||||||
|
return request.get('/getproducts', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片充值
|
||||||
|
export function postAddvalue(data) {
|
||||||
|
return request.post('/addvalue', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 卡片远程灌装水
|
||||||
|
export function postNotify(data) {
|
||||||
|
return request.post('/notify', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 卡片远程停止灌装
|
||||||
|
export function getCardStop(params) {
|
||||||
|
return request.get('/card/stop', params);
|
||||||
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,155 @@
|
||||||
|
@font-face {
|
||||||
|
font-family: "iconfont"; /* Project id 3180711 */
|
||||||
|
src: url('https://at.alicdn.com/t/font_3180711_atv5gkgm4w4.woff2?t=1651830764889') format('woff2'),
|
||||||
|
url('https://at.alicdn.com/t/font_3180711_atv5gkgm4w4.woff?t=1651830764889') format('woff'),
|
||||||
|
url('https://at.alicdn.com/t/font_3180711_atv5gkgm4w4.ttf?t=1651830764889') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-family: "iconfont" !important;
|
||||||
|
font-size: 16px;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-del:before {
|
||||||
|
content: "\e718";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-cut:before {
|
||||||
|
content: "\e609";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-add:before {
|
||||||
|
content: "\e60a";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-add-picture05:before {
|
||||||
|
content: "\e639";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-add-picture04:before {
|
||||||
|
content: "\e636";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-add-picture03:before {
|
||||||
|
content: "\e642";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-add-picture02:before {
|
||||||
|
content: "\e8bc";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-add-picture01:before {
|
||||||
|
content: "\e62c";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-sandian:before {
|
||||||
|
content: "\e769";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-nothing-collection:before {
|
||||||
|
content: "\e610";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-nothing-more:before {
|
||||||
|
content: "\e624";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-nothing-data:before {
|
||||||
|
content: "\e60c";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-address-check:before {
|
||||||
|
content: "\e6c2";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-address-unchecked:before {
|
||||||
|
content: "\e623";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-navigate-now:before {
|
||||||
|
content: "\e640";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-send-goods:before {
|
||||||
|
content: "\e601";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-payment:before {
|
||||||
|
content: "\e602";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-finish:before {
|
||||||
|
content: "\e63f";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-take:before {
|
||||||
|
content: "\e649";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-refund:before {
|
||||||
|
content: "\e613";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-customer-black:before {
|
||||||
|
content: "\ec2e";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-customer:before {
|
||||||
|
content: "\e628";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-check:before {
|
||||||
|
content: "\e61e";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-del-white:before {
|
||||||
|
content: "\e61f";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-screen:before {
|
||||||
|
content: "\e60b";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-search:before {
|
||||||
|
content: "\e653";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-caidan-mo:before {
|
||||||
|
content: "\e73e";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-renwu-mo:before {
|
||||||
|
content: "\e73f";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-shop-cart:before {
|
||||||
|
content: "\e73d";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-caidan-active:before {
|
||||||
|
content: "\e608";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-renwu-acitve:before {
|
||||||
|
content: "\e67c";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-home-mo:before {
|
||||||
|
content: "\e673";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-home-active:before {
|
||||||
|
content: "\e674";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-return:before {
|
||||||
|
content: "\e600";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-next:before {
|
||||||
|
content: "\e60e";
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,505 @@
|
||||||
|
/* 图片处理 */
|
||||||
|
image {
|
||||||
|
/* 照顾低版本浏览器 如果图片外面包含了链接会有边框的问题 */
|
||||||
|
border: 0;
|
||||||
|
/* 取消图片底侧有空白缝隙的问题 ① */
|
||||||
|
vertical-align: middle;
|
||||||
|
/* 取消图片底侧有空白缝隙的问题 ② */
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 去除滚动条 */
|
||||||
|
scroll-view ::-webkit-scrollbar {
|
||||||
|
display: none !important;
|
||||||
|
width: 0 !important;
|
||||||
|
height: 0 !important;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 文字行数 */
|
||||||
|
.clips {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-wrap: break-word;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
[v-cloak] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 页面样式 */
|
||||||
|
page {
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
padding-bottom: 120rpx;
|
||||||
|
background: #f7f7f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 输入默认提示 */
|
||||||
|
::-webkit-input-placeholder {
|
||||||
|
/* WebKit browsers,webkit内核浏览器 */
|
||||||
|
color: #8f989f;
|
||||||
|
}
|
||||||
|
|
||||||
|
:-moz-placeholder {
|
||||||
|
/* Mozilla Firefox 4 to 18 */
|
||||||
|
color: #8f989f;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-moz-placeholder {
|
||||||
|
/* Mozilla Firefox 19+ */
|
||||||
|
color: #8f989f;
|
||||||
|
}
|
||||||
|
|
||||||
|
:-ms-input-placeholder {
|
||||||
|
/* Internet Explorer 10+ */
|
||||||
|
color: #8f989f;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.fs12 {
|
||||||
|
font-size: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs13 {
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs14 {
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs15 {
|
||||||
|
font-size: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs16 {
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs18 {
|
||||||
|
font-size: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs20 {
|
||||||
|
font-size: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fs25 {
|
||||||
|
font-size: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.w50 {
|
||||||
|
width: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w80 {
|
||||||
|
width: 160rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w120 {
|
||||||
|
width: 240rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w150 {
|
||||||
|
width: 300rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w200 {
|
||||||
|
width: 400rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w230 {
|
||||||
|
width: 460rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w250 {
|
||||||
|
width: 500rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w300 {
|
||||||
|
width: 600rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt5 {
|
||||||
|
margin-top: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb5 {
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml5 {
|
||||||
|
margin-left: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr5 {
|
||||||
|
margin-left: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt10 {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb10 {
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml10 {
|
||||||
|
margin-left: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr10 {
|
||||||
|
margin-right: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt15 {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb15 {
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml15 {
|
||||||
|
margin-left: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr15 {
|
||||||
|
margin-right: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt20 {
|
||||||
|
margin-top: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb20 {
|
||||||
|
margin-bottom: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml20 {
|
||||||
|
margin-left: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr20 {
|
||||||
|
margin-right: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt25 {
|
||||||
|
margin-top: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb25 {
|
||||||
|
margin-bottom: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml25 {
|
||||||
|
margin-left: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr25 {
|
||||||
|
margin-right: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt30 {
|
||||||
|
margin-top: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb30 {
|
||||||
|
margin-bottom: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml30 {
|
||||||
|
margin-left: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr30 {
|
||||||
|
margin-right: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt35 {
|
||||||
|
margin-top: 70rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb35 {
|
||||||
|
margin-bottom: 70rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml35 {
|
||||||
|
margin-left: 70rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr35 {
|
||||||
|
margin-right: 70rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt40 {
|
||||||
|
margin-top: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml40 {
|
||||||
|
margin-left: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr40 {
|
||||||
|
margin-right: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb40 {
|
||||||
|
margin-bottom: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt45 {
|
||||||
|
margin-top: 90rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml45 {
|
||||||
|
margin-left: 90rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr45 {
|
||||||
|
margin-right: 90rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb45 {
|
||||||
|
margin-bottom: 90rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mt50 {
|
||||||
|
margin-top: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ml50 {
|
||||||
|
margin-left: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mr50 {
|
||||||
|
margin-right: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb50 {
|
||||||
|
margin-bottom: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pt10 {
|
||||||
|
padding-top: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb10 {
|
||||||
|
padding-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl10 {
|
||||||
|
padding-left: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pr10 {
|
||||||
|
padding-right: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pt20 {
|
||||||
|
padding-top: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb20 {
|
||||||
|
padding-bottom: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl20 {
|
||||||
|
padding-left: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pr20 {
|
||||||
|
padding-right: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pt25 {
|
||||||
|
padding-top: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb25 {
|
||||||
|
padding-bottom: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl25 {
|
||||||
|
padding-left: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pr25 {
|
||||||
|
padding-right: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pt30 {
|
||||||
|
padding-top: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb30 {
|
||||||
|
padding-bottom: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl30 {
|
||||||
|
padding-left: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pr30 {
|
||||||
|
padding-right: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pt40 {
|
||||||
|
padding-top: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb40 {
|
||||||
|
padding-bottom: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl40 {
|
||||||
|
padding-left: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pr40 {
|
||||||
|
padding-right: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pt50 {
|
||||||
|
padding-top: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb50 {
|
||||||
|
padding-bottom: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pl50 {
|
||||||
|
padding-left: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pr50 {
|
||||||
|
padding-right: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clr {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fl {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fr {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tc {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tl {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tr {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.pr {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pa {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red {
|
||||||
|
color: #ce0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.white {
|
||||||
|
color: #FFF !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.black {
|
||||||
|
color: #000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gray {
|
||||||
|
color: #CCC !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
color: #999 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orange {
|
||||||
|
color: #F60 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.green {
|
||||||
|
color: #008000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blue {
|
||||||
|
color: #06F !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bf5 {
|
||||||
|
background-color: #f5f5f5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.f5 {
|
||||||
|
background: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bred {
|
||||||
|
background: #ce0000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bwhite {
|
||||||
|
background: #FFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bblack {
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgray {
|
||||||
|
background: #CCC;
|
||||||
|
}
|
||||||
|
|
||||||
|
.borange {
|
||||||
|
background: #F60;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bgreen {
|
||||||
|
background: #008000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bblue {
|
||||||
|
background: #06F;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.bd-bottom {
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
.lotus-address-picker {
|
||||||
|
font-size: 26rpx;
|
||||||
|
padding-top: 30rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
line-height: normal;
|
||||||
|
padding-right: 30rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.lotus-address-picker-box {
|
||||||
|
/*display: -webkit-box;
|
||||||
|
display: -webkit-flex;*/
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding-top: 10rpx;
|
||||||
|
padding-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
.lotus-address-picker-box-item {
|
||||||
|
height: 600upx;
|
||||||
|
overflow-y: auto;
|
||||||
|
width: 33.333%;
|
||||||
|
padding-left: 20rpx;
|
||||||
|
padding-right: 20rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.lotus-address-picker2 {
|
||||||
|
color: #03affb;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.lotus-address-picker2:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 65%;
|
||||||
|
transform: translateY(-35%) rotate(-45deg);
|
||||||
|
width: 20rpx;
|
||||||
|
height: 10rpx;
|
||||||
|
border-left-width: 4rpx;
|
||||||
|
border-bottom-width: 4rpx;
|
||||||
|
border-left-style: solid;
|
||||||
|
border-bottom-style: solid;
|
||||||
|
border-left-color: #03affb;
|
||||||
|
border-bottom-color: #03affb;
|
||||||
|
}
|
||||||
|
.lotus-address-mask {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 999;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
.lotus-address-box {
|
||||||
|
background: #fff;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.lotus-address-action {
|
||||||
|
font-size: 30rpx;
|
||||||
|
/*display: -webkit-box;
|
||||||
|
display: -webkit-flex;*/
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 25rpx 30rpx;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.lotus-address-action:after {
|
||||||
|
content: " ";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 1px;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
color: #eee;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
transform: scaleY(0.5);
|
||||||
|
}
|
||||||
|
.lotus-address-action:before {
|
||||||
|
content: " ";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 1px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
color: #eee;
|
||||||
|
transform-origin: 0 100%;
|
||||||
|
transform: scaleY(0.5);
|
||||||
|
}
|
||||||
|
.lotus-address-action-cancel {
|
||||||
|
color: #969696;
|
||||||
|
}
|
||||||
|
.lotus-address-action-affirm {
|
||||||
|
color: #03affb;
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,233 @@
|
||||||
|
<template>
|
||||||
|
<!--地址picker-->
|
||||||
|
<view :status="checkStatus" v-if="lotusAddressData.visible" class="lotus-address-mask">
|
||||||
|
<view :class="lotusAddressData.visible?'lotus-address-box':'lotus-address-box lotus-address-box-out'">
|
||||||
|
<view class="lotus-address-action">
|
||||||
|
<text @tap="cancelPicker" class="lotus-address-action-cancel">取消</text>
|
||||||
|
<text @tap="chosedVal" class="lotus-address-action-affirm">确认</text>
|
||||||
|
</view>
|
||||||
|
<view class="lotus-address-picker-box">
|
||||||
|
<!--省-->
|
||||||
|
<scroll-view scroll-y :scroll-into-view="'pid'+pChoseIndex" class="lotus-address-picker-box-item">
|
||||||
|
<view @tap="clickPicker(0,pIndex,pItem);" :id="'pid'+pIndex" :class="pIndex === pChoseIndex?'lotus-address-picker lotus-address-picker2':'lotus-address-picker'" v-for="(pItem,pIndex) in province" :key="pIndex">{{pItem}}</view>
|
||||||
|
</scroll-view>
|
||||||
|
<!--市-->
|
||||||
|
<scroll-view scroll-y :scroll-into-view="'cid'+cChoseIndex" class="lotus-address-picker-box-item">
|
||||||
|
<view @tap="clickPicker(1,cIndex,cItem);" :id="'cid'+cIndex" :class="cIndex === cChoseIndex?'lotus-address-picker lotus-address-picker2':'lotus-address-picker'" v-for="(cItem,cIndex) in city" :key="cIndex">{{cItem}}</view>
|
||||||
|
</scroll-view>
|
||||||
|
<!--区-->
|
||||||
|
<scroll-view scroll-y :scroll-into-view="'tid'+tChoseIndex" class="lotus-address-picker-box-item">
|
||||||
|
<view @tap="clickPicker(2,tIndex,tItem);" :id="'tid'+tIndex" :class="tIndex === tChoseIndex?'lotus-address-picker lotus-address-picker2':'lotus-address-picker'" v-for="(tItem,tIndex) in town" :key="tIndex">{{tItem}}</view>
|
||||||
|
</scroll-view>
|
||||||
|
<!--区END-->
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!--地址picker END-->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {lotusAddressJson} from "./address-one.js";
|
||||||
|
export default {
|
||||||
|
props:['lotusAddressData'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
province:[],
|
||||||
|
city:[],
|
||||||
|
town:[],
|
||||||
|
provinceName:'',
|
||||||
|
cityName:'',
|
||||||
|
townName:'',
|
||||||
|
type:0,//0新增1编辑
|
||||||
|
pChoseIndex:-1,
|
||||||
|
cChoseIndex:-1,
|
||||||
|
tChoseIndex:-1
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
//取消
|
||||||
|
cancelPicker(){
|
||||||
|
const provinceCode = this.getTarId(this.provinceName);
|
||||||
|
const cityCode = this.getTarId(this.cityName);
|
||||||
|
const townCode = this.getTarId(this.townName);
|
||||||
|
this.visible = false;
|
||||||
|
this.$emit("choseVal",{
|
||||||
|
province:this.provinceName,
|
||||||
|
provinceCode,
|
||||||
|
city:this.cityName,
|
||||||
|
cityCode,
|
||||||
|
town:this.townName,
|
||||||
|
townCode,
|
||||||
|
isChose:0,
|
||||||
|
visible:false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//获取最后选择的省市区的值
|
||||||
|
chosedVal() {
|
||||||
|
this.type = 1;
|
||||||
|
const provinceCode = this.getTarId(this.provinceName);
|
||||||
|
const cityCode = this.getTarId(this.cityName);
|
||||||
|
const townCode = this.getTarId(this.townName);
|
||||||
|
this.visible = false;
|
||||||
|
let isChose = 0;
|
||||||
|
//已选省市区 isChose = 1
|
||||||
|
if((this.provinceName&&this.cityName)||(this.provinceName&&this.cityName&&this.townName)){
|
||||||
|
isChose = 1;
|
||||||
|
}
|
||||||
|
this.$emit("choseVal",{
|
||||||
|
province:this.provinceName,
|
||||||
|
provinceCode,
|
||||||
|
city:this.cityName,
|
||||||
|
cityCode,
|
||||||
|
town:this.townName,
|
||||||
|
townCode,
|
||||||
|
isChose,
|
||||||
|
visible:false
|
||||||
|
});
|
||||||
|
},
|
||||||
|
//获取省市区value
|
||||||
|
getTarId(name,type){
|
||||||
|
let id = 0;
|
||||||
|
lotusAddressJson.map((item,index)=>{
|
||||||
|
if(item.name === name){
|
||||||
|
id = item.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return id;
|
||||||
|
},
|
||||||
|
//获取市数据
|
||||||
|
getCityArr(parentId){
|
||||||
|
let city = [];
|
||||||
|
lotusAddressJson.map((item,index)=>{
|
||||||
|
if(item.parent === parentId){
|
||||||
|
city.push(item.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return city;
|
||||||
|
},
|
||||||
|
//获取区数据
|
||||||
|
getTownArr(parentId){
|
||||||
|
let town = [];
|
||||||
|
lotusAddressJson.map((item,index)=>{
|
||||||
|
if(index>34&&item.parent === parentId){
|
||||||
|
town.push(item.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return town;
|
||||||
|
},
|
||||||
|
//初始化数据
|
||||||
|
initFn(){
|
||||||
|
if(!this.province.length){
|
||||||
|
lotusAddressJson.map((item,index)=>{
|
||||||
|
if(index<=34){
|
||||||
|
this.province.push(item.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//已选择省市区,高亮显示对应选择省市区
|
||||||
|
const p = this._props.lotusAddressData.provinceName;
|
||||||
|
const c = this._props.lotusAddressData.cityName;
|
||||||
|
const t = this._props.lotusAddressData.townName;
|
||||||
|
//已选省
|
||||||
|
if(p){
|
||||||
|
this.pChoseIndex = this.getTarIndex(this.province,p);
|
||||||
|
}
|
||||||
|
//已选市
|
||||||
|
if(p&&c){
|
||||||
|
const pid = this.getTarId(p);
|
||||||
|
this.city = this.getCityArr(pid);
|
||||||
|
this.cChoseIndex = this.getTarIndex(this.city,c);
|
||||||
|
}
|
||||||
|
//已选区
|
||||||
|
if(p&&c&&t){
|
||||||
|
const cid= this.getTarId(c);
|
||||||
|
this.town = this.getTownArr(cid);
|
||||||
|
this.tChoseIndex = this.getTarIndex(this.town,t);
|
||||||
|
}
|
||||||
|
//未选省市区
|
||||||
|
if(!p&&!c&&!t){
|
||||||
|
this.pChoseIndex = -1;
|
||||||
|
this.cChoseIndex = -1;
|
||||||
|
this.tChoseIndex = -1;
|
||||||
|
this.city = [];
|
||||||
|
this.town = [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//获取已选省市区
|
||||||
|
getChosedData(){
|
||||||
|
const pid = this.getTarId(this.provinceName,'province');
|
||||||
|
this.city = this.getCityArr(pid);
|
||||||
|
const cid= this.getTarId(this.cityName,'city');
|
||||||
|
this.town = this.getTownArr(cid);
|
||||||
|
//已选省市区获取对应index
|
||||||
|
if(this.provinceName){
|
||||||
|
this.pChoseIndex = this.getTarIndex(this.province,this.provinceName);
|
||||||
|
}
|
||||||
|
if(this.cityName){
|
||||||
|
this.cChoseIndex = this.getTarIndex(this.city,this.cityName);
|
||||||
|
}
|
||||||
|
if(this.townName){
|
||||||
|
this.tChoseIndex = this.getTarIndex(this.town,this.townName);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//选择省市区交互
|
||||||
|
clickPicker(type,index,name){
|
||||||
|
//省
|
||||||
|
if(type === 0){
|
||||||
|
this.pChoseIndex = index;
|
||||||
|
this.provinceName = name;
|
||||||
|
this.cChoseIndex = -1;
|
||||||
|
this.tChoseIndex = -1;
|
||||||
|
this.cityName = '';
|
||||||
|
this.townName = '';
|
||||||
|
}
|
||||||
|
//市
|
||||||
|
if(type ===1){
|
||||||
|
this.cChoseIndex = index;
|
||||||
|
this.cityName = name;
|
||||||
|
this.tChoseIndex = -1;
|
||||||
|
this.townName = '';
|
||||||
|
}
|
||||||
|
//区
|
||||||
|
if(type === 2){
|
||||||
|
this.tChoseIndex = index;
|
||||||
|
this.townName = name;
|
||||||
|
}
|
||||||
|
//获取省市区数据
|
||||||
|
this.getChosedData();
|
||||||
|
},
|
||||||
|
//获取已选省市区index
|
||||||
|
getTarIndex(arr,tarName){
|
||||||
|
let cIndex = 0;
|
||||||
|
arr.map((item,index)=>{
|
||||||
|
if(item === tarName){
|
||||||
|
cIndex = index;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return cIndex;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed:{
|
||||||
|
checkStatus(){
|
||||||
|
let t = null;
|
||||||
|
const _this = this;
|
||||||
|
if(!_this.visible){
|
||||||
|
_this.visible = _this._props.lotusAddressData.visible;
|
||||||
|
//获取省市区
|
||||||
|
_this.provinceName = _this._props.lotusAddressData.provinceName;
|
||||||
|
_this.cityName = _this._props.lotusAddressData.cityName;
|
||||||
|
_this.townName = _this._props.lotusAddressData.townName;
|
||||||
|
//生成初始化数据
|
||||||
|
_this.initFn();
|
||||||
|
t = _this.visible;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
@import "./address-one.css";
|
||||||
|
</style>
|
|
@ -0,0 +1,112 @@
|
||||||
|
<template>
|
||||||
|
<view class="foot-bar">
|
||||||
|
<!-- 底部导航 -->
|
||||||
|
<view class="item" :style="{'width':`calc(100%/${footBarList.length})`}" @tap="chooseEv(index,item.url)" v-for="(item,index) in footBarList" :key="index">
|
||||||
|
<view class="icon">
|
||||||
|
<image :src="current==index?item.activePath:item.normalPath" mode="heightFix"></image>
|
||||||
|
</view>
|
||||||
|
<view class="title" :style="{'color':current == index? '#49a149' : '#a0a5af'}">{{item.title}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name:'foot-bar',
|
||||||
|
props:{
|
||||||
|
// 当前选中项
|
||||||
|
current:{
|
||||||
|
type:Number,
|
||||||
|
default:0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
footBarList:[
|
||||||
|
{
|
||||||
|
normalPath: '/static/foot-bar/index.png',
|
||||||
|
activePath: '/static/foot-bar/index-active.png',
|
||||||
|
title:'首页',
|
||||||
|
url:'/pages/home/home'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
normalPath: '/static/foot-bar/cate.png',
|
||||||
|
activePath: '/static/foot-bar/cate-active.png',
|
||||||
|
title:'商城',
|
||||||
|
url:'/pages/cate/cate'
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// normalPath: '/static/foot-bar/integral.png',
|
||||||
|
// activePath: '/static/foot-bar/integral-active.png',
|
||||||
|
// title:'积分',
|
||||||
|
// url:'/pages/integration/integration'
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
normalPath: '/static/foot-bar/my.png',
|
||||||
|
activePath: '/static/foot-bar/my-active.png',
|
||||||
|
title:'我的',
|
||||||
|
url:'/pages/my/my'
|
||||||
|
}
|
||||||
|
], //底部列表
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 获取底部高度
|
||||||
|
const query = wx.createSelectorQuery().in(this);
|
||||||
|
query.select('.foot-bar').boundingClientRect((rect) => {
|
||||||
|
uni.setStorageSync('footHeight',rect.height)
|
||||||
|
}).exec()
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
// 跳转tabbar
|
||||||
|
|
||||||
|
chooseEv(index,url){
|
||||||
|
// if(this.$toolAll.tools.judgeAuth()) {
|
||||||
|
// uni.reLaunch({
|
||||||
|
// url:'',
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
uni.reLaunch({
|
||||||
|
url:url
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.foot-bar{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height:110rpx;
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: 0 0 16rpx rgba(146, 146, 146, .06);
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 99;
|
||||||
|
}
|
||||||
|
.foot-bar .item{
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-items: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.foot-bar .icon{
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: 39rpx;
|
||||||
|
}
|
||||||
|
.foot-bar .icon image{
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.foot-bar .title{
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 12rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,231 @@
|
||||||
|
<template>
|
||||||
|
<view class="goods-list">
|
||||||
|
<view class="goods-item" :class="showType!==''?showType:''" v-for="(item,index) in goodsList" :key="index" @tap.stop="toDetail(item.id)">
|
||||||
|
<!-- <view class="tag" :style="{backgroundColor:item1}" v-if="item.tag!==''&&item.tag==index1" v-for="(item1,index1) in tag_bg_color" :key="index1">
|
||||||
|
{{item.tag}}
|
||||||
|
</view> -->
|
||||||
|
<!-- <view class="tag tag-green" v-else-if="">放心购</view> -->
|
||||||
|
<view class="img">
|
||||||
|
<image :src="item.src" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
|
<view class="msg">
|
||||||
|
<view class="title clips">{{item.title}}</view>
|
||||||
|
<view class="price-bg">
|
||||||
|
<view class="price">
|
||||||
|
<view class="price-item" v-if="item.price != 0">
|
||||||
|
<text>¥</text>
|
||||||
|
<text>{{item.price.substr(0,item.price.indexOf('.'))}}</text>
|
||||||
|
<text>{{item.price.substr(item.price.indexOf('.'),item.price.length)}}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
<view class="btn">
|
||||||
|
<view class="icon-spot" v-if="!ifShowCart">
|
||||||
|
<image src="/static/icon/icon-spot.png" mode="widthFix"></image>
|
||||||
|
</view>
|
||||||
|
<view class="icon-cart" v-else @tap.stop="addCart(item.sku_id)">
|
||||||
|
<image src="/static/icon/icon-add-cart.png" mode="widthFix"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name:'goods-list',
|
||||||
|
props:{
|
||||||
|
// 是否展示购物车
|
||||||
|
ifShowCart:{
|
||||||
|
type:Boolean,
|
||||||
|
default:true
|
||||||
|
},
|
||||||
|
// 是否展示购物车
|
||||||
|
ifRefreshCart:{
|
||||||
|
type:Boolean,
|
||||||
|
default:false
|
||||||
|
},
|
||||||
|
// 展示风格
|
||||||
|
showType:{
|
||||||
|
type:String,
|
||||||
|
default:'' //搜索search-column 分类cate-column
|
||||||
|
},
|
||||||
|
// 商品列表
|
||||||
|
goodsList:{
|
||||||
|
type:Array,
|
||||||
|
default:[]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tag_bg_color:{}, //tag颜色
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
toDetail(id){
|
||||||
|
uni.navigateTo({
|
||||||
|
url:`/pagesB/goodsDetail/goodsDetail?id=${id}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.goods-list{
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.goods-item{
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: calc(50% - 9rpx);
|
||||||
|
padding: 18rpx;
|
||||||
|
margin-bottom: 18rpx;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
background-color: #ffffff;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item .tag{
|
||||||
|
line-height: 34rpx;
|
||||||
|
padding: 0 8rpx;
|
||||||
|
background-color: #d4996d;
|
||||||
|
font-size: 20rpx;
|
||||||
|
text-align: center;
|
||||||
|
color: #ffffff;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
.goods-item .tag-green{
|
||||||
|
background-color: #4cc474;
|
||||||
|
}
|
||||||
|
.goods-item .img {
|
||||||
|
border: 1px solid #ececec;
|
||||||
|
}
|
||||||
|
.goods-item .img,
|
||||||
|
.goods-item .img image{
|
||||||
|
width: 290rpx;
|
||||||
|
height: 290rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.goods-item .msg{
|
||||||
|
margin-top: 30rpx;
|
||||||
|
}
|
||||||
|
.goods-item .msg .title{
|
||||||
|
font-size: 28rpx;
|
||||||
|
line-height: 40rpx;
|
||||||
|
min-height: 80rpx;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
}
|
||||||
|
.goods-item .msg .price-bg{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 40rpx;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
.goods-item .msg .price{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
max-width: calc(100% - 36rpx);
|
||||||
|
}
|
||||||
|
.goods-item .msg .price-item{
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
.goods-item .msg .price-item text{
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 30rpx;
|
||||||
|
color: #f72e2e;
|
||||||
|
}
|
||||||
|
.goods-item .msg .price-item text:nth-of-type(2){
|
||||||
|
font-size: 34rpx;
|
||||||
|
line-height: 40rpx;
|
||||||
|
}
|
||||||
|
.goods-item .icon-spot image{
|
||||||
|
width: 32rpx;
|
||||||
|
height: 7rpx;
|
||||||
|
}
|
||||||
|
.goods-item .icon-cart image{
|
||||||
|
width: 36rpx;
|
||||||
|
height: 35rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 搜索页面样式 */
|
||||||
|
.search-column{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20rpx 20rpx 0;
|
||||||
|
border-radius: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.search-column .img{
|
||||||
|
width: 195rpx;
|
||||||
|
height: 195rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
.search-column .img image{
|
||||||
|
width: 195rpx;
|
||||||
|
height: 195rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-column .msg{
|
||||||
|
width: calc(100% - 205rpx);
|
||||||
|
height: 195rpx;
|
||||||
|
border-bottom: 1px solid #eaeaea;
|
||||||
|
padding-bottom: 20rpx;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.search-column .msg .title{
|
||||||
|
margin-top: 10rpx;
|
||||||
|
}
|
||||||
|
.search-column .tag{
|
||||||
|
left: 20rpx;
|
||||||
|
top: 20rpx;
|
||||||
|
border-radius: 10rpx 0 0 0;
|
||||||
|
}
|
||||||
|
.search-column .msg .price-bg{
|
||||||
|
margin-top: 46rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分类页面样式 */
|
||||||
|
.cate-column{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20rpx 0;
|
||||||
|
border-radius: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.cate-column .img,
|
||||||
|
.cate-column .img image{
|
||||||
|
width: 155rpx;
|
||||||
|
height: 155rpx;
|
||||||
|
}
|
||||||
|
.cate-column .msg{
|
||||||
|
width: calc(100% - 170rpx);
|
||||||
|
height: 155rpx;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
.cate-column .msg .title{
|
||||||
|
margin-top: 6rpx;
|
||||||
|
}
|
||||||
|
.cate-column .tag{
|
||||||
|
left: 0;
|
||||||
|
top: 20rpx;
|
||||||
|
border-radius: 10rpx 0 0 0;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,350 @@
|
||||||
|
<template>
|
||||||
|
<view class="waterfalls-box goods-list" :style="{ height: height + 'px' }">
|
||||||
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
|
<view v-for="(item, index) of list" class="waterfalls-list goods-item" :key="item[idKey]"
|
||||||
|
:id="'waterfalls-list-id-' + item[idKey]" :ref="'waterfalls-list-id-' + item[idKey]" :style="{
|
||||||
|
'--offset': offset + 'px',
|
||||||
|
'--cols': cols,
|
||||||
|
top: allPositionArr[index].top || 0,
|
||||||
|
left: allPositionArr[index].left || 0,
|
||||||
|
}" @click="$emit('wapper-lick', item)">
|
||||||
|
|
||||||
|
<image class="waterfalls-list-image" mode="widthFix" :class="{ single }" :style="imageStyle"
|
||||||
|
:src="item[imageSrcKey] || ' '" @load="imageLoadHandle(index)" @error="imageLoadHandle(index)"
|
||||||
|
@click="toDetail(item.id)" />
|
||||||
|
<slot name="slot{{index}}" />
|
||||||
|
|
||||||
|
<view class="msg">
|
||||||
|
<view class="title clips">{{item.title}}</view>
|
||||||
|
<view class="price-bg">
|
||||||
|
<view class="price">
|
||||||
|
<view class="price-item" v-if="item.price != 0">
|
||||||
|
<text>¥</text>
|
||||||
|
<text>{{item.price.substr(0,item.price.indexOf('.'))}}</text>
|
||||||
|
<text>{{item.price.substr(item.price.indexOf('.'),item.price.length)}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="btn">
|
||||||
|
<view class="icon-spot">
|
||||||
|
<image src="/static/icon/icon-spot.png" mode="widthFix"></image>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
<!-- #ifndef MP-WEIXIN -->
|
||||||
|
<view v-for="(item, index) of list" class="waterfalls-list" :key="item[idKey]"
|
||||||
|
:id="'waterfalls-list-id-' + item[idKey]" :ref="'waterfalls-list-id-' + item[idKey]" :style="{
|
||||||
|
'--offset': offset + 'px',
|
||||||
|
'--cols': cols,
|
||||||
|
...listStyle,
|
||||||
|
...(allPositionArr[index] || {}),
|
||||||
|
}" @click="$emit('wapper-lick', item)">
|
||||||
|
<image class="waterfalls-list-image" :class="{ single }" mode="widthFix" :style="imageStyle"
|
||||||
|
:src="item[imageSrcKey] || ' '" @load="imageLoadHandle(index)" @error="imageLoadHandle(index)"
|
||||||
|
@click="$emit('image-click', item)" />
|
||||||
|
<slot v-bind="item" />
|
||||||
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
// offset 间距,单位为 px
|
||||||
|
offset: {
|
||||||
|
type: Number,
|
||||||
|
default: 10
|
||||||
|
},
|
||||||
|
// 列表渲染的 key 的键名,值必须唯一,默认为 id
|
||||||
|
idKey: {
|
||||||
|
type: String,
|
||||||
|
default: "id"
|
||||||
|
},
|
||||||
|
// 图片 src 的键名
|
||||||
|
imageSrcKey: {
|
||||||
|
type: String,
|
||||||
|
default: "image_url"
|
||||||
|
},
|
||||||
|
// 列数
|
||||||
|
cols: {
|
||||||
|
type: Number,
|
||||||
|
default: 2,
|
||||||
|
validator: (num) => num >= 2
|
||||||
|
},
|
||||||
|
imageStyle: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
// 是否展示购物车
|
||||||
|
ifShowCart: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否是单独的渲染图片的样子,只控制图片圆角而已
|
||||||
|
single: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
listStyle: {
|
||||||
|
type: Object
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
topArr: [], // left, right 多个时依次表示第几列的数据
|
||||||
|
allPositionArr: [], // 保存所有的位置信息
|
||||||
|
allHeightArr: [], // 保存所有的 height 信息
|
||||||
|
height: 0, // 外层包裹高度
|
||||||
|
oldNum: 0,
|
||||||
|
num: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.refresh();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
imageLoadHandle(index) {
|
||||||
|
const id = "waterfalls-list-id-" + this.list[index][this.idKey],
|
||||||
|
query = uni.createSelectorQuery().in(this);
|
||||||
|
query
|
||||||
|
.select("#" + id)
|
||||||
|
.fields({
|
||||||
|
size: true
|
||||||
|
}, (data) => {
|
||||||
|
this.num++;
|
||||||
|
this.$set(this.allHeightArr, index, data.height);
|
||||||
|
if (this.num === this.list.length) {
|
||||||
|
for (let i = this.oldNum; i < this.num; i++) {
|
||||||
|
const getTopArrMsg = () => {
|
||||||
|
let arrtmp = [...this.topArr].sort((a, b) => a - b);
|
||||||
|
return {
|
||||||
|
shorterIndex: this.topArr.indexOf(arrtmp[0]),
|
||||||
|
shorterValue: arrtmp[0],
|
||||||
|
longerIndex: this.topArr.indexOf(arrtmp[this.cols - 1]),
|
||||||
|
longerValue: arrtmp[this.cols - 1],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const {
|
||||||
|
shorterIndex,
|
||||||
|
shorterValue
|
||||||
|
} = getTopArrMsg();
|
||||||
|
const position = {
|
||||||
|
top: shorterValue + "px",
|
||||||
|
left: (data.width + this.offset) * shorterIndex + "px",
|
||||||
|
};
|
||||||
|
this.$set(this.allPositionArr, i, position);
|
||||||
|
this.topArr[shorterIndex] =
|
||||||
|
shorterValue + this.allHeightArr[i] + this.offset;
|
||||||
|
this.height = getTopArrMsg().longerValue - this.offset;
|
||||||
|
}
|
||||||
|
this.oldNum = this.num;
|
||||||
|
// 完成渲染 emit `image-load` 事件
|
||||||
|
this.$emit("image-load");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.exec();
|
||||||
|
},
|
||||||
|
refresh() {
|
||||||
|
let arr = [];
|
||||||
|
for (let i = 0; i < this.cols; i++) {
|
||||||
|
arr.push(0);
|
||||||
|
}
|
||||||
|
this.topArr = arr;
|
||||||
|
this.num = 0;
|
||||||
|
this.oldNum = 0;
|
||||||
|
this.height = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 查看详情
|
||||||
|
toDetail(id){
|
||||||
|
uni.navigateTo({
|
||||||
|
url:`/pagesB/goodsDetail/goodsDetail?id=${id}`
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
// 这里可以自行配置
|
||||||
|
$border-radius: 6px;
|
||||||
|
|
||||||
|
.waterfalls-box {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.waterfalls-list {
|
||||||
|
width: calc((100% - var(--offset) * (var(--cols) - 1)) / var(--cols));
|
||||||
|
position: absolute;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: $border-radius;
|
||||||
|
// 防止刚开始渲染时堆叠在第一幅图的地方
|
||||||
|
left: calc(-50% - var(--offset));
|
||||||
|
|
||||||
|
.waterfalls-list-image {
|
||||||
|
width: 100%;
|
||||||
|
background: #ccc;
|
||||||
|
will-change: transform;
|
||||||
|
border-radius: $border-radius $border-radius 0 0;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
&.single {
|
||||||
|
border-radius: $border-radius;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item .tag {
|
||||||
|
line-height: 34rpx;
|
||||||
|
padding: 0 8rpx;
|
||||||
|
background-color: #d4996d;
|
||||||
|
font-size: 20rpx;
|
||||||
|
text-align: center;
|
||||||
|
color: #ffffff;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item .tag-green {
|
||||||
|
background-color: #4cc474;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item .msg {
|
||||||
|
padding:24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item .msg .title {
|
||||||
|
font-size: 28rpx;
|
||||||
|
line-height: 40rpx;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item .msg .price-bg {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 40rpx;
|
||||||
|
margin-top: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item .msg .price {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
max-width: calc(100% - 36rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item .msg .price-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item .msg .price-item text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 30rpx;
|
||||||
|
color: #f72e2e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item .msg .price-item text:nth-of-type(2) {
|
||||||
|
font-size: 34rpx;
|
||||||
|
line-height: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item .icon-spot image {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 7rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.goods-item .icon-cart image {
|
||||||
|
width: 36rpx;
|
||||||
|
height: 35rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 搜索页面样式 */
|
||||||
|
.search-column {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20rpx 20rpx 0;
|
||||||
|
border-radius: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-column .img {
|
||||||
|
width: 195rpx;
|
||||||
|
height: 195rpx;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-column .img image {
|
||||||
|
width: 195rpx;
|
||||||
|
height: 195rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-column .msg {
|
||||||
|
width: calc(100% - 205rpx);
|
||||||
|
height: 195rpx;
|
||||||
|
border-bottom: 1px solid #eaeaea;
|
||||||
|
padding-bottom: 20rpx;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-column .msg .title {
|
||||||
|
margin-top: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-column .tag {
|
||||||
|
left: 20rpx;
|
||||||
|
top: 20rpx;
|
||||||
|
border-radius: 10rpx 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-column .msg .price-bg {
|
||||||
|
margin-top: 46rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分类页面样式 */
|
||||||
|
.cate-column {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20rpx 0;
|
||||||
|
border-radius: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cate-column .img,
|
||||||
|
.cate-column .img image {
|
||||||
|
width: 155rpx;
|
||||||
|
height: 155rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cate-column .msg {
|
||||||
|
width: calc(100% - 170rpx);
|
||||||
|
height: 155rpx;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cate-column .msg .title {
|
||||||
|
margin-top: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cate-column .tag {
|
||||||
|
left: 0;
|
||||||
|
top: 20rpx;
|
||||||
|
border-radius: 10rpx 0 0 0;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,41 @@
|
||||||
|
<template>
|
||||||
|
<view class="nothing">
|
||||||
|
<view class="nothing-box">
|
||||||
|
<image v-if="imgSrc!=''" class="nothing-img" :src="imgSrc" mode="aspectFill" lazy-load></image>
|
||||||
|
<i class="iconImg icon"
|
||||||
|
:class="['icon-nothing-more','icon-nothing-data','icon-nothing-collection'][currentType]"></i>
|
||||||
|
<view v-if="currentType!=1" class="nothing-con">{{content}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name:"nothing-page",
|
||||||
|
props:{
|
||||||
|
imgSrc:{ // 没有更多的图片
|
||||||
|
type:String,
|
||||||
|
default:''
|
||||||
|
},
|
||||||
|
content:{ // 没有更多的描述
|
||||||
|
type:String,
|
||||||
|
default:'暂无内容'
|
||||||
|
},
|
||||||
|
currentType:{ // 暂无更多 icon 图标
|
||||||
|
type:Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.nothing{position: fixed;top: 0;bottom: 0;left: 0;right: 0;display: flex;justify-content: center;align-items: center;}
|
||||||
|
.nothing-box{display: flex;justify-content: center;flex-direction: column;align-items: center;}
|
||||||
|
.nothing-box .nothing-img{width: 470rpx;height: 270rpx;}
|
||||||
|
.iconImg {font-size: 280rpx;color: #999999;}
|
||||||
|
.nothing-con{font-size: 24rpx;font-family: PingFang SC;font-weight: 500;color: #999999;}
|
||||||
|
</style>
|
|
@ -0,0 +1,54 @@
|
||||||
|
<template>
|
||||||
|
<view :style="{
|
||||||
|
color: textColor,
|
||||||
|
fontSize: textFontSize,
|
||||||
|
fontWeight: `${ ifBold ? 'bold' : 0 }`,
|
||||||
|
textAlign: `${ ifCenter ? 'center' : 'left' }`,
|
||||||
|
padding: paddingStr
|
||||||
|
}">{{textStr}}</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name:"pitera",
|
||||||
|
props:{
|
||||||
|
// 内容
|
||||||
|
textStr: {
|
||||||
|
type:String,
|
||||||
|
default:'-- NO MORE --'
|
||||||
|
},
|
||||||
|
// 字体颜色
|
||||||
|
textColor: {
|
||||||
|
type:String,
|
||||||
|
default:'#999999'
|
||||||
|
},
|
||||||
|
// 字体大小
|
||||||
|
textFontSize: {
|
||||||
|
type: String,
|
||||||
|
default: '24rpx'
|
||||||
|
},
|
||||||
|
// 是否加粗
|
||||||
|
ifBold: {
|
||||||
|
type:Boolean,
|
||||||
|
default:false
|
||||||
|
},
|
||||||
|
// 是否居中
|
||||||
|
ifCenter: {
|
||||||
|
type:Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 内边距的值
|
||||||
|
paddingStr: {
|
||||||
|
type:String,
|
||||||
|
default:'20rpx'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,187 @@
|
||||||
|
<template>
|
||||||
|
<view class="status-box" :style="{marginBottom:marginBottom,background:backgroudColor}">
|
||||||
|
<!-- 网络、电量栏 -->
|
||||||
|
<view :style="{height:statusBarHeight+'px'}"></view>
|
||||||
|
<!-- 头部状态栏 -->
|
||||||
|
<view class="status-nav" :style="{height:navBarHeight}">
|
||||||
|
<!-- 返回键 -->
|
||||||
|
<view class="left-box" @tap="backEv" v-if="ifReturn" :style="{height:navBarHeight}">
|
||||||
|
<slot name="leftcontent">
|
||||||
|
<i class="icon icon-return" style="font-size: 38rpx;" :style="{color:returnColor}"></i>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
<!-- 标题 -->
|
||||||
|
<view class="tab-title" :style="{color:titleColor,fontWeight:ifBold?'bold':'',justifyContent:ifCenter?'center':'',padding:ifCenter?'0px':`${ifReturn ?'0 38':'0 15'}px`}">
|
||||||
|
<view class="title-box" :class="['','clips1','clips2'][clipNumber*1]" :style="{maxWidth: ifCenter ?'360rpx':'70%'}">
|
||||||
|
<!-- 有网络 -->
|
||||||
|
<view v-if="ifTitle && ifNet">{{navBarTitle}}</view>
|
||||||
|
<!-- 无网络 -->
|
||||||
|
<view v-if="!ifNet">{{netText}}<text @tap="refreshEv" style="color: #1f6fbb;margin-left: 20rpx;">刷新</text></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<!-- 右侧图标 -->
|
||||||
|
<view class="right-box" :style="{height:navBarHeight}">
|
||||||
|
<slot name="rightcontent"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'status-nav',
|
||||||
|
props: {
|
||||||
|
//状态栏、导航栏背景颜色
|
||||||
|
backgroudColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#f7f7f7'
|
||||||
|
},
|
||||||
|
// 默认导航栏高度
|
||||||
|
navBarHeight: {
|
||||||
|
type: String,
|
||||||
|
default: '50px'
|
||||||
|
},
|
||||||
|
//是否显示返回键
|
||||||
|
ifReturn: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 返回键颜色
|
||||||
|
returnColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#333333'
|
||||||
|
},
|
||||||
|
//是否显示标题
|
||||||
|
ifTitle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 导航栏标题
|
||||||
|
navBarTitle: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 标题最多几行显示
|
||||||
|
clipNumber: {
|
||||||
|
type: String,
|
||||||
|
default: '1'
|
||||||
|
},
|
||||||
|
//标题颜色
|
||||||
|
titleColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#333333'
|
||||||
|
},
|
||||||
|
// 标题是否居中
|
||||||
|
ifCenter: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 标题是否加粗
|
||||||
|
ifBold: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 底部距离内容多高
|
||||||
|
marginBottom: {
|
||||||
|
type: String,
|
||||||
|
default: '0'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
statusBarHeight: uni.getSystemInfoSync().statusBarHeight,
|
||||||
|
ifNet: true, // 是否有网络
|
||||||
|
netText: '当前无网络',
|
||||||
|
netTimer: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 网络监测
|
||||||
|
this.$toolAll.tools.networkStatus();
|
||||||
|
// 获取当前页面路径
|
||||||
|
this.$toolAll.tools.obtainPagePath();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.ifNet = uni.getStorageSync('isNet');
|
||||||
|
}, 500)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 刷新网络事件
|
||||||
|
refreshEv() {
|
||||||
|
this.netText = '正在刷新...';
|
||||||
|
let outTime = 0; //十秒超时
|
||||||
|
this.netTimer = setInterval(() => {
|
||||||
|
outTime++;
|
||||||
|
this.$toolAll.tools.networkStatus();
|
||||||
|
if (uni.getStorageSync('isNet')) {
|
||||||
|
clearInterval(this.netTimer);
|
||||||
|
this.ifNet = true;
|
||||||
|
}
|
||||||
|
if (outTime == 10) {
|
||||||
|
clearInterval(this.netTimer);
|
||||||
|
this.netText = '刷新失败';
|
||||||
|
outTime = 0;
|
||||||
|
}
|
||||||
|
}, 1000)
|
||||||
|
},
|
||||||
|
//返回事件
|
||||||
|
backEv() {
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1,
|
||||||
|
fail: () => {
|
||||||
|
uni.reLaunch({
|
||||||
|
url: '/pages/home/home'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.status-box {
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 750rpx auto;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-nav {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
padding: 0 50rpx 0 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
padding: 0 20rpx 0 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-title {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 32rpx;
|
||||||
|
line-height: 1.5;
|
||||||
|
letter-spacing: 2rpx;
|
||||||
|
text-indent: 2rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-title .title-box {
|
||||||
|
margin-top: -4rpx;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,62 @@
|
||||||
|
<template>
|
||||||
|
<view class="lamp-box">
|
||||||
|
<swiper :current="lampCur" :style="{height: newHeight}" :autoplay="isplay" :circular="true" :interval="3000" :vertical="true" :duration="1000">
|
||||||
|
<swiper-item v-for="(item,index) in lampList" :key="index">
|
||||||
|
<view @tap="toDetail(index)">{{item.title}}</view>
|
||||||
|
</swiper-item>
|
||||||
|
<swiper-item v-if="lampList.length==1" v-for="(item,index) in lampList" :key="index">
|
||||||
|
<view @tap="toDetail(index)">{{item.title}}</view>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "swiper-lamp",
|
||||||
|
props: {
|
||||||
|
isplay: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
isClick: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
lampList: { //默认轮播图片
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
newHeight: { //swiper的高
|
||||||
|
type: String,
|
||||||
|
default: '42rpx'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
lampCur: 0, // 默认当前选中项
|
||||||
|
autoplay: true, // 是否开启自动轮播
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 标题点击事件
|
||||||
|
toDetail(index) {
|
||||||
|
this.lampCur = index;
|
||||||
|
if(this.isClick){
|
||||||
|
// 有链接,跳转链接
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pagesB/news/newsDetail?id=${this.lampList[index].id}`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.lamp-box {
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,168 @@
|
||||||
|
<template>
|
||||||
|
<view class="banner-box">
|
||||||
|
<swiper :current="bcurrent" @change="changeBanner" :style="{height: newHeight}" :autoplay="isplay" :circular="true" :interval="5000" :duration="500">
|
||||||
|
<swiper-item v-for="(item,index) in bannerList" :key="index">
|
||||||
|
<view @tap="chooseImg(index,item.url)" class="img-box">
|
||||||
|
<image :style="{borderRadius:newRadius,height:newHeight}" class="img animated fadeIn" :src="item.imgSrc" mode="widthFix"></image>
|
||||||
|
</view>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
<!-- 指示点 -->
|
||||||
|
<view v-if="isDot" class="dot-box" :style="{bottom:newBottom}">
|
||||||
|
<view class="item-dot" :style="{backgroundColor: bcurrent==indexd ? activec : defaultc}" v-for="(itemd,indexd) in bannerList.length" :key="indexd" @tap="chooseDot(indexd)"></view>
|
||||||
|
</view>
|
||||||
|
<!-- 指示数字 -->
|
||||||
|
<view v-if="isNum" class="num-box" :style="{bottom:newBottom}">
|
||||||
|
<text>{{bcurrent+1}}</text>
|
||||||
|
<text>/</text>
|
||||||
|
<text>{{bannerList.length}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "swiper-pu",
|
||||||
|
props: {
|
||||||
|
isplay: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
isDot: { //是否显示指示点
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
isNum: { //是否显示指示数字
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
bannerList: { //默认轮播图片
|
||||||
|
type: Array,
|
||||||
|
default: []
|
||||||
|
},
|
||||||
|
newHeight: { //swiper的高
|
||||||
|
type: String,
|
||||||
|
default: '100%'
|
||||||
|
},
|
||||||
|
newBottom: { //指示点距离底部位置
|
||||||
|
type: String,
|
||||||
|
default: '18rpx'
|
||||||
|
},
|
||||||
|
newRadius: { //图片圆角
|
||||||
|
type: String,
|
||||||
|
default: '0rpx'
|
||||||
|
},
|
||||||
|
browseP: { //是否可预览
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
activec: {
|
||||||
|
type: String,
|
||||||
|
default: 'rgba(255,255,255,1)'
|
||||||
|
},
|
||||||
|
defaultc: {
|
||||||
|
type: String,
|
||||||
|
default: 'rgba(255,255,255,.6)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
bcurrent: 0, // 默认当前选中项
|
||||||
|
isShowVideo: false, // 是否显示视频
|
||||||
|
autoplay: false, // 是否开启自动轮播
|
||||||
|
isVedio: uni.getStorageSync('is_vedio') // 是否是视频
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 图片点击事件
|
||||||
|
chooseImg(index, url) {
|
||||||
|
console.log('当前banner图', index, url);
|
||||||
|
this.bcurrent = index
|
||||||
|
if (this.browseP) {
|
||||||
|
let imgList = []
|
||||||
|
this.bannerList.forEach(item => {
|
||||||
|
let obj = {
|
||||||
|
url: item.imgSrc,
|
||||||
|
type: 'image'
|
||||||
|
}
|
||||||
|
imgList.push(obj)
|
||||||
|
})
|
||||||
|
// 预览图片和视频
|
||||||
|
uni.previewMedia({
|
||||||
|
current: this.bcurrent,
|
||||||
|
sources: imgList
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (url) {
|
||||||
|
// 有链接,跳转链接
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `${url}`
|
||||||
|
})
|
||||||
|
console.log(`${url}`, '跳转链接');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 切换后获取当前索引
|
||||||
|
changeBanner(e) {
|
||||||
|
this.bcurrent = e.detail.current //当前的指示点下标
|
||||||
|
},
|
||||||
|
// 点击当前指示点
|
||||||
|
chooseDot(index) {
|
||||||
|
this.bcurrent = index;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.banner-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.img {
|
||||||
|
width: 100%;
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dot-box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-dot {
|
||||||
|
width: 15rpx;
|
||||||
|
height: 15rpx;
|
||||||
|
border-radius: 100%;
|
||||||
|
margin: 0 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.num-box{
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
width: auto;
|
||||||
|
line-height: 46rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
padding: 0 12rpx;
|
||||||
|
background-color: rgba(0, 0, 0, .4);
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #ffffff;
|
||||||
|
position: absolute;
|
||||||
|
right: 38rpx;
|
||||||
|
}
|
||||||
|
.num-box text:nth-of-type(2){
|
||||||
|
font-size: 24rpx;
|
||||||
|
margin: 0 4rpx;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,107 @@
|
||||||
|
<template>
|
||||||
|
<view @touchmove.stop.prevent>
|
||||||
|
<view class="tui-popup-class tui-bottom-popup" :class="{ 'tui-popup-show': show, 'tui-popup-radius': radius }" :style="{ backgroundColor: backgroundColor, height: height ? height + 'rpx' : 'auto', zIndex: zIndex,transform:`translate3d(0, ${show?translateY:'100%'}, 0)`}">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
<view class="tui-popup-mask" :class="[show ? 'tui-mask-show' : '']" :style="{ zIndex: maskZIndex }" v-if="mask" @tap="handleClose"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiBottomPopup',
|
||||||
|
emits: ['close'],
|
||||||
|
props: {
|
||||||
|
//是否需要mask
|
||||||
|
mask: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//控制显示
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//背景颜色
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#fff'
|
||||||
|
},
|
||||||
|
//高度 rpx
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
//设置圆角
|
||||||
|
radius: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
zIndex: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 997
|
||||||
|
},
|
||||||
|
maskZIndex: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 996
|
||||||
|
},
|
||||||
|
//弹层显示时,垂直方向移动的距离
|
||||||
|
translateY: {
|
||||||
|
type: String,
|
||||||
|
default: '0'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClose() {
|
||||||
|
if (!this.show) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$emit('close', {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-bottom-popup {
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate3d(0, 100%, 0);
|
||||||
|
transform-origin: center;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
min-height: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-popup-radius {
|
||||||
|
border-top-left-radius: 24rpx;
|
||||||
|
border-top-right-radius: 24rpx;
|
||||||
|
padding-bottom: env(safe-area-inset-bottom);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-popup-show {
|
||||||
|
opacity: 1;
|
||||||
|
/* transform: translate3d(0, 0, 0); */
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-popup-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-mask-show {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,204 @@
|
||||||
|
<template>
|
||||||
|
<view :class="{ 'tui-flex-end': flexEnd }">
|
||||||
|
<view class="tui-popup-list" :class="{ 'tui-popup-show': show,'tui-z_index':show && position!='relative' }" :style="{ width: width, backgroundColor: backgroundColor, borderRadius: radius, color: color, position: position, left: left, right: right, bottom: bottom, top: top,transform:`translate(${translateX},${translateY})` }">
|
||||||
|
<view class="tui-triangle" :style="{
|
||||||
|
borderWidth: borderWidth,
|
||||||
|
borderColor: `transparent transparent ${backgroundColor} transparent`,
|
||||||
|
left: triangleLeft,
|
||||||
|
right: triangleRight,
|
||||||
|
top: triangleTop,
|
||||||
|
bottom: triangleBottom
|
||||||
|
}"
|
||||||
|
v-if="direction == 'top'"></view>
|
||||||
|
<view class="tui-triangle" :style="{
|
||||||
|
borderWidth: borderWidth,
|
||||||
|
borderColor: `${backgroundColor} transparent transparent transparent`,
|
||||||
|
left: triangleLeft,
|
||||||
|
right: triangleRight,
|
||||||
|
top: triangleTop,
|
||||||
|
bottom: triangleBottom
|
||||||
|
}"
|
||||||
|
v-if="direction == 'bottom'"></view>
|
||||||
|
<view class="tui-triangle" :style="{
|
||||||
|
borderWidth: borderWidth,
|
||||||
|
borderColor: `transparent ${backgroundColor} transparent transparent`,
|
||||||
|
left: triangleLeft,
|
||||||
|
right: triangleRight,
|
||||||
|
top: triangleTop,
|
||||||
|
bottom: triangleBottom
|
||||||
|
}"
|
||||||
|
v-if="direction == 'left'"></view>
|
||||||
|
<view class="tui-triangle" :style="{
|
||||||
|
borderWidth: borderWidth,
|
||||||
|
borderColor: `transparent transparent transparent ${backgroundColor}`,
|
||||||
|
left: triangleLeft,
|
||||||
|
right: triangleRight,
|
||||||
|
top: triangleTop,
|
||||||
|
bottom: triangleBottom
|
||||||
|
}"
|
||||||
|
v-if="direction == 'right'"></view>
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
<view @touchmove.stop.prevent="stop" class="tui-popup-mask" :class="{ 'tui-popup-show': show }" :style="{ backgroundColor: maskBgColor }"
|
||||||
|
v-if="mask" @tap="handleClose"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiBubblePopup',
|
||||||
|
emits: ['close'],
|
||||||
|
props: {
|
||||||
|
//宽度
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '300rpx'
|
||||||
|
},
|
||||||
|
//popup圆角
|
||||||
|
radius: {
|
||||||
|
type: String,
|
||||||
|
default: '8rpx'
|
||||||
|
},
|
||||||
|
//popup 定位 left right top bottom值
|
||||||
|
left: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
top: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
bottom: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
translateX:{
|
||||||
|
type: String,
|
||||||
|
default: '0'
|
||||||
|
},
|
||||||
|
translateY:{
|
||||||
|
type: String,
|
||||||
|
default: '0'
|
||||||
|
},
|
||||||
|
//背景颜色
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#4c4c4c'
|
||||||
|
},
|
||||||
|
//字体颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#fff'
|
||||||
|
},
|
||||||
|
//三角border-width
|
||||||
|
borderWidth: {
|
||||||
|
type: String,
|
||||||
|
default: '12rpx'
|
||||||
|
},
|
||||||
|
//三角形方向 top left right bottom
|
||||||
|
direction: {
|
||||||
|
type: String,
|
||||||
|
default: 'top'
|
||||||
|
},
|
||||||
|
//定位 left right top bottom值
|
||||||
|
triangleLeft: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
triangleRight: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
triangleTop: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
triangleBottom: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
//定位 relative absolute fixed
|
||||||
|
position: {
|
||||||
|
type: String,
|
||||||
|
default: 'fixed'
|
||||||
|
},
|
||||||
|
//flex-end
|
||||||
|
flexEnd: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//是否需要mask
|
||||||
|
mask: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
maskBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'rgba(0, 0, 0, 0.4)'
|
||||||
|
},
|
||||||
|
//控制显示
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClose() {
|
||||||
|
if (!this.show) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$emit('close', {});
|
||||||
|
},
|
||||||
|
stop() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-popup-list {
|
||||||
|
z-index: 1;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-flex-end {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-triangle {
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-style: solid;
|
||||||
|
z-index: 997;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-popup-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 995;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-popup-show {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-z_index {
|
||||||
|
z-index: 996;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,520 @@
|
||||||
|
<template>
|
||||||
|
<button
|
||||||
|
class="tui-btn"
|
||||||
|
:class="[
|
||||||
|
plain ? 'tui-' + type + '-outline' : 'tui-btn-' + (type || 'primary'),
|
||||||
|
getDisabledClass(disabled, type, plain),
|
||||||
|
getShapeClass(shape, plain),
|
||||||
|
getShadowClass(type, shadow, plain),
|
||||||
|
bold ? 'tui-text-bold' : '',
|
||||||
|
link ? 'tui-btn__link' : ''
|
||||||
|
]"
|
||||||
|
:hover-class="getHoverClass(disabled, type, plain)"
|
||||||
|
:style="{ width: width, height: height, lineHeight: height, fontSize: size + 'rpx', margin: margin }"
|
||||||
|
:loading="loading"
|
||||||
|
:form-type="formType"
|
||||||
|
:open-type="openType"
|
||||||
|
@getuserinfo="bindgetuserinfo"
|
||||||
|
@getphonenumber="bindgetphonenumber"
|
||||||
|
@contact="bindcontact"
|
||||||
|
@error="binderror"
|
||||||
|
:disabled="disabled"
|
||||||
|
@tap="handleClick"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiButton',
|
||||||
|
emits: ['click','getuserinfo','contact','getphonenumber','error'],
|
||||||
|
// #ifndef MP-QQ
|
||||||
|
behaviors: ['wx://form-field-button'],
|
||||||
|
// #endif
|
||||||
|
props: {
|
||||||
|
//样式类型 primary, white, danger, warning, green,blue, gray,black,brown,gray-primary,gray-danger,gray-warning,gray-green
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'primary'
|
||||||
|
},
|
||||||
|
//是否加阴影
|
||||||
|
shadow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 宽度 rpx或 %
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '100%'
|
||||||
|
},
|
||||||
|
//高度 rpx
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: '96rpx'
|
||||||
|
},
|
||||||
|
//字体大小 rpx
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 32
|
||||||
|
},
|
||||||
|
bold: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
margin: {
|
||||||
|
type: String,
|
||||||
|
default: '0'
|
||||||
|
},
|
||||||
|
//形状 circle(圆角), square(默认方形),rightAngle(平角)
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: 'square'
|
||||||
|
},
|
||||||
|
plain: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//link样式,去掉边框,结合plain一起使用
|
||||||
|
link: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//禁用后背景是否为灰色 (非空心button生效)
|
||||||
|
disabledGray: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
formType: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
openType: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
index: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
//是否需要阻止重复点击【默认200ms】
|
||||||
|
preventClick: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
time: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClick() {
|
||||||
|
if (this.disabled) return;
|
||||||
|
if (this.preventClick) {
|
||||||
|
if(new Date().getTime() - this.time <= 200) return;
|
||||||
|
this.time = new Date().getTime();
|
||||||
|
setTimeout(() => {
|
||||||
|
this.time = 0;
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
this.$emit('click', {
|
||||||
|
index: Number(this.index)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
bindgetuserinfo({ detail = {} } = {}) {
|
||||||
|
this.$emit('getuserinfo', detail);
|
||||||
|
},
|
||||||
|
bindcontact({ detail = {} } = {}) {
|
||||||
|
this.$emit('contact', detail);
|
||||||
|
},
|
||||||
|
bindgetphonenumber({ detail = {} } = {}) {
|
||||||
|
this.$emit('getphonenumber', detail);
|
||||||
|
},
|
||||||
|
binderror({ detail = {} } = {}) {
|
||||||
|
this.$emit('error', detail);
|
||||||
|
},
|
||||||
|
getShadowClass: function(type, shadow, plain) {
|
||||||
|
let className = '';
|
||||||
|
if (shadow && type != 'white' && !plain) {
|
||||||
|
className = 'tui-shadow-' + type;
|
||||||
|
}
|
||||||
|
return className;
|
||||||
|
},
|
||||||
|
getDisabledClass: function(disabled, type, plain) {
|
||||||
|
let className = '';
|
||||||
|
if (disabled && type != 'white' && type.indexOf('-') == -1) {
|
||||||
|
let classVal = this.disabledGray ? 'tui-gray-disabled' : 'tui-dark-disabled';
|
||||||
|
className = plain ? 'tui-dark-disabled-outline' : classVal;
|
||||||
|
}
|
||||||
|
return className;
|
||||||
|
},
|
||||||
|
getShapeClass: function(shape, plain) {
|
||||||
|
let className = '';
|
||||||
|
if (shape == 'circle') {
|
||||||
|
className = plain ? 'tui-outline-fillet' : 'tui-fillet';
|
||||||
|
} else if (shape == 'rightAngle') {
|
||||||
|
className = plain ? 'tui-outline-rightAngle' : 'tui-rightAngle';
|
||||||
|
}
|
||||||
|
return className;
|
||||||
|
},
|
||||||
|
getHoverClass: function(disabled, type, plain) {
|
||||||
|
let className = '';
|
||||||
|
if (!disabled) {
|
||||||
|
className = plain ? 'tui-outline-hover' : 'tui-' + (type || 'primary') + '-hover';
|
||||||
|
}
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-btn-primary {
|
||||||
|
background: #5677fc !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-shadow-primary {
|
||||||
|
box-shadow: 0 10rpx 14rpx 0 rgba(86, 119, 252, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-danger {
|
||||||
|
background: #eb0909 !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-shadow-danger {
|
||||||
|
box-shadow: 0 10rpx 14rpx 0 rgba(235, 9, 9, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-warning {
|
||||||
|
background: #fc872d !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-shadow-warning {
|
||||||
|
box-shadow: 0 10rpx 14rpx 0 rgba(252, 135, 45, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-green {
|
||||||
|
background: #07c160 !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-shadow-green {
|
||||||
|
box-shadow: 0 10rpx 14rpx 0 rgba(7, 193, 96, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-blue {
|
||||||
|
background: #007aff !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-shadow-blue {
|
||||||
|
box-shadow: 0 10rpx 14rpx 0 rgba(0, 122, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-white {
|
||||||
|
background: #fff !important;
|
||||||
|
color: #333 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-gray {
|
||||||
|
background: #bfbfbf !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-black {
|
||||||
|
background: #333 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
.tui-btn-brown{
|
||||||
|
background: #ac9157 !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-gray-black {
|
||||||
|
background: #f2f2f2 !important;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-gray-primary {
|
||||||
|
background: #f2f2f2 !important;
|
||||||
|
color: #5677fc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray-primary-hover {
|
||||||
|
background: #d9d9d9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-gray-green {
|
||||||
|
background: #f2f2f2 !important;
|
||||||
|
color: #07c160 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray-green-hover {
|
||||||
|
background: #d9d9d9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-gray-danger {
|
||||||
|
background: #f2f2f2 !important;
|
||||||
|
color: #eb0909 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray-danger-hover {
|
||||||
|
background: #d9d9d9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-gray-warning {
|
||||||
|
background: #f2f2f2 !important;
|
||||||
|
color: #fc872d !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray-warning-hover {
|
||||||
|
background: #d9d9d9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-shadow-gray {
|
||||||
|
box-shadow: 0 10rpx 14rpx 0 rgba(191, 191, 191, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-hover-gray {
|
||||||
|
background: #f7f7f9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-black-hover {
|
||||||
|
background: #555 !important;
|
||||||
|
color: #e5e5e5 !important;
|
||||||
|
}
|
||||||
|
.tui-brown-hover{
|
||||||
|
background: #A37F49 !important;
|
||||||
|
color: #e5e5e5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* button start*/
|
||||||
|
|
||||||
|
.tui-btn {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
border: 0 !important;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
width: 200%;
|
||||||
|
height: 200%;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
transform: scale(0.5, 0.5) translateZ(0);
|
||||||
|
box-sizing: border-box;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-text-bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-white::after {
|
||||||
|
border: 1px solid #bfbfbf;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-white-hover {
|
||||||
|
background: #e5e5e5 !important;
|
||||||
|
color: #2e2e2e !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-dark-disabled {
|
||||||
|
opacity: 0.6 !important;
|
||||||
|
color: #fafbfc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-dark-disabled-outline {
|
||||||
|
opacity: 0.5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray-disabled {
|
||||||
|
background: #f3f3f3 !important;
|
||||||
|
color: #919191 !important;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-outline-hover {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-primary-hover {
|
||||||
|
background: #4a67d6 !important;
|
||||||
|
color: #e5e5e5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-primary-outline::after {
|
||||||
|
border: 1px solid #5677fc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-primary-outline {
|
||||||
|
color: #5677fc !important;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-danger-hover {
|
||||||
|
background: #c80808 !important;
|
||||||
|
color: #e5e5e5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-danger-outline {
|
||||||
|
color: #eb0909 !important;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-danger-outline::after {
|
||||||
|
border: 1px solid #eb0909 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-warning-hover {
|
||||||
|
background: #d67326 !important;
|
||||||
|
color: #e5e5e5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-warning-outline {
|
||||||
|
color: #fc872d !important;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-warning-outline::after {
|
||||||
|
border: 1px solid #fc872d !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-green-hover {
|
||||||
|
background: #06ad56 !important;
|
||||||
|
color: #e5e5e5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-green-outline {
|
||||||
|
color: #07c160 !important;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-green-outline::after {
|
||||||
|
border: 1px solid #07c160 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-blue-hover {
|
||||||
|
background: #0062cc !important;
|
||||||
|
color: #e5e5e5 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-blue-outline {
|
||||||
|
color: #007aff !important;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-blue-outline::after {
|
||||||
|
border: 1px solid #007aff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
.tui-btn-gradual {
|
||||||
|
background: linear-gradient(90deg, rgb(255, 89, 38), rgb(240, 14, 44)) !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-shadow-gradual {
|
||||||
|
box-shadow: 0 10rpx 14rpx 0 rgba(235, 9, 9, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
.tui-gray-hover {
|
||||||
|
background: #a3a3a3 !important;
|
||||||
|
color: #898989;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
.tui-gradual-hover {
|
||||||
|
background: linear-gradient(90deg, #d74620, #cd1225) !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
.tui-gray-outline {
|
||||||
|
color: #999 !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-white-outline {
|
||||||
|
color: #fff !important;
|
||||||
|
background: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-black-outline {
|
||||||
|
background: transparent !important;
|
||||||
|
color: #333 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray-outline::after {
|
||||||
|
border: 1px solid #ccc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-white-outline::after {
|
||||||
|
border: 1px solid #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-black-outline::after {
|
||||||
|
border: 1px solid #333 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-brown-outline {
|
||||||
|
color: #ac9157 !important;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
.tui-brown-outline::after {
|
||||||
|
border: 1px solid #ac9157 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*圆角 */
|
||||||
|
|
||||||
|
.tui-fillet {
|
||||||
|
border-radius: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-white.tui-fillet::after {
|
||||||
|
border-radius: 98rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-outline-fillet::after {
|
||||||
|
border-radius: 98rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*平角*/
|
||||||
|
.tui-rightAngle {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-white.tui-rightAngle::after {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-outline-rightAngle::after {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.tui-btn__link::after {
|
||||||
|
border: 0 !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,562 @@
|
||||||
|
/**
|
||||||
|
* @1900-2100区间内的公历、农历互转
|
||||||
|
* @公历转农历:solar2lunar(1987,11,01);
|
||||||
|
* @农历转公历:lunar2solar(1987,09,10);
|
||||||
|
*/
|
||||||
|
let calendar = {
|
||||||
|
/**
|
||||||
|
* 农历1900-2100的润大小信息表
|
||||||
|
* @Array Of Property
|
||||||
|
* @return Hex
|
||||||
|
*/
|
||||||
|
lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, //1900-1909
|
||||||
|
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, //1910-1919
|
||||||
|
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, //1920-1929
|
||||||
|
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, //1930-1939
|
||||||
|
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, //1940-1949
|
||||||
|
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, //1950-1959
|
||||||
|
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, //1960-1969
|
||||||
|
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, //1970-1979
|
||||||
|
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, //1980-1989
|
||||||
|
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, //1990-1999
|
||||||
|
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, //2000-2009
|
||||||
|
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, //2010-2019
|
||||||
|
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, //2020-2029
|
||||||
|
0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, //2030-2039
|
||||||
|
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, //2040-2049
|
||||||
|
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, //2050-2059
|
||||||
|
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, //2060-2069
|
||||||
|
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, //2070-2079
|
||||||
|
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, //2080-2089
|
||||||
|
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, //2090-2099
|
||||||
|
0x0d520
|
||||||
|
], //2100
|
||||||
|
/**
|
||||||
|
* 公历每个月份的天数普通表
|
||||||
|
* @Array Of Property
|
||||||
|
* @return Number
|
||||||
|
*/
|
||||||
|
solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
|
||||||
|
/**
|
||||||
|
* 天干地支之天干速查表
|
||||||
|
* @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
|
||||||
|
* @return Cn string
|
||||||
|
*/
|
||||||
|
Gan: ["\u7532", "\u4e59", "\u4e19", "\u4e01", "\u620a", "\u5df1", "\u5e9a", "\u8f9b", "\u58ec", "\u7678"],
|
||||||
|
/**
|
||||||
|
* 天干地支之地支速查表
|
||||||
|
* @Array Of Property
|
||||||
|
* @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
|
||||||
|
* @return Cn string
|
||||||
|
*/
|
||||||
|
Zhi: ["\u5b50", "\u4e11", "\u5bc5", "\u536f", "\u8fb0", "\u5df3", "\u5348", "\u672a", "\u7533", "\u9149", "\u620c",
|
||||||
|
"\u4ea5"
|
||||||
|
],
|
||||||
|
/**
|
||||||
|
* 天干地支之地支速查表<=>生肖
|
||||||
|
* @Array Of Property
|
||||||
|
* @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
|
||||||
|
* @return Cn string
|
||||||
|
*/
|
||||||
|
Animals: ["\u9f20", "\u725b", "\u864e", "\u5154", "\u9f99", "\u86c7", "\u9a6c", "\u7f8a", "\u7334", "\u9e21",
|
||||||
|
"\u72d7", "\u732a"
|
||||||
|
],
|
||||||
|
/**
|
||||||
|
* 24节气速查表
|
||||||
|
* @Array Of Property
|
||||||
|
* @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
|
||||||
|
* @return Cn string
|
||||||
|
*/
|
||||||
|
solarTerm: ["\u5c0f\u5bd2", "\u5927\u5bd2", "\u7acb\u6625", "\u96e8\u6c34", "\u60ca\u86f0", "\u6625\u5206",
|
||||||
|
"\u6e05\u660e", "\u8c37\u96e8", "\u7acb\u590f", "\u5c0f\u6ee1", "\u8292\u79cd", "\u590f\u81f3", "\u5c0f\u6691",
|
||||||
|
"\u5927\u6691", "\u7acb\u79cb", "\u5904\u6691", "\u767d\u9732", "\u79cb\u5206", "\u5bd2\u9732", "\u971c\u964d",
|
||||||
|
"\u7acb\u51ac", "\u5c0f\u96ea", "\u5927\u96ea", "\u51ac\u81f3"
|
||||||
|
],
|
||||||
|
/**
|
||||||
|
* 1900-2100各年的24节气日期速查表
|
||||||
|
* @Array Of Property
|
||||||
|
* @return 0x string For splice
|
||||||
|
*/
|
||||||
|
sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
|
||||||
|
'97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||||
|
'97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
|
||||||
|
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
|
||||||
|
'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
|
||||||
|
'97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
|
||||||
|
'97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
|
||||||
|
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
|
||||||
|
'97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||||
|
'97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||||
|
'97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
|
||||||
|
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
|
||||||
|
'97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||||
|
'97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||||
|
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
|
||||||
|
'9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
|
||||||
|
'97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
|
||||||
|
'97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
|
||||||
|
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
|
||||||
|
'7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||||
|
'97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||||
|
'97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
|
||||||
|
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
|
||||||
|
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
|
||||||
|
'97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||||
|
'97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
|
||||||
|
'9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
|
||||||
|
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
|
||||||
|
'97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
|
||||||
|
'9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
|
||||||
|
'7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
|
||||||
|
'7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||||
|
'97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
|
||||||
|
'9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
|
||||||
|
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
|
||||||
|
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
|
||||||
|
'97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
|
||||||
|
'9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
|
||||||
|
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
|
||||||
|
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
|
||||||
|
'977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
|
||||||
|
'7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||||
|
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
|
||||||
|
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
|
||||||
|
'977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
|
||||||
|
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||||
|
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
|
||||||
|
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
|
||||||
|
'977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
|
||||||
|
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
|
||||||
|
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
|
||||||
|
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
|
||||||
|
'7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||||
|
'7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
|
||||||
|
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
|
||||||
|
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
|
||||||
|
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
|
||||||
|
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
|
||||||
|
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
|
||||||
|
'7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
|
||||||
|
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
|
||||||
|
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
|
||||||
|
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
|
||||||
|
'665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
|
||||||
|
'7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
|
||||||
|
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
|
||||||
|
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'
|
||||||
|
],
|
||||||
|
/**
|
||||||
|
* 数字转中文速查表
|
||||||
|
* @Array Of Property
|
||||||
|
* @trans ['日','一','二','三','四','五','六','七','八','九','十']
|
||||||
|
* @return Cn string
|
||||||
|
*/
|
||||||
|
nStr1: ["\u65e5", "\u4e00", "\u4e8c", "\u4e09", "\u56db", "\u4e94", "\u516d", "\u4e03", "\u516b", "\u4e5d", "\u5341"],
|
||||||
|
/**
|
||||||
|
* 日期转农历称呼速查表
|
||||||
|
* @Array Of Property
|
||||||
|
* @trans ['初','十','廿','卅']
|
||||||
|
* @return Cn string
|
||||||
|
*/
|
||||||
|
nStr2: ["\u521d", "\u5341", "\u5eff", "\u5345"],
|
||||||
|
/**
|
||||||
|
* 月份转农历称呼速查表
|
||||||
|
* @Array Of Property
|
||||||
|
* @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
|
||||||
|
* @return Cn string
|
||||||
|
*/
|
||||||
|
nStr3: ["\u6b63", "\u4e8c", "\u4e09", "\u56db", "\u4e94", "\u516d", "\u4e03", "\u516b", "\u4e5d", "\u5341", "\u51ac",
|
||||||
|
"\u814a"
|
||||||
|
],
|
||||||
|
/**
|
||||||
|
* 返回农历y年一整年的总天数
|
||||||
|
* @param lunar Year
|
||||||
|
* @return Number
|
||||||
|
* @eg:let count = calendar.lYearDays(1987) ;//count=387
|
||||||
|
*/
|
||||||
|
lYearDays: function(y) {
|
||||||
|
let i, sum = 348;
|
||||||
|
for (i = 0x8000; i > 0x8; i >>= 1) {
|
||||||
|
sum += (calendar.lunarInfo[y - 1900] & i) ? 1 : 0;
|
||||||
|
}
|
||||||
|
return (sum + calendar.leapDays(y));
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 返回农历y年闰月是哪个月;若y年没有闰月 则返回0
|
||||||
|
* @param lunar Year
|
||||||
|
* @return Number (0-12)
|
||||||
|
* @eg:let leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
|
||||||
|
*/
|
||||||
|
leapMonth: function(y) { //闰字编码 \u95f0
|
||||||
|
return (calendar.lunarInfo[y - 1900] & 0xf);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 返回农历y年闰月的天数 若该年没有闰月则返回0
|
||||||
|
* @param lunar Year
|
||||||
|
* @return Number (0、29、30)
|
||||||
|
* @eg:let leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
|
||||||
|
*/
|
||||||
|
leapDays: function(y) {
|
||||||
|
if (calendar.leapMonth(y)) {
|
||||||
|
return ((calendar.lunarInfo[y - 1900] & 0x10000) ? 30 : 29);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 返回农历y年m月(非闰月)的总天数,计算m为闰月时的天数请使用leapDays方法
|
||||||
|
* @param lunar Year
|
||||||
|
* @return Number (-1、29、30)
|
||||||
|
* @eg:let MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
|
||||||
|
*/
|
||||||
|
monthDays: function(y, m) {
|
||||||
|
if (m > 12 || m < 1) {
|
||||||
|
return -1
|
||||||
|
} //月份参数从1至12,参数错误返回-1
|
||||||
|
return ((calendar.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 返回公历(!)y年m月的天数
|
||||||
|
* @param solar Year
|
||||||
|
* @return Number (-1、28、29、30、31)
|
||||||
|
* @eg:let solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
|
||||||
|
*/
|
||||||
|
solarDays: function(y, m) {
|
||||||
|
if (m > 12 || m < 1) {
|
||||||
|
return -1
|
||||||
|
} //若参数错误 返回-1
|
||||||
|
let ms = m - 1;
|
||||||
|
if (ms == 1) { //2月份的闰平规律测算后确认返回28或29
|
||||||
|
return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28);
|
||||||
|
} else {
|
||||||
|
return (calendar.solarMonth[ms]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 农历年份转换为干支纪年
|
||||||
|
* @param lYear 农历年的年份数
|
||||||
|
* @return Cn string
|
||||||
|
*/
|
||||||
|
toGanZhiYear: function(lYear) {
|
||||||
|
let ganKey = (lYear - 3) % 10;
|
||||||
|
let zhiKey = (lYear - 3) % 12;
|
||||||
|
if (ganKey == 0) ganKey = 10; //如果余数为0则为最后一个天干
|
||||||
|
if (zhiKey == 0) zhiKey = 12; //如果余数为0则为最后一个地支
|
||||||
|
return calendar.Gan[ganKey - 1] + calendar.Zhi[zhiKey - 1];
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 公历月、日判断所属星座
|
||||||
|
* @param cMonth [description]
|
||||||
|
* @param cDay [description]
|
||||||
|
* @return Cn string
|
||||||
|
*/
|
||||||
|
toAstro: function(cMonth, cDay) {
|
||||||
|
let s =
|
||||||
|
"\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf";
|
||||||
|
let arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22];
|
||||||
|
return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + "\u5ea7"; //座
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 传入offset偏移量返回干支
|
||||||
|
* @param offset 相对甲子的偏移量
|
||||||
|
* @return Cn string
|
||||||
|
*/
|
||||||
|
toGanZhi: function(offset) {
|
||||||
|
return calendar.Gan[offset % 10] + calendar.Zhi[offset % 12];
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 传入公历(!)y年获得该年第n个节气的公历日期
|
||||||
|
* @param y公历年(1900-2100);n二十四节气中的第几个节气(1~24);从n=1(小寒)算起
|
||||||
|
* @return day Number
|
||||||
|
* @eg:let _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
|
||||||
|
*/
|
||||||
|
getTerm: function(y, n) {
|
||||||
|
if (y < 1900 || y > 2100) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (n < 1 || n > 24) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
let _table = calendar.sTermInfo[y - 1900];
|
||||||
|
let _info = [
|
||||||
|
parseInt('0x' + _table.substr(0, 5)).toString(),
|
||||||
|
parseInt('0x' + _table.substr(5, 5)).toString(),
|
||||||
|
parseInt('0x' + _table.substr(10, 5)).toString(),
|
||||||
|
parseInt('0x' + _table.substr(15, 5)).toString(),
|
||||||
|
parseInt('0x' + _table.substr(20, 5)).toString(),
|
||||||
|
parseInt('0x' + _table.substr(25, 5)).toString()
|
||||||
|
];
|
||||||
|
let _calday = [
|
||||||
|
_info[0].substr(0, 1),
|
||||||
|
_info[0].substr(1, 2),
|
||||||
|
_info[0].substr(3, 1),
|
||||||
|
_info[0].substr(4, 2),
|
||||||
|
_info[1].substr(0, 1),
|
||||||
|
_info[1].substr(1, 2),
|
||||||
|
_info[1].substr(3, 1),
|
||||||
|
_info[1].substr(4, 2),
|
||||||
|
_info[2].substr(0, 1),
|
||||||
|
_info[2].substr(1, 2),
|
||||||
|
_info[2].substr(3, 1),
|
||||||
|
_info[2].substr(4, 2),
|
||||||
|
_info[3].substr(0, 1),
|
||||||
|
_info[3].substr(1, 2),
|
||||||
|
_info[3].substr(3, 1),
|
||||||
|
_info[3].substr(4, 2),
|
||||||
|
_info[4].substr(0, 1),
|
||||||
|
_info[4].substr(1, 2),
|
||||||
|
_info[4].substr(3, 1),
|
||||||
|
_info[4].substr(4, 2),
|
||||||
|
_info[5].substr(0, 1),
|
||||||
|
_info[5].substr(1, 2),
|
||||||
|
_info[5].substr(3, 1),
|
||||||
|
_info[5].substr(4, 2),
|
||||||
|
];
|
||||||
|
return parseInt(_calday[n - 1]);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 传入农历数字月份返回汉语通俗表示法
|
||||||
|
* @param lunar month
|
||||||
|
* @return Cn string
|
||||||
|
* @eg:let cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
|
||||||
|
*/
|
||||||
|
toChinaMonth: function(m) { // 月 => \u6708
|
||||||
|
if (m > 12 || m < 1) {
|
||||||
|
return -1
|
||||||
|
} //若参数错误 返回-1
|
||||||
|
let s = calendar.nStr3[m - 1];
|
||||||
|
s += "\u6708"; //加上月字
|
||||||
|
return s;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 传入农历日期数字返回汉字表示法
|
||||||
|
* @param lunar day
|
||||||
|
* @return Cn string
|
||||||
|
* @eg:let cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
|
||||||
|
*/
|
||||||
|
toChinaDay: function(d) { //日 => \u65e5
|
||||||
|
let s;
|
||||||
|
switch (d) {
|
||||||
|
case 10:
|
||||||
|
s = '\u521d\u5341';
|
||||||
|
break;
|
||||||
|
case 20:
|
||||||
|
s = '\u4e8c\u5341';
|
||||||
|
break;
|
||||||
|
break;
|
||||||
|
case 30:
|
||||||
|
s = '\u4e09\u5341';
|
||||||
|
break;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
s = calendar.nStr2[Math.floor(d / 10)];
|
||||||
|
s += calendar.nStr1[d % 10];
|
||||||
|
}
|
||||||
|
return (s);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是“立春”
|
||||||
|
* @param y year
|
||||||
|
* @return Cn string
|
||||||
|
* @eg:let animal = calendar.getAnimal(1987) ;//animal='兔'
|
||||||
|
*/
|
||||||
|
getAnimal: function(y) {
|
||||||
|
return calendar.Animals[(y - 4) % 12]
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 传入阳历年月日获得详细的公历、农历object信息 <=>JSON
|
||||||
|
* @param y solar year
|
||||||
|
* @param m solar month
|
||||||
|
* @param d solar day
|
||||||
|
* @return JSON object
|
||||||
|
* @eg:console.log(calendar.solar2lunar(1987,11,01));
|
||||||
|
*/
|
||||||
|
solar2lunar: function(y, m, d) { //参数区间1900.1.31~2100.12.31
|
||||||
|
if (y < 1900 || y > 2100) {
|
||||||
|
return -1;
|
||||||
|
} //年份限定、上限
|
||||||
|
if (y == 1900 && m == 1 && d < 31) {
|
||||||
|
return -1;
|
||||||
|
} //下限
|
||||||
|
let objDate;
|
||||||
|
if (!y) { //未传参 获得当天
|
||||||
|
objDate = new Date();
|
||||||
|
} else {
|
||||||
|
objDate = new Date(y, parseInt(m) - 1, d)
|
||||||
|
}
|
||||||
|
let i, leap = 0,
|
||||||
|
temp = 0;
|
||||||
|
//修正ymd参数
|
||||||
|
y = objDate.getFullYear();
|
||||||
|
m = objDate.getMonth() + 1;
|
||||||
|
d = objDate.getDate();
|
||||||
|
let offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) /
|
||||||
|
86400000;
|
||||||
|
for (i = 1900; i < 2101 && offset > 0; i++) {
|
||||||
|
temp = calendar.lYearDays(i);
|
||||||
|
offset -= temp;
|
||||||
|
}
|
||||||
|
if (offset < 0) {
|
||||||
|
offset += temp;
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
//是否今天
|
||||||
|
let isTodayObj = new Date(),
|
||||||
|
isToday = false;
|
||||||
|
if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
|
||||||
|
isToday = true;
|
||||||
|
}
|
||||||
|
//星期几
|
||||||
|
let nWeek = objDate.getDay(),
|
||||||
|
cWeek = calendar.nStr1[nWeek];
|
||||||
|
if (nWeek == 0) {
|
||||||
|
nWeek = 7;
|
||||||
|
} //数字表示周几顺应天朝周一开始的惯例
|
||||||
|
//农历年
|
||||||
|
let year = i;
|
||||||
|
leap = calendar.leapMonth(i); //闰哪个月
|
||||||
|
let isLeap = false;
|
||||||
|
//效验闰月
|
||||||
|
for (i = 1; i < 13 && offset > 0; i++) {
|
||||||
|
//闰月
|
||||||
|
if (leap > 0 && i == (leap + 1) && isLeap == false) {
|
||||||
|
--i;
|
||||||
|
isLeap = true;
|
||||||
|
temp = calendar.leapDays(year); //计算农历闰月天数
|
||||||
|
} else {
|
||||||
|
temp = calendar.monthDays(year, i); //计算农历普通月天数
|
||||||
|
}
|
||||||
|
//解除闰月
|
||||||
|
if (isLeap == true && i == (leap + 1)) {
|
||||||
|
isLeap = false;
|
||||||
|
}
|
||||||
|
offset -= temp;
|
||||||
|
}
|
||||||
|
if (offset == 0 && leap > 0 && i == leap + 1)
|
||||||
|
if (isLeap) {
|
||||||
|
isLeap = false;
|
||||||
|
} else {
|
||||||
|
isLeap = true;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
if (offset < 0) {
|
||||||
|
offset += temp;
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
//农历月
|
||||||
|
let month = i;
|
||||||
|
//农历日
|
||||||
|
let day = offset + 1;
|
||||||
|
//天干地支处理
|
||||||
|
let sm = m - 1;
|
||||||
|
let gzY = calendar.toGanZhiYear(year);
|
||||||
|
//月柱 1900年1月小寒以前为 丙子月(60进制12)
|
||||||
|
let firstNode = calendar.getTerm(year, (m * 2 - 1)); //返回当月「节」为几日开始
|
||||||
|
let secondNode = calendar.getTerm(year, (m * 2)); //返回当月「节」为几日开始
|
||||||
|
//依据12节气修正干支月
|
||||||
|
let gzM = calendar.toGanZhi((y - 1900) * 12 + m + 11);
|
||||||
|
if (d >= firstNode) {
|
||||||
|
gzM = calendar.toGanZhi((y - 1900) * 12 + m + 12);
|
||||||
|
}
|
||||||
|
//传入的日期的节气与否
|
||||||
|
let isTerm = false;
|
||||||
|
let Term = null;
|
||||||
|
if (firstNode == d) {
|
||||||
|
isTerm = true;
|
||||||
|
Term = calendar.solarTerm[m * 2 - 2];
|
||||||
|
}
|
||||||
|
if (secondNode == d) {
|
||||||
|
isTerm = true;
|
||||||
|
Term = calendar.solarTerm[m * 2 - 1];
|
||||||
|
}
|
||||||
|
//日柱 当月一日与 1900/1/1 相差天数
|
||||||
|
let dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10;
|
||||||
|
let gzD = calendar.toGanZhi(dayCyclical + d - 1);
|
||||||
|
//该日期所属的星座
|
||||||
|
let astro = calendar.toAstro(m, d);
|
||||||
|
return {
|
||||||
|
'lYear': year,
|
||||||
|
'lMonth': month,
|
||||||
|
'lDay': day,
|
||||||
|
'Animal': calendar.getAnimal(year),
|
||||||
|
'IMonthCn': (isLeap ? "\u95f0" : '') + calendar.toChinaMonth(month),
|
||||||
|
'IDayCn': calendar.toChinaDay(day),
|
||||||
|
'cYear': y,
|
||||||
|
'cMonth': m,
|
||||||
|
'cDay': d,
|
||||||
|
'gzYear': gzY,
|
||||||
|
'gzMonth': gzM,
|
||||||
|
'gzDay': gzD,
|
||||||
|
'isToday': isToday,
|
||||||
|
'isLeap': isLeap,
|
||||||
|
'nWeek': nWeek,
|
||||||
|
'ncWeek': "\u661f\u671f" + cWeek,
|
||||||
|
'isTerm': isTerm,
|
||||||
|
'Term': Term,
|
||||||
|
'astro': astro
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 传入农历年月日以及传入的月份是否闰月获得详细的公历、农历object信息 <=>JSON
|
||||||
|
* @param y lunar year
|
||||||
|
* @param m lunar month
|
||||||
|
* @param d lunar day
|
||||||
|
* @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
|
||||||
|
* @return JSON object
|
||||||
|
* @eg:console.log(calendar.lunar2solar(1987,9,10));
|
||||||
|
*/
|
||||||
|
lunar2solar: function(y, m, d, isLeapMonth) { //参数区间1900.1.31~2100.12.1
|
||||||
|
isLeapMonth = !!isLeapMonth;
|
||||||
|
let leapOffset = 0;
|
||||||
|
let leapMonth = calendar.leapMonth(y);
|
||||||
|
let leapDay = calendar.leapDays(y);
|
||||||
|
if (isLeapMonth && (leapMonth != m)) {
|
||||||
|
return -1;
|
||||||
|
} //传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
|
||||||
|
if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) {
|
||||||
|
return -1;
|
||||||
|
} //超出了最大极限值
|
||||||
|
let day = calendar.monthDays(y, m);
|
||||||
|
let _day = day;
|
||||||
|
//bugFix 2016-9-25
|
||||||
|
//if month is leap, _day use leapDays method
|
||||||
|
if (isLeapMonth) {
|
||||||
|
_day = calendar.leapDays(y, m);
|
||||||
|
}
|
||||||
|
if (y < 1900 || y > 2100 || d > _day) {
|
||||||
|
return -1;
|
||||||
|
} //参数合法性效验
|
||||||
|
//计算农历的时间差
|
||||||
|
let offset = 0;
|
||||||
|
for (let i = 1900; i < y; i++) {
|
||||||
|
offset += calendar.lYearDays(i);
|
||||||
|
}
|
||||||
|
let leap = 0,
|
||||||
|
isAdd = false;
|
||||||
|
for (let i = 1; i < m; i++) {
|
||||||
|
leap = calendar.leapMonth(y);
|
||||||
|
if (!isAdd) { //处理闰月
|
||||||
|
if (leap <= i && leap > 0) {
|
||||||
|
offset += calendar.leapDays(y);
|
||||||
|
isAdd = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset += calendar.monthDays(y, i);
|
||||||
|
}
|
||||||
|
//转换闰月农历 需补充该年闰月的前一个月的时差
|
||||||
|
if (isLeapMonth) {
|
||||||
|
offset += day;
|
||||||
|
}
|
||||||
|
//1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
|
||||||
|
let stmap = Date.UTC(1900, 1, 30, 0, 0, 0);
|
||||||
|
let calObj = new Date((offset + d - 31) * 86400000 + stmap);
|
||||||
|
let cY = calObj.getUTCFullYear();
|
||||||
|
let cM = calObj.getUTCMonth() + 1;
|
||||||
|
let cD = calObj.getUTCDate();
|
||||||
|
return calendar.solar2lunar(cY, cM, cD);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
solar2lunar: calendar.solar2lunar,
|
||||||
|
lunar2solar: calendar.lunar2solar
|
||||||
|
};
|
|
@ -0,0 +1,915 @@
|
||||||
|
<template>
|
||||||
|
<view @touchmove.stop.prevent="stop" v-if="isFixed">
|
||||||
|
<view class="tui-bottom-popup" :class="{'tui-popup-show': isShow}">
|
||||||
|
<view class="tui-calendar-header" :class="{ 'tui-calendar-radius': radius }">
|
||||||
|
<view>日期选择</view>
|
||||||
|
<view class="tui-iconfont tui-font-close" hover-class="tui-opacity" :hover-stay-time="150" @tap="hide">
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="tui-date-box">
|
||||||
|
<view class="tui-iconfont tui-font-arrowleft" :style="{ color: yearArrowColor }"
|
||||||
|
hover-class="tui-opacity" :hover-stay-time="150" v-if="arrowType == 1" @tap="changeYear(0)"></view>
|
||||||
|
<view class="tui-iconfont tui-font-arrowleft" :style="{ color: monthArrowColor }"
|
||||||
|
hover-class="tui-opacity" :hover-stay-time="150" @tap="changeMonth(0)"></view>
|
||||||
|
<view class="tui-date_time">{{ showTitle }}</view>
|
||||||
|
<view class="tui-iconfont tui-font-arrowright" :style="{ color: monthArrowColor }"
|
||||||
|
hover-class="tui-opacity" :hover-stay-time="150" @tap="changeMonth(1)"></view>
|
||||||
|
<view class="tui-iconfont tui-font-arrowright" :style="{ color: yearArrowColor }"
|
||||||
|
hover-class="tui-opacity" :hover-stay-time="150" v-if="arrowType == 1" @tap="changeYear(1)"></view>
|
||||||
|
</view>
|
||||||
|
<view class="tui-date-header">
|
||||||
|
<view class="tui-date">日</view>
|
||||||
|
<view class="tui-date">一</view>
|
||||||
|
<view class="tui-date">二</view>
|
||||||
|
<view class="tui-date">三</view>
|
||||||
|
<view class="tui-date">四</view>
|
||||||
|
<view class="tui-date">五</view>
|
||||||
|
<view class="tui-date">六</view>
|
||||||
|
</view>
|
||||||
|
<view class="tui-date-content" :class="{ 'tui-flex-start': isFixed && fixedHeight }"
|
||||||
|
:style="{ height: isFixed && fixedHeight ? dateHeight * 6 + 'px' : 'auto' }">
|
||||||
|
<block v-for="(item, index) in weekdayArr" :key="index">
|
||||||
|
<view class="tui-date"></view>
|
||||||
|
</block>
|
||||||
|
<view class="tui-date" :class="{
|
||||||
|
'tui-date-pd_0': isFixed && fixedHeight,
|
||||||
|
'tui-opacity': openDisAbled(year, month, index + 1),
|
||||||
|
'tui-start-date': (type == 2 && startDate == `${year}-${month}-${index + 1}`) || type == 1,
|
||||||
|
'tui-end-date': (type == 2 && endDate == `${year}-${month}-${index + 1}`) || type == 1
|
||||||
|
}" :style="{ backgroundColor: isFixed ? getColor(index, 1) : 'transparent', height: isFixed && fixedHeight ? dateHeight + 'px' : 'auto' }"
|
||||||
|
v-for="(item, index) in daysArr" :key="index" @tap="dateClick(index)">
|
||||||
|
<view class="tui-date-text"
|
||||||
|
:style="{ color: isFixed ? getColor(index, 2) : getStatusData(3, index), backgroundColor: getStatusData(2, index) }">
|
||||||
|
<view v-if="isFixed || !getStatusData(4, index)">{{ index + 1 }}</view>
|
||||||
|
<view v-if="!getStatusData(4, index)" class="tui-custom-desc"
|
||||||
|
:class="{ 'tui-lunar-unshow': !lunar && isFixed }">
|
||||||
|
{{ getDescText(index, startDate, endDate) }}
|
||||||
|
</view>
|
||||||
|
<text class="tui-iconfont tui-font-check" v-if="getStatusData(4, index)"></text>
|
||||||
|
</view>
|
||||||
|
<view class="tui-date-desc" :style="{ color: activeColor }"
|
||||||
|
v-if="!lunar && type == 2 && startDate == `${year}-${month}-${index + 1}` && startDate != endDate">
|
||||||
|
{{ startText }}
|
||||||
|
</view>
|
||||||
|
<view class="tui-date-desc" :style="{ color: activeColor }"
|
||||||
|
v-if="!lunar && type == 2 && endDate == `${year}-${month}-${index + 1}`">{{ endText }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="tui-bg-month">{{ month }}</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="tui-calendar-op">
|
||||||
|
<view class="tui-calendar-result">
|
||||||
|
<text>{{ type == 1 ? activeDate : startDate }}</text>
|
||||||
|
<text v-if="endDate">至{{ endDate }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="tui-calendar-btn_box">
|
||||||
|
<tui-button :type="btnType" height="72rpx" shape="circle" :size="28" :disabled="disabled"
|
||||||
|
@click="btnFix(false)">确定
|
||||||
|
</tui-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="tui-popup-mask" :class="[isShow ? 'tui-mask-show' : '']" @tap="hide"></view>
|
||||||
|
</view>
|
||||||
|
<view v-else>
|
||||||
|
<view class="tui-date-box">
|
||||||
|
<view class="tui-iconfont tui-font-arrowleft" :style="{ color: yearArrowColor }" hover-class="tui-opacity"
|
||||||
|
:hover-stay-time="150" v-if="arrowType == 1" @tap="changeYear(0)"></view>
|
||||||
|
<view class="tui-iconfont tui-font-arrowleft" :style="{ color: monthArrowColor }" hover-class="tui-opacity"
|
||||||
|
:hover-stay-time="150" @tap="changeMonth(0)"></view>
|
||||||
|
<view class="tui-date_time">{{ showTitle }}</view>
|
||||||
|
<view class="tui-iconfont tui-font-arrowright" :style="{ color: monthArrowColor }" hover-class="tui-opacity"
|
||||||
|
:hover-stay-time="150" @tap="changeMonth(1)"></view>
|
||||||
|
<view class="tui-iconfont tui-font-arrowright" :style="{ color: yearArrowColor }" hover-class="tui-opacity"
|
||||||
|
:hover-stay-time="150" v-if="arrowType == 1" @tap="changeYear(1)"></view>
|
||||||
|
</view>
|
||||||
|
<view class="tui-date-header">
|
||||||
|
<view class="tui-date">日</view>
|
||||||
|
<view class="tui-date">一</view>
|
||||||
|
<view class="tui-date">二</view>
|
||||||
|
<view class="tui-date">三</view>
|
||||||
|
<view class="tui-date">四</view>
|
||||||
|
<view class="tui-date">五</view>
|
||||||
|
<view class="tui-date">六</view>
|
||||||
|
</view>
|
||||||
|
<view class="tui-date-content" :style="{ height: isFixed && fixedHeight ? dateHeight * 6 + 'px' : 'auto' }">
|
||||||
|
<block v-for="(item, index) in weekdayArr" :key="index">
|
||||||
|
<view class="tui-date"></view>
|
||||||
|
</block>
|
||||||
|
<view class="tui-date" :class="{
|
||||||
|
'tui-date-pd_0': isFixed && fixedHeight,
|
||||||
|
'tui-opacity': openDisAbled(year, month, index + 1),
|
||||||
|
'tui-start-date': (type == 2 && startDate == `${year}-${month}-${index + 1}`) || type == 1,
|
||||||
|
'tui-end-date': (type == 2 && endDate == `${year}-${month}-${index + 1}`) || type == 1
|
||||||
|
}" :style="{ backgroundColor: isFixed ? getColor(index, 1) : 'transparent', height: isFixed && fixedHeight ? dateHeight + 'px' : 'auto' }"
|
||||||
|
v-for="(item, index) in daysArr" :key="index" @tap="dateClick(index)">
|
||||||
|
<view class="tui-date-text"
|
||||||
|
:style="{ color: isFixed ? getColor(index, 2) : getStatusData(3, index), backgroundColor: getStatusData(2, index) }">
|
||||||
|
<view v-if="isFixed || !getStatusData(4, index)">{{ index + 1 }}</view>
|
||||||
|
<view v-if="!getStatusData(4, index)" class="tui-custom-desc"
|
||||||
|
:class="{ 'tui-lunar-unshow': !lunar && isFixed }">
|
||||||
|
{{ getDescText(index, startDate, endDate) }}
|
||||||
|
</view>
|
||||||
|
<text class="tui-iconfont tui-font-check" v-if="getStatusData(4, index)"></text>
|
||||||
|
</view>
|
||||||
|
<view class="tui-date-desc" :style="{ color: activeColor }"
|
||||||
|
v-if="!lunar && type == 2 && startDate == `${year}-${month}-${index + 1}` && startDate != endDate">
|
||||||
|
{{ startText }}
|
||||||
|
</view>
|
||||||
|
<view class="tui-date-desc" :style="{ color: activeColor }"
|
||||||
|
v-if="!lunar && type == 2 && endDate == `${year}-${month}-${index + 1}`">{{ endText }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="tui-bg-month">{{ month }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
//easycom组件模式 无需手动引入
|
||||||
|
// import tuiButton from "../tui-button/tui-button"
|
||||||
|
import calendar from './tui-calendar.js';
|
||||||
|
export default {
|
||||||
|
name: 'tuiCalendar',
|
||||||
|
emits: ['hide', 'change'],
|
||||||
|
// components:{
|
||||||
|
// tuiButton
|
||||||
|
// },
|
||||||
|
props: {
|
||||||
|
//1-切换月份和年份 2-切换月份
|
||||||
|
arrowType: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
//1-单个日期选择 2-开始日期+结束日期选择
|
||||||
|
type: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
//可切换最大年份
|
||||||
|
maxYear: {
|
||||||
|
type: Number,
|
||||||
|
default: 2030
|
||||||
|
},
|
||||||
|
//可切换最小年份
|
||||||
|
minYear: {
|
||||||
|
type: Number,
|
||||||
|
default: 1920
|
||||||
|
},
|
||||||
|
//最小可选日期(不在范围内日期禁用不可选)
|
||||||
|
minDate: {
|
||||||
|
type: String,
|
||||||
|
default: '1920-01-01'
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 最大可选日期
|
||||||
|
* 默认最大值为今天,之后的日期不可选
|
||||||
|
* 2030-12-31
|
||||||
|
* */
|
||||||
|
maxDate: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
//显示圆角
|
||||||
|
radius: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//状态 数据顺序与当月天数一致,index=>day
|
||||||
|
/**
|
||||||
|
* [{
|
||||||
|
* text:"", 描述:2字以内
|
||||||
|
* value:"",状态值
|
||||||
|
* bgColor:"",背景色
|
||||||
|
* color:"" 文字颜色,
|
||||||
|
* check:false //是否显示对勾
|
||||||
|
*
|
||||||
|
}]
|
||||||
|
*
|
||||||
|
* **/
|
||||||
|
status: {
|
||||||
|
type: Array,
|
||||||
|
default () {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//月份切换箭头颜色
|
||||||
|
monthArrowColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#999'
|
||||||
|
},
|
||||||
|
//年份切换箭头颜色
|
||||||
|
yearArrowColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#bcbcbc'
|
||||||
|
},
|
||||||
|
//默认日期字体颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#333'
|
||||||
|
},
|
||||||
|
//选中|起始结束日期背景色
|
||||||
|
activeBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#5677fc'
|
||||||
|
},
|
||||||
|
//选中|起始结束日期字体颜色
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#fff'
|
||||||
|
},
|
||||||
|
//范围内日期背景色
|
||||||
|
rangeBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'rgba(86,119,252,0.1)'
|
||||||
|
},
|
||||||
|
//范围内日期字体颜色
|
||||||
|
rangeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#5677fc'
|
||||||
|
},
|
||||||
|
//type=2时生效,起始日期自定义文案
|
||||||
|
startText: {
|
||||||
|
type: String,
|
||||||
|
default: '开始'
|
||||||
|
},
|
||||||
|
//type=2时生效,结束日期自定义文案
|
||||||
|
endText: {
|
||||||
|
type: String,
|
||||||
|
default: '结束'
|
||||||
|
},
|
||||||
|
//按钮样式类型
|
||||||
|
btnType: {
|
||||||
|
type: String,
|
||||||
|
default: 'primary'
|
||||||
|
},
|
||||||
|
//固定在底部
|
||||||
|
isFixed: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//固定日历容器高度,isFixed=true时生效
|
||||||
|
fixedHeight: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//当前选中日期带选中效果
|
||||||
|
isActiveCurrent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//切换年月是否触发事件 type=1时生效
|
||||||
|
isChange: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//是否显示农历
|
||||||
|
lunar: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//初始化起始选中日期 格式: 2020-06-06 或 2020/06/06 【type=1 or 2】
|
||||||
|
initStartDate: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
//初始化结束日期 格式: 2020-06-06 或 2020/06/06【type=2】
|
||||||
|
initEndDate: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isShow: false,
|
||||||
|
weekday: 1, // 星期几,值为1-7
|
||||||
|
weekdayArr: [],
|
||||||
|
days: 0, //当前月有多少天
|
||||||
|
daysArr: [],
|
||||||
|
showTitle: '',
|
||||||
|
year: 2020,
|
||||||
|
month: 0,
|
||||||
|
day: 0,
|
||||||
|
startYear: 0,
|
||||||
|
startMonth: 0,
|
||||||
|
startDay: 0,
|
||||||
|
endYear: 0,
|
||||||
|
endMonth: 0,
|
||||||
|
endDay: 0,
|
||||||
|
today: '',
|
||||||
|
activeDate: '',
|
||||||
|
startDate: '',
|
||||||
|
endDate: '',
|
||||||
|
isStart: true,
|
||||||
|
min: null,
|
||||||
|
max: null,
|
||||||
|
dateHeight: 20
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
dataChange() {
|
||||||
|
return `${this.type}-${this.minDate}-${this.maxDate}-${this.initStartDate}-${this.initEndDate}`;
|
||||||
|
},
|
||||||
|
disabled() {
|
||||||
|
return this.type == 2 && (!this.startDate || !this.endDate)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
dataChange(val) {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
fixedHeight(val) {
|
||||||
|
if (val) {
|
||||||
|
this.initDateHeight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.init();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getColor(index, type) {
|
||||||
|
let color = type == 1 ? '' : this.color;
|
||||||
|
let day = index + 1;
|
||||||
|
let date = `${this.year}-${this.month}-${day}`;
|
||||||
|
let timestamp = new Date(date.replace(/\-/g, '/')).getTime();
|
||||||
|
let start = this.startDate.replace(/\-/g, '/');
|
||||||
|
let end = this.endDate.replace(/\-/g, '/');
|
||||||
|
if ((this.isActiveCurrent && this.activeDate == date) || this.startDate == date || this.endDate == date) {
|
||||||
|
color = type == 1 ? this.activeBgColor : this.activeColor;
|
||||||
|
} else if (this.endDate && timestamp > new Date(start).getTime() && timestamp < new Date(end).getTime()) {
|
||||||
|
color = type == 1 ? this.rangeBgColor : this.rangeColor;
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
},
|
||||||
|
//获取状态数据
|
||||||
|
getStatusData(type, index) {
|
||||||
|
//1-描述text,2-bgColor背景色,3-color文字颜色 4-check 是否显示对勾
|
||||||
|
let val = ['', 'transparent', '#333', ''][type - 1];
|
||||||
|
if (!this.isFixed && this.status && this.status.length > 0) {
|
||||||
|
let item = this.status[index];
|
||||||
|
if (item) {
|
||||||
|
switch (type) {
|
||||||
|
case 1:
|
||||||
|
val = item.text;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
val = item.bgColor;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
val = item.color;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
val = item.check;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
getDescText(index, startDate, endDate) {
|
||||||
|
let text = this.lunar ? this.getLunar(this.year, this.month, index + 1) : '';
|
||||||
|
if (this.isFixed && this.type == 2) {
|
||||||
|
//此判断不能与上面条件一起判断
|
||||||
|
if (this.lunar) {
|
||||||
|
let date = `${this.year}-${this.month}-${index + 1}`;
|
||||||
|
if (startDate == date && startDate != endDate) {
|
||||||
|
text = this.startText;
|
||||||
|
} else if (endDate == date) {
|
||||||
|
text = this.endText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let status = this.getStatusData(1, index);
|
||||||
|
if (status) text = status;
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
},
|
||||||
|
getLunar(year, month, day) {
|
||||||
|
let obj = calendar.solar2lunar(year, month, day);
|
||||||
|
return obj.IDayCn;
|
||||||
|
},
|
||||||
|
initDateHeight() {
|
||||||
|
if (this.fixedHeight && this.isFixed) {
|
||||||
|
this.dateHeight = uni.getSystemInfoSync().windowWidth / 7;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
init() {
|
||||||
|
this.initDateHeight();
|
||||||
|
let now = new Date();
|
||||||
|
this.year = now.getFullYear();
|
||||||
|
this.month = now.getMonth() + 1;
|
||||||
|
this.day = now.getDate();
|
||||||
|
this.today = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
|
||||||
|
this.activeDate = this.today;
|
||||||
|
this.min = this.initDate(this.minDate);
|
||||||
|
this.max = this.initDate(this.maxDate || this.today);
|
||||||
|
this.startDate = '';
|
||||||
|
this.startYear = 0;
|
||||||
|
this.startMonth = 0;
|
||||||
|
this.startDay = 0;
|
||||||
|
if (this.initStartDate) {
|
||||||
|
let start = new Date(this.initStartDate.replace(/\-/g, '/'));
|
||||||
|
if (this.type == 1) {
|
||||||
|
this.year = start.getFullYear();
|
||||||
|
this.month = start.getMonth() + 1;
|
||||||
|
this.day = start.getDate();
|
||||||
|
this.activeDate = `${start.getFullYear()}-${start.getMonth() + 1}-${start.getDate()}`;
|
||||||
|
} else {
|
||||||
|
this.startDate = `${start.getFullYear()}-${start.getMonth() + 1}-${start.getDate()}`;
|
||||||
|
this.startYear = start.getFullYear();
|
||||||
|
this.startMonth = start.getMonth() + 1;
|
||||||
|
this.startDay = start.getDate();
|
||||||
|
this.activeDate = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
this.endYear = 0;
|
||||||
|
this.endMonth = 0;
|
||||||
|
this.endDay = 0;
|
||||||
|
this.endDate = '';
|
||||||
|
if (this.initEndDate && this.type == 2) {
|
||||||
|
let end = new Date(this.initEndDate.replace(/\-/g, '/'));
|
||||||
|
this.endDate = `${end.getFullYear()}-${end.getMonth() + 1}-${end.getDate()}`;
|
||||||
|
this.endYear = end.getFullYear();
|
||||||
|
this.endMonth = end.getMonth() + 1;
|
||||||
|
this.endDay = end.getDate();
|
||||||
|
this.activeDate = '';
|
||||||
|
this.year = end.getFullYear();
|
||||||
|
this.month = end.getMonth() + 1;
|
||||||
|
this.day = end.getDate();
|
||||||
|
}
|
||||||
|
this.isStart = true;
|
||||||
|
this.changeData();
|
||||||
|
},
|
||||||
|
//日期处理
|
||||||
|
initDate(date) {
|
||||||
|
let fdate = date.split('-');
|
||||||
|
return {
|
||||||
|
year: Number(fdate[0] || 1920),
|
||||||
|
month: Number(fdate[1] || 1),
|
||||||
|
day: Number(fdate[2] || 1)
|
||||||
|
};
|
||||||
|
},
|
||||||
|
openDisAbled: function(year, month, day) {
|
||||||
|
let bool = true;
|
||||||
|
let date = `${year}/${month}/${day}`;
|
||||||
|
// let today = this.today.replace(/\-/g, '/');
|
||||||
|
let min = `${this.min.year}/${this.min.month}/${this.min.day}`;
|
||||||
|
let max = `${this.max.year}/${this.max.month}/${this.max.day}`;
|
||||||
|
let timestamp = new Date(date).getTime();
|
||||||
|
if (timestamp >= new Date(min).getTime() && timestamp <= new Date(max).getTime()) {
|
||||||
|
bool = false;
|
||||||
|
}
|
||||||
|
return bool;
|
||||||
|
},
|
||||||
|
generateArray: function(start, end) {
|
||||||
|
return Array.from(new Array(end + 1).keys()).slice(start);
|
||||||
|
},
|
||||||
|
formatNum: function(num) {
|
||||||
|
return num < 10 ? '0' + num : num + '';
|
||||||
|
},
|
||||||
|
stop() {
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
//一个月有多少天
|
||||||
|
getMonthDay(year, month) {
|
||||||
|
let days = new Date(year, month, 0).getDate();
|
||||||
|
return days;
|
||||||
|
},
|
||||||
|
getWeekday(year, month) {
|
||||||
|
let date = new Date(`${year}/${month}/01 00:00:00`);
|
||||||
|
return date.getDay();
|
||||||
|
},
|
||||||
|
checkRange(year) {
|
||||||
|
let overstep = false;
|
||||||
|
if (year < this.minYear || year > this.maxYear) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '日期超出范围啦~',
|
||||||
|
icon: 'none'
|
||||||
|
});
|
||||||
|
overstep = true;
|
||||||
|
}
|
||||||
|
return overstep;
|
||||||
|
},
|
||||||
|
changeMonth(isAdd) {
|
||||||
|
if (isAdd) {
|
||||||
|
let month = this.month + 1;
|
||||||
|
let year = month > 12 ? this.year + 1 : this.year;
|
||||||
|
if (!this.checkRange(year)) {
|
||||||
|
this.month = month > 12 ? 1 : month;
|
||||||
|
this.year = year;
|
||||||
|
this.changeData();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let month = this.month - 1;
|
||||||
|
let year = month < 1 ? this.year - 1 : this.year;
|
||||||
|
if (!this.checkRange(year)) {
|
||||||
|
this.month = month < 1 ? 12 : month;
|
||||||
|
this.year = year;
|
||||||
|
this.changeData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
changeYear(isAdd) {
|
||||||
|
let year = isAdd ? this.year + 1 : this.year - 1;
|
||||||
|
if (!this.checkRange(year)) {
|
||||||
|
this.year = year;
|
||||||
|
this.changeData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
changeData() {
|
||||||
|
this.days = this.getMonthDay(this.year, this.month);
|
||||||
|
this.daysArr = this.generateArray(1, this.days);
|
||||||
|
this.weekday = this.getWeekday(this.year, this.month);
|
||||||
|
this.weekdayArr = this.generateArray(1, this.weekday);
|
||||||
|
this.showTitle = `${this.year}年${this.month}月`;
|
||||||
|
if (this.isChange && this.type == 1) {
|
||||||
|
this.btnFix(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dateClick: function(day) {
|
||||||
|
day += 1;
|
||||||
|
if (!this.openDisAbled(this.year, this.month, day)) {
|
||||||
|
this.day = day;
|
||||||
|
let date = `${this.year}-${this.month}-${day}`;
|
||||||
|
if (this.type == 1) {
|
||||||
|
this.activeDate = date;
|
||||||
|
} else {
|
||||||
|
let compare = new Date(date.replace(/\-/g, '/')).getTime() < new Date(this.startDate.replace(
|
||||||
|
/\-/g, '/')).getTime();
|
||||||
|
if (this.isStart || compare) {
|
||||||
|
this.startDate = date;
|
||||||
|
this.startYear = this.year;
|
||||||
|
this.startMonth = this.month;
|
||||||
|
this.startDay = this.day;
|
||||||
|
this.endYear = 0;
|
||||||
|
this.endMonth = 0;
|
||||||
|
this.endDay = 0;
|
||||||
|
this.endDate = '';
|
||||||
|
this.activeDate = '';
|
||||||
|
this.isStart = false;
|
||||||
|
} else {
|
||||||
|
this.endDate = date;
|
||||||
|
this.endYear = this.year;
|
||||||
|
this.endMonth = this.month;
|
||||||
|
this.endDay = this.day;
|
||||||
|
this.isStart = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.isFixed) {
|
||||||
|
this.btnFix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
show() {
|
||||||
|
this.isShow = true;
|
||||||
|
},
|
||||||
|
hide() {
|
||||||
|
this.isShow = false;
|
||||||
|
this.$emit('hide', {})
|
||||||
|
},
|
||||||
|
getWeekText(date) {
|
||||||
|
date = new Date(`${date.replace(/\-/g, '/')} 00:00:00`);
|
||||||
|
let week = date.getDay();
|
||||||
|
return '星期' + ['日', '一', '二', '三', '四', '五', '六'][week];
|
||||||
|
},
|
||||||
|
btnFix(show) {
|
||||||
|
if (!show) {
|
||||||
|
this.hide();
|
||||||
|
}
|
||||||
|
if (this.type == 1) {
|
||||||
|
let arr = this.activeDate.split('-');
|
||||||
|
let year = this.isChange ? this.year : Number(arr[0]);
|
||||||
|
let month = this.isChange ? this.month : Number(arr[1]);
|
||||||
|
let day = this.isChange ? this.day : Number(arr[2]);
|
||||||
|
//当前月有多少天
|
||||||
|
let days = this.getMonthDay(year, month);
|
||||||
|
let result = `${year}-${this.formatNum(month)}-${this.formatNum(day)}`;
|
||||||
|
let weekText = this.getWeekText(result);
|
||||||
|
let isToday = false;
|
||||||
|
if (`${year}-${month}-${day}` == this.today) {
|
||||||
|
//今天
|
||||||
|
isToday = true;
|
||||||
|
}
|
||||||
|
let lunar = calendar.solar2lunar(year, month, day);
|
||||||
|
this.$emit('change', {
|
||||||
|
year: year,
|
||||||
|
month: month,
|
||||||
|
day: day,
|
||||||
|
days: days,
|
||||||
|
result: result,
|
||||||
|
week: weekText,
|
||||||
|
isToday: isToday,
|
||||||
|
switch: show, //是否是切换年月操作
|
||||||
|
lunar: lunar
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (!this.startDate || !this.endDate) return;
|
||||||
|
let startMonth = this.formatNum(this.startMonth);
|
||||||
|
let startDay = this.formatNum(this.startDay);
|
||||||
|
let startDate = `${this.startYear}-${startMonth}-${startDay}`;
|
||||||
|
let startWeek = this.getWeekText(startDate);
|
||||||
|
let startLunar = calendar.solar2lunar(this.startYear, startMonth, startDay);
|
||||||
|
|
||||||
|
let endMonth = this.formatNum(this.endMonth);
|
||||||
|
let endDay = this.formatNum(this.endDay);
|
||||||
|
let endDate = `${this.endYear}-${endMonth}-${endDay}`;
|
||||||
|
let endWeek = this.getWeekText(endDate);
|
||||||
|
let endLunar = calendar.solar2lunar(this.endYear, endMonth, endDay);
|
||||||
|
this.$emit('change', {
|
||||||
|
startYear: this.startYear,
|
||||||
|
startMonth: this.startMonth,
|
||||||
|
startDay: this.startDay,
|
||||||
|
startDate: startDate,
|
||||||
|
startWeek: startWeek,
|
||||||
|
startLunar: startLunar,
|
||||||
|
endYear: this.endYear,
|
||||||
|
endMonth: this.endMonth,
|
||||||
|
endDay: this.endDay,
|
||||||
|
endDate: endDate,
|
||||||
|
endWeek: endWeek,
|
||||||
|
endLunar: endLunar
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'tuiDateFont';
|
||||||
|
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAVgAA0AAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAFRAAAABoAAAAci0/w50dERUYAAAUkAAAAHgAAAB4AKQANT1MvMgAAAaAAAABDAAAAVjxuSNNjbWFwAAAB+AAAAEoAAAFS5iPQt2dhc3AAAAUcAAAACAAAAAj//wADZ2x5ZgAAAlQAAAFHAAABvPf29TBoZWFkAAABMAAAADAAAAA2GMsN3WhoZWEAAAFgAAAAHQAAACQHjAOFaG10eAAAAeQAAAATAAAAFgzQAPJsb2NhAAACRAAAABAAAAAQAOoBSG1heHAAAAGAAAAAHgAAACABEwA3bmFtZQAAA5wAAAFJAAACiCnmEVVwb3N0AAAE6AAAADQAAABLUwjqHHjaY2BkYGAAYp5Gj5/x/DZfGbhZGEDg1tUn7+F00P/LzOuY9YFcDgYmkCgAa0gNlHjaY2BkYGBu+N/AEMPCAALM6xgYGVABCwBT4AMaAAAAeNpjYGRgYGBn0GZgYgABEMkFhAwM/8F8BgANaAFLAAB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PGJ49ZG7438AQw9zA0AAUZgTJAQDrcAy8AHjaY2GAABYIDgLCBQx1AAcEAc8AeNpjYGBgZoBgGQZGBhDwAfIYwXwWBgMgzQGETAwMzxifcTx7+P8/kMUAYUkxS/6VVIXqAgNGNgY4lxGoB6QPBTAyDHsAADDkDYkAAAAAAAAAAAAAADQAagC2AN542m2QsU7DMBCG/Tt1bNPUiUnkSgiVtqKpxJAgVLVbeAa6MaK+B4JXgJWBjY21UtW5gpkdMTFX7dzApaJLhXU6n8+n//ttxtn458N79XJWZ8eMxS00C4wy9A1EP8PQncAlIQzS4WgsVtPpSmwzV3OFRqLetH5TSQMK939X61ptPZ2p2EAttNMLBRMrtschQblDeS34aY50cIkCzg/B2Y5C+VpyQxhFkRgu515O8jvU5mmPM2O0wJ5Z27vhX+yMsV437WvCdTM+GI40MgwKfuGammC0uURqeqFMfe9cxaJclkt5GMaB1hIR1VobOgpEiKq+sLZcIrJWhO3/Jw7qWlYj1Jf21FaCtmd5bevrlk28O/7A4spXTl4KTh9MTlqQ8PESBRstReic+sRj0Dni9fIqmNS/pXNWCvWOeYBmx5S9Bsn9Ah+5WtAAeNp9kD1OAzEQhZ/zByQSQiCoXVEA2vyUKRMp9Ailo0g23pBo1155nUg5AS0VB6DlGByAGyDRcgpelkmTImvt6PObmeexAZzjGwr/3yXuhBWO8ShcwREy4Sr1F+Ea+V24jhY+hRvUf4SbuFUD4RYu1BsdVO2Eu5vSbcsKZxgIV3CKJ+Eq9ZVwjfwqXMcVPoQb1L+EmxjjV7iFa2WpDOFhMEFgnEFjig3jAjEcLJIyBtahOfRmEsxMTzd6ETubOBso71dilwMeaDnngCntPbdmvkon/mDLgdSYbh4FS7YpjS4idCgbXyyc1d2oc7D9nu22tNi/a4E1x+xRDWzU/D3bM9JIbAyvkJI18jK3pBJTj2hrrPG7ZynW814IiU68y/SIx5o0dTr3bmniwOLn8owcfbS5kj33qBw+Y1kIeb/dTsQgil2GP5PYcRkAAAB42mNgYoAALjDJyIAO2MGiTIxMjMyMLIys7GmJeRmlmWZQ2pQ5OSORLaU0Mz2/FACDfwlbAAAAAf//AAIAAQAAAAwAAAAWAAAAAgABAAMABgABAAQAAAACAAAAAHjaY2BgYGQAgqtL1DlA9K2rT97DaABNlwiuAAA=) format('woff');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-iconfont {
|
||||||
|
font-family: 'tuiDateFont' !important;
|
||||||
|
font-size: 36rpx;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-font-close:before {
|
||||||
|
content: '\e608';
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-font-check:before {
|
||||||
|
content: '\e6e1';
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-font-arrowright:before {
|
||||||
|
content: '\e600';
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-font-arrowleft:before {
|
||||||
|
content: '\e601';
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-date-box {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 20rpx 0 30rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-calendar-radius {
|
||||||
|
border-top-left-radius: 20rpx;
|
||||||
|
border-top-right-radius: 20rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-date_time {
|
||||||
|
padding: 0 16rpx;
|
||||||
|
color: #333;
|
||||||
|
font-size: 32rpx;
|
||||||
|
line-height: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-font-arrowleft {
|
||||||
|
margin-right: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-font-arrowright {
|
||||||
|
margin-left: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-date-header {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: #fff;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 24rpx;
|
||||||
|
color: #555;
|
||||||
|
box-shadow: 0 15rpx 20rpx -15rpx #efefef;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-date-content {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 12rpx 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #fff;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-flex-start {
|
||||||
|
align-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-bg-month {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 260rpx;
|
||||||
|
line-height: 260rpx;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
color: #f5f5f7;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-date {
|
||||||
|
width: 14.2857%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 12rpx 0;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-date-pd_0 {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-start-date {
|
||||||
|
border-top-left-radius: 8rpx;
|
||||||
|
border-bottom-left-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-end-date {
|
||||||
|
border-top-right-radius: 8rpx;
|
||||||
|
border-bottom-right-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-date-text {
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 32rpx;
|
||||||
|
line-height: 32rpx;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-calendar {
|
||||||
|
padding: 16rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-opacity {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-bottom-popup {
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: 9999;
|
||||||
|
visibility: hidden;
|
||||||
|
transform: translate3d(0, 100%, 0);
|
||||||
|
transform-origin: center;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
min-height: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-popup-show {
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-popup-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
z-index: 9996;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-mask-show {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-calendar-header {
|
||||||
|
width: 100%;
|
||||||
|
height: 80rpx;
|
||||||
|
padding: 0 40rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 30rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
color: #555;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-font-close {
|
||||||
|
position: absolute;
|
||||||
|
right: 30rpx;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-calendar {
|
||||||
|
padding: 16rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-font-check {
|
||||||
|
color: #fff;
|
||||||
|
font-size: 54rpx;
|
||||||
|
line-height: 54rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-custom-desc {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 24rpx;
|
||||||
|
transform: scale(0.8);
|
||||||
|
transform-origin: center center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-lunar-unshow {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 8rpx;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-date-desc {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 24rpx;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
transform: scale(0.8);
|
||||||
|
transform-origin: center center;
|
||||||
|
text-align: center;
|
||||||
|
bottom: 8rpx;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-calendar-op {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 0 42rpx 30rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-calendar-result {
|
||||||
|
height: 48rpx;
|
||||||
|
transform: scale(0.9);
|
||||||
|
transform-origin: center 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-calendar-btn_box {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,212 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-card-class tui-card" :class="[full?'tui-card-full':'',border?'tui-card-border':'']" @tap="handleClick"
|
||||||
|
@longtap="longTap">
|
||||||
|
<view class="tui-card-header" :class="{'tui-header-line':header.line}" :style="{background:header.bgcolor || '#fff'}">
|
||||||
|
<view class="tui-header-left">
|
||||||
|
<image :src="image.url" class="tui-header-thumb" :class="{'tui-thumb-circle':image.circle}" mode="widthFix" v-if="image.url"
|
||||||
|
:style="{height:(image.height || 60)+'rpx',width:(image.width || 60)+'rpx'}"></image>
|
||||||
|
<text class="tui-header-title" :style="{fontSize:(title.size || 30)+'rpx',color:(title.color || '#7A7A7A')}" v-if="title.text">{{title.text}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="tui-header-right" :style="{fontSize:(tag.size || 24)+'rpx',color:(tag.color || '#b2b2b2')}" v-if="tag.text">
|
||||||
|
{{tag.text}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="tui-card-body">
|
||||||
|
<slot name="body"></slot>
|
||||||
|
</view>
|
||||||
|
<view class="tui-card-footer">
|
||||||
|
<slot name="footer"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "tuiCard",
|
||||||
|
emits: ['click','longclick'],
|
||||||
|
props: {
|
||||||
|
//是否铺满
|
||||||
|
full: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
image: {
|
||||||
|
type: Object,
|
||||||
|
default: function() {
|
||||||
|
return {
|
||||||
|
url: "", //图片地址
|
||||||
|
height: 60, //图片高度
|
||||||
|
width: 60, //图片宽度
|
||||||
|
circle: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//标题
|
||||||
|
title: {
|
||||||
|
type: Object,
|
||||||
|
default: function() {
|
||||||
|
return {
|
||||||
|
text: "", //标题文字
|
||||||
|
size: 30, //字体大小
|
||||||
|
color: "#7A7A7A" //字体颜色
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//标签,时间等
|
||||||
|
tag: {
|
||||||
|
type: Object,
|
||||||
|
default: function() {
|
||||||
|
return {
|
||||||
|
text: "", //标签文字
|
||||||
|
size: 24, //字体大小
|
||||||
|
color: "#b2b2b2" //字体颜色
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
type: Object,
|
||||||
|
default: function() {
|
||||||
|
return {
|
||||||
|
bgcolor: "#fff", //背景颜色
|
||||||
|
line: false //是否去掉底部线条
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//是否设置外边框
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
index: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClick() {
|
||||||
|
this.$emit('click', {
|
||||||
|
index: this.index
|
||||||
|
});
|
||||||
|
},
|
||||||
|
longTap() {
|
||||||
|
this.$emit('longclick', {
|
||||||
|
index: this.index
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-card {
|
||||||
|
margin: 0 30rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
box-shadow: 0 0 10rpx #eee;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-card-full {
|
||||||
|
margin: 0 !important;
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-card-full::after {
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-card-border {
|
||||||
|
position: relative;
|
||||||
|
box-shadow: none !important
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-card-border::after {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
height: 200%;
|
||||||
|
width: 200%;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
-webkit-transform-origin: 0 0;
|
||||||
|
-webkit-transform: scale(0.5);
|
||||||
|
transform: scale(0.5);
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-card-header {
|
||||||
|
width: 100%;
|
||||||
|
padding: 20rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
border-top-left-radius: 10rpx;
|
||||||
|
border-top-right-radius: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-card-header::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
border-bottom: 1rpx solid #eaeef1;
|
||||||
|
-webkit-transform: scaleY(0.5);
|
||||||
|
transform: scaleY(0.5);
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-header-line::after {
|
||||||
|
border-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-header-thumb {
|
||||||
|
height: 60rpx;
|
||||||
|
width: 60rpx;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-thumb-circle {
|
||||||
|
border-radius: 50% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-header-title {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 30rpx;
|
||||||
|
color: #7a7a7a;
|
||||||
|
vertical-align: middle;
|
||||||
|
max-width: 460rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-header-right {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #b2b2b2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-card-body {
|
||||||
|
font-size: 32rpx;
|
||||||
|
color: #262b3a;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-card-footer {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #596d96;
|
||||||
|
border-bottom-left-radius: 10rpx;
|
||||||
|
border-bottom-right-radius: 10rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,513 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-cascade-selection">
|
||||||
|
<scroll-view scroll-x scroll-with-animation :scroll-into-view="scrollViewId"
|
||||||
|
:style="{ backgroundColor: headerBgColor }" class="tui-bottom-line"
|
||||||
|
:class="{ 'tui-btm-none': !headerLine }">
|
||||||
|
<view class="tui-selection-header" :style="{ height: tabsHeight, backgroundColor: backgroundColor }">
|
||||||
|
<view class="tui-header-item" :class="{ 'tui-font-bold': idx === currentTab && bold }"
|
||||||
|
:style="{ color: idx === currentTab ? activeColor : color, fontSize: size + 'rpx' }"
|
||||||
|
:id="`id_${idx}`" @tap.stop="swichNav" :data-current="idx" v-for="(item, idx) in selectedArr"
|
||||||
|
:key="idx">
|
||||||
|
{{ item.text }}
|
||||||
|
<view class="tui-active-line" :style="{ backgroundColor: lineColor }"
|
||||||
|
v-if="idx === currentTab && showLine"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
<swiper class="tui-selection-list" :current="currentTab" duration="300" @change="switchTab"
|
||||||
|
:style="{ height: height, backgroundColor: backgroundColor }">
|
||||||
|
<swiper-item v-for="(item, index) in selectedArr" :key="index">
|
||||||
|
<scroll-view scroll-y :scroll-into-view="item.scrollViewId" class="tui-selection-item"
|
||||||
|
:style="{ height: height }">
|
||||||
|
<view class="tui-first-item" :style="{ height: firstItemTop }"></view>
|
||||||
|
<view class="tui-selection-cell" :style="{ padding: padding, backgroundColor: backgroundColor }"
|
||||||
|
:id="`id_${subIndex}`" v-for="(subItem, subIndex) in item.list" :key="subIndex"
|
||||||
|
@tap="change(index, subIndex, subItem)">
|
||||||
|
<icon type="success_no_circle" v-if="item.index === subIndex" :color="checkMarkColor"
|
||||||
|
:size="checkMarkSize" class="tui-icon-success"></icon>
|
||||||
|
<image :src="subItem.src" v-if="subItem.src" class="tui-cell-img"
|
||||||
|
:style="{ width: imgWidth, height: imgHeight, borderRadius: radius }"></image>
|
||||||
|
<view class="tui-cell-title"
|
||||||
|
:class="{ 'tui-font-bold': item.index === subIndex && textBold, 'tui-flex-shrink': nowrap }"
|
||||||
|
:style="{ color: item.index === subIndex ? textActiveColor : textColor, fontSize: textSize + 'rpx' }">
|
||||||
|
{{ subItem.text }}
|
||||||
|
</view>
|
||||||
|
<view class="tui-cell-sub_title" :style="{ color: subTextColor, fontSize: subTextSize + 'rpx' }"
|
||||||
|
v-if="subItem.subText">{{ subItem.subText }}</view>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiCascadeSelection',
|
||||||
|
emits: ['change','complete'],
|
||||||
|
props: {
|
||||||
|
/**
|
||||||
|
* 如果下一级是请求返回,则为第一级数据,否则所有数据
|
||||||
|
* 数据格式
|
||||||
|
[{
|
||||||
|
src: "",
|
||||||
|
text: "",
|
||||||
|
subText: "",
|
||||||
|
value: 0,
|
||||||
|
children:[{
|
||||||
|
text: "",
|
||||||
|
subText: "",
|
||||||
|
value: 0,
|
||||||
|
children:[]
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
* */
|
||||||
|
itemList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
初始化默认选中数据
|
||||||
|
[{
|
||||||
|
text: "",//选中text
|
||||||
|
subText: '',//选中subText
|
||||||
|
value: '',//选中value
|
||||||
|
src: '', //选中src,没有则传空或不传
|
||||||
|
index: 0, //选中数据在当前layer索引
|
||||||
|
list: [{src: "", text: "", subText: "", value: 101}] //当前layer下所有数据集合
|
||||||
|
}];
|
||||||
|
|
||||||
|
*/
|
||||||
|
defaultItemList: {
|
||||||
|
type: Array,
|
||||||
|
value: []
|
||||||
|
},
|
||||||
|
//是否显示header底部细线
|
||||||
|
headerLine: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//header背景颜色
|
||||||
|
headerBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#FFFFFF'
|
||||||
|
},
|
||||||
|
//顶部标签栏高度
|
||||||
|
tabsHeight: {
|
||||||
|
type: String,
|
||||||
|
default: '88rpx'
|
||||||
|
},
|
||||||
|
//默认显示文字
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: '请选择'
|
||||||
|
},
|
||||||
|
//tabs 文字大小
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 28
|
||||||
|
},
|
||||||
|
//tabs 文字颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#555'
|
||||||
|
},
|
||||||
|
//选中颜色
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#5677fc'
|
||||||
|
},
|
||||||
|
//选中后文字加粗
|
||||||
|
bold: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//选中后是否显示底部线条
|
||||||
|
showLine: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//线条颜色
|
||||||
|
lineColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#5677fc'
|
||||||
|
},
|
||||||
|
//icon 大小
|
||||||
|
checkMarkSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 15
|
||||||
|
},
|
||||||
|
//icon 颜色
|
||||||
|
checkMarkColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#5677fc'
|
||||||
|
},
|
||||||
|
//item 图片宽度
|
||||||
|
imgWidth: {
|
||||||
|
type: String,
|
||||||
|
default: '40rpx'
|
||||||
|
},
|
||||||
|
//item 图片高度
|
||||||
|
imgHeight: {
|
||||||
|
type: String,
|
||||||
|
default: '40rpx'
|
||||||
|
},
|
||||||
|
//图片圆角
|
||||||
|
radius: {
|
||||||
|
type: String,
|
||||||
|
default: '50%'
|
||||||
|
},
|
||||||
|
//item text颜色
|
||||||
|
textColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#333'
|
||||||
|
},
|
||||||
|
textActiveColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#333'
|
||||||
|
},
|
||||||
|
//选中后字体是否加粗
|
||||||
|
textBold: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//item text字体大小
|
||||||
|
textSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 28
|
||||||
|
},
|
||||||
|
//text 是否不换行
|
||||||
|
nowrap: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//item subText颜色
|
||||||
|
subTextColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#999'
|
||||||
|
},
|
||||||
|
//item subText字体大小
|
||||||
|
subTextSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 24
|
||||||
|
},
|
||||||
|
// item padding
|
||||||
|
padding: {
|
||||||
|
type: String,
|
||||||
|
default: '20rpx 30rpx'
|
||||||
|
},
|
||||||
|
//占位高度,第一条数据距离顶部距离
|
||||||
|
firstItemTop: {
|
||||||
|
type: String,
|
||||||
|
default: '20rpx'
|
||||||
|
},
|
||||||
|
//swiper 高度
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: '300px'
|
||||||
|
},
|
||||||
|
//item swiper 内容部分背景颜色
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#FFFFFF'
|
||||||
|
},
|
||||||
|
//子集数据是否请求返回(默认false,一次性返回所有数据)
|
||||||
|
request: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//子级数据(当有改变时,默认当前选中项新增子级数据,request=true时生效)
|
||||||
|
receiveData: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//改变值则重置数据
|
||||||
|
reset: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
itemList(val) {
|
||||||
|
this.initData(val, -1);
|
||||||
|
},
|
||||||
|
receiveData(val) {
|
||||||
|
this.subLevelData(val, this.currentTab);
|
||||||
|
},
|
||||||
|
reset() {
|
||||||
|
this.initData(this.itemList, -1);
|
||||||
|
},
|
||||||
|
defaultItemList(val) {
|
||||||
|
this.setDefaultData(val)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.setDefaultData(this.defaultItemList)
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
currentTab: 0,
|
||||||
|
//tab栏scrollview滚动的位置
|
||||||
|
scrollViewId: 'id__1',
|
||||||
|
selectedArr: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setDefaultData(val) {
|
||||||
|
let defaultItemList = val || [];
|
||||||
|
if (defaultItemList.length > 0) {
|
||||||
|
defaultItemList.map(item => {
|
||||||
|
item.scrollViewId = `id_${item.index}`;
|
||||||
|
});
|
||||||
|
this.selectedArr = defaultItemList;
|
||||||
|
this.currentTab = defaultItemList.length - 1;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.checkCor();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.initData(this.itemList, -1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
initData(data, layer) {
|
||||||
|
if (!data || data.length === 0) return;
|
||||||
|
if (this.request) {
|
||||||
|
//第一级数据
|
||||||
|
this.subLevelData(data, layer);
|
||||||
|
} else {
|
||||||
|
let selectedValue = this.selectedValue || {};
|
||||||
|
if (selectedValue.type) {
|
||||||
|
this.setDefaultData(selectedValue);
|
||||||
|
} else {
|
||||||
|
this.subLevelData(this.getItemList(layer, -1), layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeChildren(data) {
|
||||||
|
let list = data.map(item => {
|
||||||
|
delete item['children'];
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
},
|
||||||
|
getItemList(layer, index) {
|
||||||
|
let list = [];
|
||||||
|
let arr = JSON.parse(JSON.stringify(this.itemList));
|
||||||
|
if (layer == -1) {
|
||||||
|
list = this.removeChildren(arr);
|
||||||
|
} else {
|
||||||
|
let value = this.selectedArr[0].index;
|
||||||
|
value = value == -1 ? index : value;
|
||||||
|
list = arr[value].children || [];
|
||||||
|
if (layer > 0) {
|
||||||
|
for (let i = 1; i < layer + 1; i++) {
|
||||||
|
let val = layer === i ? index : this.selectedArr[i].index;
|
||||||
|
list = list[val].children || [];
|
||||||
|
if (list.length === 0) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list = this.removeChildren(list);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
},
|
||||||
|
//滚动切换
|
||||||
|
switchTab: function(e) {
|
||||||
|
this.currentTab = e.detail.current;
|
||||||
|
this.checkCor();
|
||||||
|
},
|
||||||
|
//点击标题切换当
|
||||||
|
swichNav: function(e) {
|
||||||
|
let cur = e.currentTarget.dataset.current;
|
||||||
|
if (this.currentTab != cur) {
|
||||||
|
this.currentTab = cur;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkCor: function() {
|
||||||
|
let item = this.selectedArr[this.currentTab];
|
||||||
|
item.scrollViewId = 'id__1';
|
||||||
|
this.$nextTick(() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
let val = item.index < 2 ? 0 : Number(item.index - 2);
|
||||||
|
item.scrollViewId = `id_${val}`;
|
||||||
|
}, 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.currentTab > 1) {
|
||||||
|
this.scrollViewId = `id_${this.currentTab - 1}`;
|
||||||
|
} else {
|
||||||
|
this.scrollViewId = `id_0`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
change(index, subIndex, subItem) {
|
||||||
|
let item = this.selectedArr[index];
|
||||||
|
if (item.index == subIndex) return;
|
||||||
|
item.index = subIndex;
|
||||||
|
item.text = subItem.text;
|
||||||
|
item.value = subItem.value;
|
||||||
|
item.subText = subItem.subText || '';
|
||||||
|
item.src = subItem.src || '';
|
||||||
|
this.$emit('change', {
|
||||||
|
layer: index,
|
||||||
|
subIndex: subIndex, //layer=> Array index
|
||||||
|
...subItem
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.request) {
|
||||||
|
let data = this.getItemList(index, subIndex);
|
||||||
|
this.subLevelData(data, index);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//新增子级数据时处理
|
||||||
|
subLevelData(data, layer) {
|
||||||
|
if (!data || data.length === 0) {
|
||||||
|
if (layer == -1) return;
|
||||||
|
//完成选择
|
||||||
|
let arr = this.selectedArr;
|
||||||
|
if (layer < arr.length - 1) {
|
||||||
|
let newArr = arr.slice(0, layer + 1);
|
||||||
|
this.selectedArr = newArr;
|
||||||
|
}
|
||||||
|
let result = JSON.parse(JSON.stringify(this.selectedArr));
|
||||||
|
let lastItem = result[result.length - 1] || {};
|
||||||
|
let text = '';
|
||||||
|
result.map(item => {
|
||||||
|
text += item.text;
|
||||||
|
delete item['list'];
|
||||||
|
//delete item['index'];
|
||||||
|
delete item['scrollViewId'];
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
this.$emit('complete', {
|
||||||
|
result: result,
|
||||||
|
value: lastItem.value,
|
||||||
|
text: text,
|
||||||
|
subText: lastItem.subText,
|
||||||
|
src: lastItem.src
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
//重置数据( >layer层级)
|
||||||
|
let item = [{
|
||||||
|
text: this.text,
|
||||||
|
subText: '',
|
||||||
|
value: '',
|
||||||
|
src: '',
|
||||||
|
index: -1,
|
||||||
|
scrollViewId: 'id__1',
|
||||||
|
list: data
|
||||||
|
}];
|
||||||
|
if (layer == -1) {
|
||||||
|
this.selectedArr = item;
|
||||||
|
} else {
|
||||||
|
let retainArr = this.selectedArr.slice(0, layer + 1);
|
||||||
|
this.selectedArr = retainArr.concat(item);
|
||||||
|
}
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.currentTab = this.selectedArr.length - 1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-cascade-selection {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-selection-header {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-bottom-line {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-bottom-line::after {
|
||||||
|
width: 100%;
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
border-bottom: 1rpx solid #eaeef1;
|
||||||
|
-webkit-transform: scaleY(0.5) translateZ(0);
|
||||||
|
transform: scaleY(0.5) translateZ(0);
|
||||||
|
transform-origin: 0 100%;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btm-none::after {
|
||||||
|
border-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-header-item {
|
||||||
|
max-width: 240rpx;
|
||||||
|
padding: 15rpx 30rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
flex-shrink: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-font-bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-active-line {
|
||||||
|
width: 60rpx;
|
||||||
|
height: 6rpx;
|
||||||
|
border-radius: 4rpx;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-selection-cell {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-icon-success {
|
||||||
|
margin-right: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-cell-img {
|
||||||
|
margin-right: 12rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-cell-title {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-flex-shrink {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-font-bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-cell-sub_title {
|
||||||
|
margin-left: 20rpx;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-first-item {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,265 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-circular-container" :style="{ width: diam + 'px', height: (height || diam) + 'px' }">
|
||||||
|
<canvas
|
||||||
|
class="tui-circular-default"
|
||||||
|
:canvas-id="defaultCanvasId"
|
||||||
|
:id="defaultCanvasId"
|
||||||
|
:style="{ width: diam + 'px', height: (height || diam) + 'px' }"
|
||||||
|
v-if="defaultShow"
|
||||||
|
></canvas>
|
||||||
|
<canvas class="tui-circular-progress" :canvas-id="progressCanvasId" :id="progressCanvasId" :style="{ width: diam + 'px', height: (height || diam) + 'px' }"></canvas>
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiCircularProgress',
|
||||||
|
emits: ['change','end'],
|
||||||
|
props: {
|
||||||
|
/*
|
||||||
|
传值需使用rpx进行转换保证各终端兼容
|
||||||
|
px = rpx / 750 * wx.getSystemInfoSync().windowWidth
|
||||||
|
圆形进度条(画布)宽度,直径 [px]
|
||||||
|
*/
|
||||||
|
diam: {
|
||||||
|
type: Number,
|
||||||
|
default: 60
|
||||||
|
},
|
||||||
|
//圆形进度条(画布)高度,默认取diam值[当画半弧时传值,height有值时则取height]
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
//进度条线条宽度[px]
|
||||||
|
lineWidth: {
|
||||||
|
type: Number,
|
||||||
|
default: 4
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
线条的端点样式
|
||||||
|
butt:向线条的每个末端添加平直的边缘
|
||||||
|
round 向线条的每个末端添加圆形线帽
|
||||||
|
square 向线条的每个末端添加正方形线帽
|
||||||
|
*/
|
||||||
|
lineCap: {
|
||||||
|
type: String,
|
||||||
|
default: 'round'
|
||||||
|
},
|
||||||
|
//圆环进度字体大小 [px]
|
||||||
|
fontSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 12
|
||||||
|
},
|
||||||
|
//圆环进度字体颜色
|
||||||
|
fontColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#5677fc'
|
||||||
|
},
|
||||||
|
//是否显示进度文字
|
||||||
|
fontShow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
/*
|
||||||
|
自定义显示文字[默认为空,显示百分比,fontShow=true时生效]
|
||||||
|
可以使用 slot自定义显示内容
|
||||||
|
*/
|
||||||
|
percentText: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
//是否显示默认(背景)进度条
|
||||||
|
defaultShow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//默认进度条颜色
|
||||||
|
defaultColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#CCC'
|
||||||
|
},
|
||||||
|
//进度条颜色
|
||||||
|
progressColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#5677fc'
|
||||||
|
},
|
||||||
|
//进度条渐变颜色[结合progressColor使用,默认为空]
|
||||||
|
gradualColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
//起始弧度,单位弧度
|
||||||
|
sAngle: {
|
||||||
|
type: Number,
|
||||||
|
default: -Math.PI / 2
|
||||||
|
},
|
||||||
|
//指定弧度的方向是逆时针还是顺时针。默认是false,即顺时针
|
||||||
|
counterclockwise: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//进度百分比 [10% 传值 10]
|
||||||
|
percentage: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
//进度百分比缩放倍数[使用半弧为100%时,则可传2]
|
||||||
|
multiple: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
//动画执行时间[单位毫秒,低于50无动画]
|
||||||
|
duration: {
|
||||||
|
type: Number,
|
||||||
|
default: 800
|
||||||
|
},
|
||||||
|
//backwards: 动画从头播;forwards:动画从上次结束点接着播
|
||||||
|
activeMode: {
|
||||||
|
type: String,
|
||||||
|
default: 'backwards'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
percentage(val) {
|
||||||
|
this.initDraw();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
progressCanvasId: 'progressCanvasId',
|
||||||
|
defaultCanvasId: 'defaultCanvasId',
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
progressCanvasId: this.getCanvasId(),
|
||||||
|
defaultCanvasId: this.getCanvasId(),
|
||||||
|
// #endif
|
||||||
|
progressContext: null,
|
||||||
|
linearGradient: null,
|
||||||
|
//起始百分比
|
||||||
|
startPercentage: 0
|
||||||
|
// dpi
|
||||||
|
//pixelRatio: uni.getSystemInfoSync().pixelRatio
|
||||||
|
};
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.initDraw(true);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
//初始化绘制
|
||||||
|
initDraw(init) {
|
||||||
|
let start = this.activeMode === 'backwards' ? 0 : this.startPercentage;
|
||||||
|
start = start > this.percentage ? 0 : start;
|
||||||
|
if (this.defaultShow && init) {
|
||||||
|
this.drawDefaultCircular();
|
||||||
|
}
|
||||||
|
this.drawProgressCircular(start);
|
||||||
|
},
|
||||||
|
//默认(背景)圆环
|
||||||
|
drawDefaultCircular() {
|
||||||
|
let ctx = uni.createCanvasContext(this.defaultCanvasId, this);
|
||||||
|
ctx.setLineWidth(this.lineWidth);
|
||||||
|
ctx.setStrokeStyle(this.defaultColor);
|
||||||
|
//终止弧度
|
||||||
|
let eAngle = Math.PI * (this.height ? 1 : 2) + this.sAngle;
|
||||||
|
this.drawArc(ctx, eAngle);
|
||||||
|
},
|
||||||
|
//进度圆环
|
||||||
|
drawProgressCircular(startPercentage) {
|
||||||
|
let ctx = this.progressContext;
|
||||||
|
let gradient = this.linearGradient;
|
||||||
|
if (!ctx) {
|
||||||
|
ctx = uni.createCanvasContext(this.progressCanvasId, this);
|
||||||
|
//创建一个线性的渐变颜色 CanvasGradient对象
|
||||||
|
gradient = ctx.createLinearGradient(0, 0, this.diam, 0);
|
||||||
|
gradient.addColorStop('0', this.progressColor);
|
||||||
|
if (this.gradualColor) {
|
||||||
|
gradient.addColorStop('1', this.gradualColor);
|
||||||
|
}
|
||||||
|
// #ifdef APP-PLUS || MP
|
||||||
|
const res = uni.getSystemInfoSync();
|
||||||
|
if (!this.gradualColor && res.platform.toLocaleLowerCase() == 'android') {
|
||||||
|
gradient.addColorStop('1', this.progressColor);
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
this.progressContext = ctx;
|
||||||
|
this.linearGradient = gradient;
|
||||||
|
}
|
||||||
|
ctx.setLineWidth(this.lineWidth);
|
||||||
|
ctx.setStrokeStyle(gradient);
|
||||||
|
let time = this.percentage == 0 || this.duration < 50 ? 0 : this.duration / this.percentage;
|
||||||
|
if (this.percentage > 0) {
|
||||||
|
startPercentage = this.duration < 50 ? this.percentage - 1 : startPercentage;
|
||||||
|
startPercentage++;
|
||||||
|
}
|
||||||
|
if (this.fontShow) {
|
||||||
|
ctx.setFontSize(this.fontSize);
|
||||||
|
ctx.setFillStyle(this.fontColor);
|
||||||
|
ctx.setTextAlign('center');
|
||||||
|
ctx.setTextBaseline('middle');
|
||||||
|
let percentage = this.percentText;
|
||||||
|
if (!percentage) {
|
||||||
|
percentage = this.counterclockwise ? 100 - startPercentage * this.multiple : startPercentage * this.multiple;
|
||||||
|
percentage = `${percentage}%`;
|
||||||
|
}
|
||||||
|
let radius = this.diam / 2;
|
||||||
|
ctx.fillText(percentage, radius, radius);
|
||||||
|
}
|
||||||
|
if (this.percentage == 0 || (this.counterclockwise && startPercentage == 100)) {
|
||||||
|
ctx.draw();
|
||||||
|
}else{
|
||||||
|
let eAngle = ((2 * Math.PI) / 100) * startPercentage + this.sAngle;
|
||||||
|
this.drawArc(ctx, eAngle);
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
this.startPercentage = startPercentage;
|
||||||
|
if (startPercentage == this.percentage) {
|
||||||
|
this.$emit('end', {
|
||||||
|
canvasId: this.progressCanvasId,
|
||||||
|
percentage: startPercentage
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.drawProgressCircular(startPercentage);
|
||||||
|
}
|
||||||
|
this.$emit('change', {
|
||||||
|
percentage: startPercentage
|
||||||
|
});
|
||||||
|
}, time);
|
||||||
|
// #ifdef H5
|
||||||
|
// requestAnimationFrame(()=>{})
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
//创建弧线
|
||||||
|
drawArc(ctx, eAngle) {
|
||||||
|
ctx.setLineCap(this.lineCap);
|
||||||
|
ctx.beginPath();
|
||||||
|
let radius = this.diam / 2; //x=y
|
||||||
|
ctx.arc(radius, radius, radius - this.lineWidth, this.sAngle, eAngle, this.counterclockwise);
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.draw();
|
||||||
|
},
|
||||||
|
//生成canvasId
|
||||||
|
getCanvasId() {
|
||||||
|
let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
|
||||||
|
return (c === 'x' ? (Math.random() * 16) | 0 : 'r&0x3' | '0x8').toString(16);
|
||||||
|
});
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-circular-container,
|
||||||
|
.tui-circular-default {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-circular-progress {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,167 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-collapse" :style="{backgroundColor:bgColor}">
|
||||||
|
<view class="tui-collapse-head" :style="{backgroundColor:hdBgColor}" @tap.stop="handleClick">
|
||||||
|
<view class="tui-header" :class="{'tui-opacity':disabled}">
|
||||||
|
<slot name="title"></slot>
|
||||||
|
<view class="tui-collapse-icon tui-icon-arrow" :class="{'tui-icon-active':isOpen}" :style="{color:arrowColor}" v-if="arrow"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="tui-collapse-body_box" :style="{backgroundColor:bdBgColor,height:isOpen?height:'0rpx'}">
|
||||||
|
<view class="tui-collapse-body" :class="{'tui-collapse-transform':height=='auto','tui-collapse-body_show':isOpen && height=='auto'}">
|
||||||
|
<slot name="content"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "tuiCollapse",
|
||||||
|
emits: ['click'],
|
||||||
|
props: {
|
||||||
|
//collapse背景颜色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'transparent'
|
||||||
|
},
|
||||||
|
//collapse-head 背景颜色
|
||||||
|
hdBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#fff'
|
||||||
|
},
|
||||||
|
//collapse-body 背景颜色
|
||||||
|
bdBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'transparent'
|
||||||
|
},
|
||||||
|
//collapse-body实际高度 open时使用
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
//索引
|
||||||
|
index: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
//当前索引,index==current时展开
|
||||||
|
current: {
|
||||||
|
type: Number,
|
||||||
|
default: -1
|
||||||
|
},
|
||||||
|
// 是否禁用
|
||||||
|
disabled: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//是否带箭头
|
||||||
|
arrow: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//箭头颜色
|
||||||
|
arrowColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#333"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
current() {
|
||||||
|
this.updateCurrentChange()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.updateCurrentChange()
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isOpen: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateCurrentChange() {
|
||||||
|
this.isOpen = this.index == this.current
|
||||||
|
},
|
||||||
|
handleClick() {
|
||||||
|
if (this.disabled) return;
|
||||||
|
this.$emit("click", {
|
||||||
|
index: Number(this.index)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'tuiCollapse';
|
||||||
|
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAQ4AA0AAAAABlgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAEHAAAABoAAAAciRx3B0dERUYAAAP8AAAAHgAAAB4AKQAKT1MvMgAAAaAAAABCAAAAVjxuR/JjbWFwAAAB9AAAAD4AAAFCAA/pq2dhc3AAAAP0AAAACAAAAAj//wADZ2x5ZgAAAkAAAABEAAAARCs1U/toZWFkAAABMAAAADAAAAA2FpaT+mhoZWEAAAFgAAAAHQAAACQHngOFaG10eAAAAeQAAAAPAAAAEAwAAEBsb2NhAAACNAAAAAoAAAAKACIAAG1heHAAAAGAAAAAHwAAACABDwAdbmFtZQAAAoQAAAFJAAACiCnmEVVwb3N0AAAD0AAAACMAAAA1DunpUnjaY2BkYGAAYja/oO54fpuvDNwsDCBwc4/6fzjtwNDNfICpBMjlYGACiQIAGVAKZnjaY2BkYGBu+N/AEMPCAALMBxgYGVABCwBVNgMsAAAAeNpjYGRgYGBhEGQA0QwMTEDMBYQMDP/BfAYACnYBLQB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PGJ4xMDf8b2CIYW5gaAAKM4LkANq9C9sAAHjaY2GAABYIdgAAAMAATQB42mNgYGBmgGAZBkYGELAB8hjBfBYGBSDNAoRA/jOG//8hpBQzVCUDIxsDjMnAyAQkmBhQASPDsAcAMCAGoQAAAAAAAAAAAAAAIgAAAAEAQACLA8ACdAAQAAAlASYiBhQXARYyNwE2NCYiBwIA/oYNIBkMAZcNIA0BlwwZIA3uAXoMGSAN/mkMDAGXDSAZDAB42n2QPU4DMRCFn/MHJBJCIKhdUQDa/JQpEyn0CKWjSDbekGjXXnmdSDkBLRUHoOUYHIAbINFyCl6WSZMia+3o85uZ57EBnOMbCv/fJe6EFY7xKFzBETLhKvUX4Rr5XbiOFj6FG9R/hJu4VQPhFi7UGx1U7YS7m9JtywpnGAhXcIon4Sr1lXCN/CpcxxU+hBvUv4SbGONXuIVrZakM4WEwQWCcQWOKDeMCMRwskjIG1qE59GYSzExPN3oRO5s4GyjvV2KXAx5oOeeAKe09t2a+Sif+YMuB1JhuHgVLtimNLiJ0KBtfLJzV3ahzsP2e7ba02L9rgTXH7FENbNT8Pdsz0khsDK+QkjXyMrekElOPaGus8btnKdbzXgiJTrzL9IjHmjR1OvduaeLA4ufyjBx9tLmSPfeoHD5jWQh5v91OxCCKXYY/k9hxGQAAAHjaY2BigAAuMMnIgA5YwKJMjExciUVF+eW6KfnleQAZ0wQyAAAAAAH//wACAAEAAAAMAAAAFgAAAAIAAQADAAMAAQAEAAAAAgAAAAB42mNgYGBkAIKrS9Q5QPTNPer/YTQAQ+0HIAAA) format('woff');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-collapse-icon {
|
||||||
|
font-family: "tuiCollapse" !important;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-icon-arrow:before {
|
||||||
|
content: "\e600";
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-icon-arrow {
|
||||||
|
font-size: 32rpx;
|
||||||
|
transform: rotate(0);
|
||||||
|
transform-origin: center center;
|
||||||
|
transition: all 0.3s;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -8px;
|
||||||
|
right: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-arrow-padding {
|
||||||
|
padding-right: 62rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-icon-active {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
transform-origin: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-header {
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
.tui-collapse-body_box{
|
||||||
|
transition: all 0.25s;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.tui-collapse-body {
|
||||||
|
transition: all 0.25s;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-collapse-transform {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
-webkit-transform: translateY(-40%);
|
||||||
|
transform: translateY(-40%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-collapse-body_show {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
-webkit-transform: translateY(0);
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-opacity {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,343 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-countdown-box">
|
||||||
|
<view class="tui-countdown-item" :style="{ background: backgroundColor, borderColor: borderColor, width: getWidth(d, width) + 'rpx', height: height + 'rpx' }" v-if="days">
|
||||||
|
<view class="tui-countdown-time" :class="[scale ? 'tui-countdown-scale' : '']" :style="{ fontSize: size + 'rpx', color: color, lineHeight: size + 'rpx' }">
|
||||||
|
{{ d }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="tui-countdown-colon"
|
||||||
|
:class="{ 'tui-colon-pad': borderColor == 'transparent' }"
|
||||||
|
:style="{ lineHeight: colonSize + 'rpx', fontSize: colonSize + 'rpx', color: colonColor }"
|
||||||
|
v-if="days"
|
||||||
|
>
|
||||||
|
{{ isColon ? ':' : '天' }}
|
||||||
|
</view>
|
||||||
|
<view class="tui-countdown-item" :style="{ background: backgroundColor, borderColor: borderColor, width: getWidth(h, width) + 'rpx', height: height + 'rpx' }" v-if="hours">
|
||||||
|
<view class="tui-countdown-time" :class="[scale ? 'tui-countdown-scale' : '']" :style="{ fontSize: size + 'rpx', color: color, lineHeight: size + 'rpx' }">
|
||||||
|
{{ h }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="tui-countdown-colon"
|
||||||
|
:class="{ 'tui-colon-pad': borderColor == 'transparent' }"
|
||||||
|
:style="{ lineHeight: colonSize + 'rpx', fontSize: colonSize + 'rpx', color: colonColor }"
|
||||||
|
v-if="hours"
|
||||||
|
>
|
||||||
|
{{ isColon ? ':' : '时' }}
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="tui-countdown-item"
|
||||||
|
:style="{ background: backgroundColor, borderColor: borderColor, width: getWidth(i, width) + 'rpx', height: height + 'rpx' }"
|
||||||
|
v-if="minutes"
|
||||||
|
>
|
||||||
|
<view class="tui-countdown-time" :class="[scale ? 'tui-countdown-scale' : '']" :style="{ fontSize: size + 'rpx', color: color, lineHeight: size + 'rpx' }">
|
||||||
|
{{ i }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="tui-countdown-colon"
|
||||||
|
:class="{ 'tui-colon-pad': borderColor == 'transparent' }"
|
||||||
|
:style="{ lineHeight: colonSize + 'rpx', fontSize: colonSize + 'rpx', color: colonColor }"
|
||||||
|
v-if="minutes"
|
||||||
|
>
|
||||||
|
{{ isColon ? ':' : '分' }}
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="tui-countdown-item"
|
||||||
|
:style="{ background: backgroundColor, borderColor: borderColor, width: getWidth(s, width) + 'rpx', height: height + 'rpx' }"
|
||||||
|
v-if="seconds"
|
||||||
|
>
|
||||||
|
<view class="tui-countdown-time" :class="[scale ? 'tui-countdown-scale' : '']" :style="{ fontSize: size + 'rpx', color: color, lineHeight: size + 'rpx' }">
|
||||||
|
{{ s }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="tui-countdown-colon"
|
||||||
|
:class="{ 'tui-colon-pad': borderColor == 'transparent' }"
|
||||||
|
:style="{ lineHeight: colonSize + 'rpx', fontSize: colonSize + 'rpx', color: colonColor }"
|
||||||
|
v-if="seconds && !isColon"
|
||||||
|
>
|
||||||
|
{{ unitEn ? 's' : '秒' }}
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="tui-countdown-colon" :style="{ lineHeight: colonSize + 'rpx', fontSize: colonSize + 'rpx', color: colonColor }" v-if="seconds && isMs && isColon">.</view>
|
||||||
|
<view
|
||||||
|
class="tui-countdown__ms"
|
||||||
|
:style="{
|
||||||
|
background: backgroundColor,
|
||||||
|
borderColor: borderColor,
|
||||||
|
fontSize: msSize + 'rpx',
|
||||||
|
color: msColor,
|
||||||
|
height: height + 'rpx',
|
||||||
|
width: msWidth > 0 ? msWidth + 'rpx' : 'auto'
|
||||||
|
}"
|
||||||
|
v-if="seconds && isMs"
|
||||||
|
>
|
||||||
|
<view :class="{ 'tui-ms__list': ani }">
|
||||||
|
<view class="tui-ms__item" :style="{ height: height + 'rpx' }" v-for="(item, index) in ms" :key="index">
|
||||||
|
<view :class="[scale ? 'tui-countdown-scale' : '']">{{item}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiCountdown',
|
||||||
|
emits: ['end','time'],
|
||||||
|
props: {
|
||||||
|
//数字框宽度
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 32
|
||||||
|
},
|
||||||
|
//数字框高度
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 32
|
||||||
|
},
|
||||||
|
//数字框border颜色
|
||||||
|
borderColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#333'
|
||||||
|
},
|
||||||
|
//数字框背景颜色
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#fff'
|
||||||
|
},
|
||||||
|
//数字框字体大小
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 24
|
||||||
|
},
|
||||||
|
//数字框字体颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#333'
|
||||||
|
},
|
||||||
|
//是否缩放 0.9
|
||||||
|
scale: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//冒号大小
|
||||||
|
colonSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 28
|
||||||
|
},
|
||||||
|
//冒号颜色
|
||||||
|
colonColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#333'
|
||||||
|
},
|
||||||
|
//剩余时间 (单位:秒)
|
||||||
|
time: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
//是否包含天
|
||||||
|
days: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//是否包含小时
|
||||||
|
hours: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//是否包含分钟
|
||||||
|
minutes: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//是否包含秒
|
||||||
|
seconds: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//单位用英文缩写表示 仅seconds秒数有效
|
||||||
|
unitEn: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//是否展示为冒号,false为文字
|
||||||
|
isColon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//是否返回剩余时间
|
||||||
|
returnTime: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//是否显示毫秒
|
||||||
|
isMs: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
msWidth: {
|
||||||
|
type: Number,
|
||||||
|
default: 32
|
||||||
|
},
|
||||||
|
msSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 24
|
||||||
|
},
|
||||||
|
msColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#333'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
time(val) {
|
||||||
|
this.clearTimer();
|
||||||
|
this.doLoop();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
countdown: null,
|
||||||
|
d: '0',
|
||||||
|
h: '00',
|
||||||
|
i: '00',
|
||||||
|
s: '00',
|
||||||
|
//此处若从9到1,结束需要特殊处理
|
||||||
|
ms: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||||
|
ani: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.clearTimer();
|
||||||
|
this.doLoop();
|
||||||
|
},
|
||||||
|
// #ifndef VUE3
|
||||||
|
beforeDestroy() {
|
||||||
|
this.clearTimer();
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
// #ifdef VUE3
|
||||||
|
beforeUnmount(){
|
||||||
|
this.clearTimer();
|
||||||
|
},
|
||||||
|
// #endif
|
||||||
|
methods: {
|
||||||
|
getWidth: function(num, width) {
|
||||||
|
return num > 99 ? (width / 2) * num.toString().length : width;
|
||||||
|
},
|
||||||
|
clearTimer() {
|
||||||
|
clearInterval(this.countdown);
|
||||||
|
this.countdown = null;
|
||||||
|
},
|
||||||
|
endOfTime() {
|
||||||
|
this.ani = false;
|
||||||
|
this.clearTimer();
|
||||||
|
this.$emit('end', {});
|
||||||
|
},
|
||||||
|
doLoop: function() {
|
||||||
|
let seconds = this.time || 0;
|
||||||
|
this.ani = true;
|
||||||
|
this.countDown(seconds);
|
||||||
|
this.countdown = setInterval(() => {
|
||||||
|
seconds--;
|
||||||
|
if (seconds < 0) {
|
||||||
|
this.endOfTime();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.countDown(seconds);
|
||||||
|
if (this.returnTime) {
|
||||||
|
this.$emit('time', { seconds: seconds });
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
countDown(seconds) {
|
||||||
|
let [day, hour, minute, second] = [0, 0, 0, 0];
|
||||||
|
if (seconds > 0) {
|
||||||
|
day = this.days ? Math.floor(seconds / (60 * 60 * 24)) : 0;
|
||||||
|
hour = this.hours ? Math.floor(seconds / (60 * 60)) - day * 24 : 0;
|
||||||
|
minute = this.minutes ? Math.floor(seconds / 60) - hour * 60 - day * 24 * 60 : 0;
|
||||||
|
second = Math.floor(seconds) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60;
|
||||||
|
} else {
|
||||||
|
this.endOfTime();
|
||||||
|
}
|
||||||
|
hour = hour < 10 ? '0' + hour : hour;
|
||||||
|
minute = minute < 10 ? '0' + minute : minute;
|
||||||
|
second = second < 10 ? '0' + second : second;
|
||||||
|
this.d = day;
|
||||||
|
this.h = hour;
|
||||||
|
this.i = minute;
|
||||||
|
this.s = second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-countdown-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-countdown-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-countdown-item {
|
||||||
|
border: 1rpx solid;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
white-space: nowrap;
|
||||||
|
transform: translateZ(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-countdown-time {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-countdown-colon {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 5rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-colon-pad {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-countdown-scale {
|
||||||
|
transform: scale(0.9);
|
||||||
|
transform-origin: center center;
|
||||||
|
}
|
||||||
|
.tui-countdown__ms {
|
||||||
|
border: 1rpx solid;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*ms使用css3代替js频繁更新操作,性能优化*/
|
||||||
|
.tui-ms__list {
|
||||||
|
animation: loop 1s steps(10) infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loop {
|
||||||
|
from {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: translateY(-100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-ms__item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,103 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-divider" :style="{ height: height + 'rpx' }">
|
||||||
|
<view class="tui-divider-line" :style="{ width: width, background: getBgColor(gradual, gradualColor, dividerColor) }"></view>
|
||||||
|
<view
|
||||||
|
class="tui-divider-text"
|
||||||
|
:style="{ color: color, fontSize: size + 'rpx', lineHeight: size + 'rpx', backgroundColor: backgroundColor, fontWeight: bold ? 'bold' : 'normal' }"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiDivider',
|
||||||
|
props: {
|
||||||
|
//divider占据高度
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 100
|
||||||
|
},
|
||||||
|
//divider宽度,可填写具体长度,如400rpx
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '100%'
|
||||||
|
},
|
||||||
|
//divider颜色,如果为渐变线条,此属性失效
|
||||||
|
dividerColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#e5e5e5'
|
||||||
|
},
|
||||||
|
//文字颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#999'
|
||||||
|
},
|
||||||
|
//文字大小 rpx
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 24
|
||||||
|
},
|
||||||
|
bold: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//背景颜色,和当前页面背景色保持一致
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#fafafa'
|
||||||
|
},
|
||||||
|
//是否为渐变线条,为true,divideColor失效
|
||||||
|
gradual: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//渐变色值,to right ,提供两个色值即可,由浅至深
|
||||||
|
gradualColor: {
|
||||||
|
type: Array,
|
||||||
|
default: function() {
|
||||||
|
return ['#eee', '#ccc'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getBgColor: function(gradual, gradualColor, dividerColor) {
|
||||||
|
let bgColor = dividerColor;
|
||||||
|
if (gradual) {
|
||||||
|
bgColor = 'linear-gradient(to right,' + gradualColor[0] + ',' + gradualColor[1] + ',' + gradualColor[1] + ',' + gradualColor[0] + ')';
|
||||||
|
}
|
||||||
|
return bgColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-divider {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-divider-line {
|
||||||
|
position: absolute;
|
||||||
|
height: 1rpx;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
-webkit-transform: scaleY(0.5) translateX(-50%) translateZ(0);
|
||||||
|
transform: scaleY(0.5) translateX(-50%) translateZ(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-divider-text {
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 18rpx;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,140 @@
|
||||||
|
<template>
|
||||||
|
<!-- @touchmove.stop.prevent -->
|
||||||
|
<view>
|
||||||
|
<view v-if="mask" class="tui-drawer-mask" :class="{ 'tui-drawer-mask_show': visible }" :style="{ zIndex: maskZIndex }" @tap="handleMaskClick"></view>
|
||||||
|
<view
|
||||||
|
class="tui-drawer-container"
|
||||||
|
:class="[`tui-drawer-container_${mode}`, visible ? `tui-drawer-${mode}__show` : '']"
|
||||||
|
:style="{ zIndex: zIndex, backgroundColor: backgroundColor }"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 超过一屏时插槽使用scroll-view
|
||||||
|
**/
|
||||||
|
export default {
|
||||||
|
name: 'tuiDrawer',
|
||||||
|
emits: ['close'],
|
||||||
|
props: {
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
mask: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
maskClosable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// left right bottom top
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'right'
|
||||||
|
},
|
||||||
|
//drawer z-index
|
||||||
|
zIndex: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 9999
|
||||||
|
},
|
||||||
|
//mask z-index
|
||||||
|
maskZIndex: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 9998
|
||||||
|
},
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#17172F'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleMaskClick() {
|
||||||
|
if (!this.maskClosable) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.$emit('close', {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-drawer-mask {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
.tui-drawer-mask_show {
|
||||||
|
display: block;
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-drawer-container {
|
||||||
|
position: fixed;
|
||||||
|
left: 80%;
|
||||||
|
height: 100.2%;
|
||||||
|
top: 0;
|
||||||
|
transform: translate3d(-50%, -50%, 0);
|
||||||
|
transform-origin: center;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
opacity: 0;
|
||||||
|
overflow-y: scroll;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
-ms-touch-action: pan-y cross-slide-y;
|
||||||
|
-ms-scroll-chaining: none;
|
||||||
|
-ms-scroll-limit: 0 50 0 50;
|
||||||
|
}
|
||||||
|
.tui-drawer-container_left {
|
||||||
|
left: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate3d(-100%, -50%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-drawer-container_right {
|
||||||
|
right: 0;
|
||||||
|
top: 50%;
|
||||||
|
left: auto;
|
||||||
|
transform: translate3d(100%, -80%, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-drawer-container_bottom,
|
||||||
|
.tui-drawer-container_top {
|
||||||
|
width: 100%;
|
||||||
|
height: auto !important;
|
||||||
|
min-height: 20rpx;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
transform-origin: center;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
.tui-drawer-container_bottom {
|
||||||
|
bottom: 0;
|
||||||
|
top: auto;
|
||||||
|
transform: translate3d(0, 100%, 0);
|
||||||
|
}
|
||||||
|
.tui-drawer-container_top {
|
||||||
|
transform: translate3d(0, -100%, 0);
|
||||||
|
}
|
||||||
|
.tui-drawer-left__show,
|
||||||
|
.tui-drawer-right__show {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate3d(0, -50%, 0);
|
||||||
|
}
|
||||||
|
.tui-drawer-top__show,
|
||||||
|
.tui-drawer-bottom__show {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translate3d(0, 0, 0);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,190 @@
|
||||||
|
export default {
|
||||||
|
"about": "\ue772",
|
||||||
|
"about-fill": "\ue771",
|
||||||
|
"add": "\ue770",
|
||||||
|
"add-fill": "\ue76f",
|
||||||
|
"addmessage": "\ue76e",
|
||||||
|
"addressbook": "\ue76d",
|
||||||
|
"agree": "\ue76c",
|
||||||
|
"agree-fill": "\ue76b",
|
||||||
|
"alarm": "\ue76a",
|
||||||
|
"alarm-fill": "\ue769",
|
||||||
|
"alipay": "\ue768",
|
||||||
|
"android": "\ue767",
|
||||||
|
"applets": "\ue766",
|
||||||
|
"arrowdown": "\ue765",
|
||||||
|
"arrowleft": "\ue764",
|
||||||
|
"arrowright": "\ue763",
|
||||||
|
"arrowup": "\ue762",
|
||||||
|
"attestation": "\ue761",
|
||||||
|
"back": "\ue760",
|
||||||
|
"bag": "\ue75f",
|
||||||
|
"bag-fill": "\ue75e",
|
||||||
|
"balloon": "\ue75d",
|
||||||
|
"bankcard": "\ue75c",
|
||||||
|
"bankcard-fill": "\ue75b",
|
||||||
|
"bottom": "\ue75a",
|
||||||
|
"calendar": "\ue759",
|
||||||
|
"camera": "\ue758",
|
||||||
|
"camera-fill": "\ue757",
|
||||||
|
"camera-add": "\ue756",
|
||||||
|
"card": "\ue755",
|
||||||
|
"card-fill": "\ue754",
|
||||||
|
"cart": "\ue753",
|
||||||
|
"cart-fill": "\ue752",
|
||||||
|
"category": "\ue751",
|
||||||
|
"category-fill": "\ue750",
|
||||||
|
"check": "\ue74f",
|
||||||
|
"circle": "\ue74e",
|
||||||
|
"circle-fill": "\ue74d",
|
||||||
|
"circle-selected": "\ue74c",
|
||||||
|
"clock": "\ue74b",
|
||||||
|
"clock-fill": "\ue74a",
|
||||||
|
"close": "\ue749",
|
||||||
|
"close-fill": "\ue748",
|
||||||
|
"community": "\ue747",
|
||||||
|
"community-fill": "\ue746",
|
||||||
|
"computer": "\ue745",
|
||||||
|
"computer-fill": "\ue744",
|
||||||
|
"coupon": "\ue743",
|
||||||
|
"delete": "\ue742",
|
||||||
|
"deletekey": "\ue741",
|
||||||
|
"dingtalk": "\ue740",
|
||||||
|
"dissatisfied": "\ue73f",
|
||||||
|
"down": "\ue73e",
|
||||||
|
"download": "\ue73d",
|
||||||
|
"edit": "\ue73c",
|
||||||
|
"ellipsis": "\ue73b",
|
||||||
|
"enlarge": "\ue73a",
|
||||||
|
"evaluate": "\ue739",
|
||||||
|
"exchange": "\ue738",
|
||||||
|
"explain": "\ue737",
|
||||||
|
"explain-fill": "\ue736",
|
||||||
|
"explore": "\ue735",
|
||||||
|
"explore-fill": "\ue734",
|
||||||
|
"eye": "\ue733",
|
||||||
|
"feedback": "\ue732",
|
||||||
|
"fingerprint": "\ue730",
|
||||||
|
"friendadd": "\ue72f",
|
||||||
|
"friendadd-fill": "\ue72e",
|
||||||
|
"gps": "\ue72d",
|
||||||
|
"histogram": "\ue72c",
|
||||||
|
"home": "\ue72b",
|
||||||
|
"home-fill": "\ue72a",
|
||||||
|
"house": "\ue729",
|
||||||
|
"imface": "\ue728",
|
||||||
|
"imkeyboard": "\ue727",
|
||||||
|
"immore": "\ue726",
|
||||||
|
"imvoice": "\ue725",
|
||||||
|
"ios": "\ue724",
|
||||||
|
"kefu": "\ue723",
|
||||||
|
"label": "\ue722",
|
||||||
|
"label-fill": "\ue721",
|
||||||
|
"like": "\ue720",
|
||||||
|
"like-fill": "\ue71f",
|
||||||
|
"link": "\ue71e",
|
||||||
|
"listview": "\ue71d",
|
||||||
|
"loading": "\ue71c",
|
||||||
|
"location": "\ue71b",
|
||||||
|
"mail": "\ue71a",
|
||||||
|
"mail-fill": "\ue719",
|
||||||
|
"manage": "\ue718",
|
||||||
|
"manage-fill": "\ue717",
|
||||||
|
"member": "\ue716",
|
||||||
|
"member-fill": "\ue715",
|
||||||
|
"message": "\ue714",
|
||||||
|
"message-fill": "\ue713",
|
||||||
|
"mobile": "\ue712",
|
||||||
|
"moments": "\ue711",
|
||||||
|
"more": "\ue710",
|
||||||
|
"more-fill": "\ue70f",
|
||||||
|
"narrow": "\ue70e",
|
||||||
|
"news": "\ue70d",
|
||||||
|
"news-fill": "\ue70c",
|
||||||
|
"nodata": "\ue70b",
|
||||||
|
"notice": "\ue699",
|
||||||
|
"notice-fill": "\ue698",
|
||||||
|
"offline": "\ue697",
|
||||||
|
"offline-fill": "\ue696",
|
||||||
|
"oppose": "\ue695",
|
||||||
|
"oppose-fill": "\ue694",
|
||||||
|
"order": "\ue693",
|
||||||
|
"partake": "\ue692",
|
||||||
|
"people": "\ue691",
|
||||||
|
"people-fill": "\ue690",
|
||||||
|
"pic": "\ue68f",
|
||||||
|
"pic-fill": "\ue68e",
|
||||||
|
"picture": "\ue68d",
|
||||||
|
"pie": "\ue68c",
|
||||||
|
"plus": "\ue689",
|
||||||
|
"polygonal": "\ue688",
|
||||||
|
"position": "\ue686",
|
||||||
|
"pwd": "\ue685",
|
||||||
|
"qq": "\ue684",
|
||||||
|
"qrcode": "\ue682",
|
||||||
|
"redpacket": "\ue681",
|
||||||
|
"redpacket-fill": "\ue680",
|
||||||
|
"reduce": "\ue67f",
|
||||||
|
"refresh": "\ue67e",
|
||||||
|
"revoke": "\ue67d",
|
||||||
|
"satisfied": "\ue67c",
|
||||||
|
"screen": "\ue67b",
|
||||||
|
"search": "\ue67a",
|
||||||
|
"search-2": "\ue679",
|
||||||
|
"send": "\ue678",
|
||||||
|
"service": "\ue677",
|
||||||
|
"service-fill": "\ue676",
|
||||||
|
"setup": "\ue675",
|
||||||
|
"setup-fill": "\ue674",
|
||||||
|
"share": "\ue673",
|
||||||
|
"share-fill": "\ue672",
|
||||||
|
"shield": "\ue671",
|
||||||
|
"shop": "\ue670",
|
||||||
|
"shop-fill": "\ue66f",
|
||||||
|
"shut": "\ue66e",
|
||||||
|
"signin": "\ue66d",
|
||||||
|
"sina": "\ue66c",
|
||||||
|
"skin": "\ue66b",
|
||||||
|
"soso": "\ue669",
|
||||||
|
"square": "\ue668",
|
||||||
|
"square-fill": "\ue667",
|
||||||
|
"square-selected": "\ue666",
|
||||||
|
"star": "\ue665",
|
||||||
|
"star-fill": "\ue664",
|
||||||
|
"strategy": "\ue663",
|
||||||
|
"sweep": "\ue662",
|
||||||
|
"time": "\ue661",
|
||||||
|
"time-fill": "\ue660",
|
||||||
|
"todown": "\ue65f",
|
||||||
|
"toleft": "\ue65e",
|
||||||
|
"tool": "\ue65d",
|
||||||
|
"top": "\ue65c",
|
||||||
|
"toright": "\ue65b",
|
||||||
|
"towardsleft": "\ue65a",
|
||||||
|
"towardsright": "\ue659",
|
||||||
|
"towardsright-fill": "\ue658",
|
||||||
|
"transport": "\ue657",
|
||||||
|
"transport-fill": "\ue656",
|
||||||
|
"turningdown": "\ue654",
|
||||||
|
"turningleft": "\ue653",
|
||||||
|
"turningright": "\ue652",
|
||||||
|
"turningup": "\ue651",
|
||||||
|
"unreceive": "\ue650",
|
||||||
|
"seen": "\ue7d2",
|
||||||
|
"unseen": "\ue7d1",
|
||||||
|
"up": "\ue64e",
|
||||||
|
"upload": "\ue64c",
|
||||||
|
"video": "\ue64b",
|
||||||
|
"voice": "\ue649",
|
||||||
|
"voice-fill": "\ue648",
|
||||||
|
"voipphone": "\ue647",
|
||||||
|
"wallet": "\ue646",
|
||||||
|
"warning": "\ue645",
|
||||||
|
"wealth": "\ue644",
|
||||||
|
"wealth-fill": "\ue643",
|
||||||
|
"weather": "\ue642",
|
||||||
|
"wechat": "\ue641",
|
||||||
|
"wifi": "\ue640",
|
||||||
|
"play": "\ue7d5",
|
||||||
|
"suspend": "\ue7d4"
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,78 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-loading-init">
|
||||||
|
<view class="tui-loading-center"></view>
|
||||||
|
<view class="tui-loadmore-tips">{{text}}</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "tuiLoading",
|
||||||
|
props: {
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: "正在加载..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-loading-init {
|
||||||
|
min-width: 200rpx;
|
||||||
|
min-height: 200rpx;
|
||||||
|
max-width: 500rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: 9999;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgba(0, 0, 0, 0.7);
|
||||||
|
border-radius: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-loading-center {
|
||||||
|
width: 50rpx;
|
||||||
|
height: 50rpx;
|
||||||
|
border: 3px solid #fff;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin: 0 6px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
clip-path: polygon(0% 0%, 100% 0%, 100% 40%, 0% 40%);
|
||||||
|
animation: rotate 1s linear infinite;
|
||||||
|
margin-bottom: 36rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-loadmore-tips {
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes rotate {
|
||||||
|
from {
|
||||||
|
transform: rotatez(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotatez(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate {
|
||||||
|
from {
|
||||||
|
transform: rotatez(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotatez(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,161 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-loadmore">
|
||||||
|
<view :class="['tui-loading-'+index, (index==3 && type)?'tui-loading-'+type:'']"></view>
|
||||||
|
<view class="tui-loadmore-tips">{{text}}</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "tuiLoadmore",
|
||||||
|
props: {
|
||||||
|
//显示文本
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: "正在加载..."
|
||||||
|
},
|
||||||
|
//loading 样式 :1,2,3
|
||||||
|
index: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
//颜色设置,只有index=3时生效:primary,red,orange,green
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-loadmore {
|
||||||
|
width: 48%;
|
||||||
|
margin: 1.5em auto;
|
||||||
|
line-height: 1.5em;
|
||||||
|
font-size: 24rpx;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-loading-1 {
|
||||||
|
margin: 0 5px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
-webkit-animation: a 1s steps(12) infinite;
|
||||||
|
animation: a 1s steps(12) infinite;
|
||||||
|
background: transparent url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgxMDB2MTAwSDB6Ii8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTlFOUU5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTMwKSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iIzk4OTY5NyIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgzMCAxMDUuOTggNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjOUI5OTlBIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDYwIDc1Ljk4IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0EzQTFBMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSg5MCA2NSA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNBQkE5QUEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoMTIwIDU4LjY2IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0IyQjJCMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgxNTAgNTQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjQkFCOEI5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDE4MCA1MCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDMkMwQzEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTE1MCA0NS45OCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDQkNCQ0IiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTEyMCA0MS4zNCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNEMkQyRDIiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDM1IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0RBREFEQSIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgtNjAgMjQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTJFMkUyIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKC0zMCAtNS45OCA2NSkiLz48L3N2Zz4=) no-repeat;
|
||||||
|
background-size: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes a {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(1turn);
|
||||||
|
transform: rotate(1turn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes a {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
-webkit-transform: rotate(1turn);
|
||||||
|
transform: rotate(1turn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-loadmore-tips {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-loading-2 {
|
||||||
|
width: 28rpx;
|
||||||
|
height: 28rpx;
|
||||||
|
border: 1px solid #8f8d8e;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin: 0 6px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
clip-path: polygon(0% 0%,100% 0%,100% 30%,0% 30%);
|
||||||
|
animation: rotate 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes rotate {
|
||||||
|
from {
|
||||||
|
transform: rotatez(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotatez(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotate {
|
||||||
|
from {
|
||||||
|
transform: rotatez(0deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
transform: rotatez(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-loading-3 {
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 6px;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 28rpx;
|
||||||
|
height: 28rpx;
|
||||||
|
background: 0 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid;
|
||||||
|
border-color: #e5e5e5 #e5e5e5 #e5e5e5 #8f8d8e;
|
||||||
|
animation: tui-rotate 0.7s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-loading-3.tui-loading-primary {
|
||||||
|
border-color: #e5e5e5 #e5e5e5 #e5e5e5 #5677fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-loading-3.tui-loading-green {
|
||||||
|
border-color: #e5e5e5 #e5e5e5 #e5e5e5 #19be6b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-loading-3.tui-loading-orange {
|
||||||
|
border-color: #e5e5e5 #e5e5e5 #e5e5e5 #ff7900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-loading-3.tui-loading-red {
|
||||||
|
border-color: #ededed #ededed #ededed #ed3f14;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes tui-rotate {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes tui-rotate {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,408 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-modal__container" :class="[show ? 'tui-modal-show' : '']" :style="{zIndex:zIndex}" @touchmove.stop.prevent>
|
||||||
|
<view
|
||||||
|
class="tui-modal-box"
|
||||||
|
:style="{ width: width, padding: padding, borderRadius: radius, backgroundColor: backgroundColor,zIndex:zIndex+1 }"
|
||||||
|
:class="[fadeIn || show ? 'tui-modal-normal' : 'tui-modal-scale', show ? 'tui-modal-show' : '']"
|
||||||
|
>
|
||||||
|
<view v-if="!custom">
|
||||||
|
<view class="tui-modal-title" v-if="title">{{ title }}</view>
|
||||||
|
<view class="tui-modal-content" :class="[title ? '' : 'tui-mtop']" :style="{ color: color, fontSize: size + 'rpx' }">{{ content }}</view>
|
||||||
|
<view class="tui-modalBtn-box" :class="[button.length != 2 ? 'tui-flex-column' : '']">
|
||||||
|
<block v-for="(item, index) in button" :key="index">
|
||||||
|
<button
|
||||||
|
class="tui-modal-btn"
|
||||||
|
:class="[
|
||||||
|
'tui-' + (item.type || 'primary') + (item.plain ? '-outline' : ''),
|
||||||
|
button.length != 2 ? 'tui-btn-width' : '',
|
||||||
|
button.length > 2 ? 'tui-mbtm' : '',
|
||||||
|
shape == 'circle' ? 'tui-circle-btn' : ''
|
||||||
|
]"
|
||||||
|
:hover-class="'tui-' + (item.plain ? 'outline' : item.type || 'primary') + '-hover'"
|
||||||
|
:data-index="index"
|
||||||
|
@tap="handleClick"
|
||||||
|
>
|
||||||
|
{{ item.text || '确定' }}
|
||||||
|
</button>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-else><slot></slot></view>
|
||||||
|
</view>
|
||||||
|
<view class="tui-modal-mask" :class="[show ? 'tui-mask-show' : '']" :style="{zIndex:maskZIndex}" @tap="handleClickCancel"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiModal',
|
||||||
|
emits: ['click','cancel'],
|
||||||
|
props: {
|
||||||
|
//是否显示
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: '84%'
|
||||||
|
},
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#fff'
|
||||||
|
},
|
||||||
|
padding: {
|
||||||
|
type: String,
|
||||||
|
default: '30rpx 0rpx 0rpx 0rpx'
|
||||||
|
},
|
||||||
|
radius: {
|
||||||
|
type: String,
|
||||||
|
default: '24rpx'
|
||||||
|
},
|
||||||
|
//标题
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
//内容
|
||||||
|
content: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
//内容字体颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#999'
|
||||||
|
},
|
||||||
|
//内容字体大小 rpx
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 28
|
||||||
|
},
|
||||||
|
//形状 circle, square
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: 'square'
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
type: Array,
|
||||||
|
default: function() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: '取消',
|
||||||
|
type: 'red',
|
||||||
|
plain: true //是否空心
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '确定',
|
||||||
|
type: 'red',
|
||||||
|
plain: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//点击遮罩 是否可关闭
|
||||||
|
maskClosable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//淡入效果,自定义弹框插入input输入框时传true
|
||||||
|
fadeIn: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//自定义弹窗内容
|
||||||
|
custom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//容器z-index
|
||||||
|
zIndex:{
|
||||||
|
type: Number,
|
||||||
|
default: 9997
|
||||||
|
},
|
||||||
|
//mask z-index
|
||||||
|
maskZIndex:{
|
||||||
|
type: Number,
|
||||||
|
default: 9990
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClick(e) {
|
||||||
|
if (!this.show) return;
|
||||||
|
const dataset = e.currentTarget.dataset;
|
||||||
|
this.$emit('click', {
|
||||||
|
index: Number(dataset.index)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handleClickCancel() {
|
||||||
|
if (!this.maskClosable) return;
|
||||||
|
this.$emit('cancel');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-modal__container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
.tui-modal-box {
|
||||||
|
position: relative;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-modal-scale {
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-modal-normal {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-modal-show {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-modal-mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-mask-show {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-modal-title {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 34rpx;
|
||||||
|
color: #333;
|
||||||
|
padding-top: 20rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-modal-content {
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
font-size: 28rpx;
|
||||||
|
padding-top: 20rpx;
|
||||||
|
padding-bottom: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-mtop {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-mbtm {
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-modalBtn-box {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-flex-column {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-modal-btn {
|
||||||
|
width: 46%;
|
||||||
|
height: 68rpx;
|
||||||
|
line-height: 68rpx;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
overflow: visible;
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-modal-btn::after {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
width: 200%;
|
||||||
|
height: 200%;
|
||||||
|
-webkit-transform-origin: 0 0;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
transform: scale(0.5, 0.5) translateZ(0);
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
border-radius: 20rpx;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-width {
|
||||||
|
width: 80% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-primary {
|
||||||
|
background: #5677fc;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-primary-hover {
|
||||||
|
background: #4a67d6;
|
||||||
|
color: #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-primary-outline {
|
||||||
|
color: #5677fc;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-primary-outline::after {
|
||||||
|
border: 1px solid #5677fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-danger {
|
||||||
|
background: #ed3f14;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-danger-hover {
|
||||||
|
background: #d53912;
|
||||||
|
color: #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-danger-outline {
|
||||||
|
color: #ed3f14;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-danger-outline::after {
|
||||||
|
border: 1px solid #ed3f14;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-red {
|
||||||
|
background: #e41f19;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-red-hover {
|
||||||
|
background: #c51a15;
|
||||||
|
color: #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-red-outline {
|
||||||
|
color: #e41f19;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-red-outline::after {
|
||||||
|
border: 1px solid #e41f19;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-warning {
|
||||||
|
background: #ff7900;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-warning-hover {
|
||||||
|
background: #e56d00;
|
||||||
|
color: #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-warning-outline {
|
||||||
|
color: #ff7900;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-warning-outline::after {
|
||||||
|
border: 1px solid #ff7900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-green {
|
||||||
|
background: #19be6b;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-green-hover {
|
||||||
|
background: #16ab60;
|
||||||
|
color: #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-green-outline {
|
||||||
|
color: #19be6b;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-green-outline::after {
|
||||||
|
border: 1px solid #19be6b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-white {
|
||||||
|
background: #fff;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-white-hover {
|
||||||
|
background: #f7f7f9;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-white-outline {
|
||||||
|
color: #333;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-white-outline::after {
|
||||||
|
border: 1px solid #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray {
|
||||||
|
background: #ededed;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray-hover {
|
||||||
|
background: #d5d5d5;
|
||||||
|
color: #898989;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray-outline {
|
||||||
|
color: #999;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray-outline::after {
|
||||||
|
border: 1px solid #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-outline-hover {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-circle-btn {
|
||||||
|
border-radius: 40rpx !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-circle-btn::after {
|
||||||
|
border-radius: 80rpx !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,118 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-nodata-box" :class="[fixed?'tui-nodata-fixed':'']">
|
||||||
|
<image v-if="imgUrl" :src="imgUrl" class="tui-tips-icon" :style="{width:imgWidth+'rpx',height:imgHeight+'rpx'}"></image>
|
||||||
|
<view class="tui-tips-content">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
<view class="tui-tips-btn" hover-class="tui-btn__hover" :hover-stay-time="150" :style="{width:btnWidth+'rpx',height:btnHeight+'rpx',background:backgroundColor,borderRadius:radius,fontSize:size+'rpx'}" v-if="btnText" @tap="handleClick">{{btnText}}</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "tuiNoData",
|
||||||
|
emits: ['click'],
|
||||||
|
props: {
|
||||||
|
//是否垂直居中
|
||||||
|
fixed: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//图片地址,没有则不显示
|
||||||
|
imgUrl: {
|
||||||
|
type: String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
//图片宽度
|
||||||
|
imgWidth: {
|
||||||
|
type: Number,
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
//图片高度
|
||||||
|
imgHeight:{
|
||||||
|
type: Number,
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
//按钮宽度
|
||||||
|
btnWidth:{
|
||||||
|
type: Number,
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
btnHeight:{
|
||||||
|
type: Number,
|
||||||
|
default: 60
|
||||||
|
},
|
||||||
|
//按钮文字,没有则不显示
|
||||||
|
btnText:{
|
||||||
|
type:String,
|
||||||
|
default: ""
|
||||||
|
},
|
||||||
|
//按钮背景色
|
||||||
|
backgroundColor:{
|
||||||
|
type:String,
|
||||||
|
default: "#EB0909"
|
||||||
|
},
|
||||||
|
size:{
|
||||||
|
type:Number,
|
||||||
|
default:28
|
||||||
|
},
|
||||||
|
radius:{
|
||||||
|
type:String,
|
||||||
|
default:'8rpx'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClick(e) {
|
||||||
|
this.$emit('click', {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-nodata-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-nodata-fixed {
|
||||||
|
width: 90%;
|
||||||
|
position: fixed;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
-webkit-transform: translate(-50%, -50%);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tips-icon {
|
||||||
|
display: block;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: 280rpx;
|
||||||
|
height: 280rpx;
|
||||||
|
margin-bottom: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tips-content {
|
||||||
|
text-align: center;
|
||||||
|
color: #666666;
|
||||||
|
font-size: 28rpx;
|
||||||
|
padding: 0 50rpx 28rpx 50rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
word-break: break-all;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tips-btn {
|
||||||
|
color: #fff;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.tui-btn__hover{
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,115 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-nomore-class tui-loadmore-none">
|
||||||
|
<view :class="[isDot?'tui-nomore-dot':'tui-nomore']">
|
||||||
|
<view :style="{backgroundColor:backgroundColor}" :class="[isDot?'tui-dot-text':'tui-nomore-text']">{{isDot?dotText:text}}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "tuiNomore",
|
||||||
|
props: {
|
||||||
|
//当前页面背景颜色
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#F6F7FA"
|
||||||
|
},
|
||||||
|
//是否以圆点代替 "没有更多了"
|
||||||
|
isDot: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//isDot为false时生效
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: "到底啦~"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dotText: "●"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-loadmore-none {
|
||||||
|
width: 50%;
|
||||||
|
margin: 1.5em auto;
|
||||||
|
line-height: 1.5em;
|
||||||
|
font-size: 24rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-nomore {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 10rpx;
|
||||||
|
padding-bottom: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-nomore::before {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
border-bottom: 1rpx solid #e5e5e5;
|
||||||
|
-webkit-transform: scaleY(0.5);
|
||||||
|
transform: scaleY(0.5);
|
||||||
|
width: 100%;
|
||||||
|
top: 18rpx;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-nomore-text {
|
||||||
|
color: #999;
|
||||||
|
font-size: 24rpx;
|
||||||
|
text-align: center;
|
||||||
|
padding: 0 18rpx;
|
||||||
|
height: 36rpx;
|
||||||
|
line-height: 36rpx;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-nomore-dot {
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
-webkit-display: flex;
|
||||||
|
display: flex;
|
||||||
|
-webkit-justify-content: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 10rpx;
|
||||||
|
padding-bottom: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-nomore-dot::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
border-bottom: 1rpx solid #e5e5e5;
|
||||||
|
-webkit-transform: scaleY(0.5) translateX(-50%);
|
||||||
|
transform: scaleY(0.5) translateX(-50%);
|
||||||
|
width: 360rpx;
|
||||||
|
top: 18rpx;
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-dot-text {
|
||||||
|
position: relative;
|
||||||
|
color: #e5e5e5;
|
||||||
|
font-size: 10px;
|
||||||
|
text-align: center;
|
||||||
|
width: 50rpx;
|
||||||
|
height: 36rpx;
|
||||||
|
line-height: 36rpx;
|
||||||
|
-webkit-transform: scale(0.8);
|
||||||
|
transform: scale(0.8);
|
||||||
|
-webkit-transform-origin: center center;
|
||||||
|
transform-origin: center center;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,231 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-numberbox">
|
||||||
|
<view class="tui-numbox-icon tui-icon-reduce " :class="[disabled || min >= inputValue ? 'tui-disabled' : '']"
|
||||||
|
@tap="reduce" :style="{ color: iconColor, fontSize: iconSize + 'rpx' }"></view>
|
||||||
|
<input type="number" v-model="inputValue" :disabled="disabled" @blur="blur" class="tui-num-input"
|
||||||
|
:style="{ color: color, fontSize: size + 'rpx', backgroundColor: backgroundColor, height: height + 'rpx', minHeight: height + 'rpx', width: width + 'rpx' }" />
|
||||||
|
<view class="tui-numbox-icon tui-icon-plus" :class="[disabled || inputValue >= max ? 'tui-disabled' : '']"
|
||||||
|
@tap="plus" :style="{ color: iconColor, fontSize: iconSize + 'rpx' }"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiNumberbox',
|
||||||
|
emits: ['change'],
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
//最小值
|
||||||
|
min: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
//最大值
|
||||||
|
max: {
|
||||||
|
type: Number,
|
||||||
|
default: 99
|
||||||
|
},
|
||||||
|
//迈步大小 1 1.1 10...
|
||||||
|
step: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
//是否禁用操作
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//加减图标大小 rpx
|
||||||
|
iconSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 26
|
||||||
|
},
|
||||||
|
iconColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#666666'
|
||||||
|
},
|
||||||
|
//input 高度
|
||||||
|
height: {
|
||||||
|
type: Number,
|
||||||
|
default: 42
|
||||||
|
},
|
||||||
|
//input 宽度
|
||||||
|
width: {
|
||||||
|
type: Number,
|
||||||
|
default: 80
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 28
|
||||||
|
},
|
||||||
|
//input 背景颜色
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#F5F5F5'
|
||||||
|
},
|
||||||
|
//input 字体颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#333'
|
||||||
|
},
|
||||||
|
//索引值,列表中使用
|
||||||
|
index: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
//自定义参数
|
||||||
|
custom: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.inputValue = +this.value;
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
inputValue: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value(val) {
|
||||||
|
this.inputValue = +val;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getLen(val, step) {
|
||||||
|
let len = 0;
|
||||||
|
let lenVal = 0;
|
||||||
|
//浮点型
|
||||||
|
if (!Number.isInteger(step)) {
|
||||||
|
len = (step + '').split('.')[1].length
|
||||||
|
}
|
||||||
|
//浮点型
|
||||||
|
if (!Number.isInteger(val)) {
|
||||||
|
lenVal = (val + '').split('.')[1].length
|
||||||
|
}
|
||||||
|
return Math.max(len, lenVal);
|
||||||
|
},
|
||||||
|
getScale(val, step) {
|
||||||
|
let scale = 1;
|
||||||
|
let scaleVal = 1;
|
||||||
|
//浮点型
|
||||||
|
if (!Number.isInteger(step)) {
|
||||||
|
scale = Math.pow(10, (step + '').split('.')[1].length);
|
||||||
|
}
|
||||||
|
//浮点型
|
||||||
|
if (!Number.isInteger(val)) {
|
||||||
|
scaleVal = Math.pow(10, (val + '').split('.')[1].length);
|
||||||
|
}
|
||||||
|
return Math.max(scale, scaleVal);
|
||||||
|
},
|
||||||
|
calcNum: function(type) {
|
||||||
|
if (this.disabled || (this.inputValue == this.min && type === 'reduce') || (this.inputValue == this
|
||||||
|
.max && type === 'plus')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const scale = this.getScale(this.inputValue, this.step);
|
||||||
|
let len = this.getLen(this.inputValue, this.step);
|
||||||
|
let num = Number(this.inputValue) * scale;
|
||||||
|
let step = this.step * scale;
|
||||||
|
if (type === 'reduce') {
|
||||||
|
num -= step;
|
||||||
|
} else if (type === 'plus') {
|
||||||
|
num += step;
|
||||||
|
}
|
||||||
|
let value = this.toFixed(num / scale, len);
|
||||||
|
if (value < this.min) {
|
||||||
|
value = this.min;
|
||||||
|
}else if (value > this.max) {
|
||||||
|
value = this.max;
|
||||||
|
}
|
||||||
|
this.handleChange(value, type);
|
||||||
|
},
|
||||||
|
plus: function() {
|
||||||
|
this.calcNum('plus');
|
||||||
|
},
|
||||||
|
reduce: function() {
|
||||||
|
this.calcNum('reduce');
|
||||||
|
},
|
||||||
|
blur: function(e) {
|
||||||
|
let value = e.detail.value;
|
||||||
|
if (value) {
|
||||||
|
if (~value.indexOf('.') && Number.isInteger(this.step) && Number.isInteger(Number(value))) {
|
||||||
|
value = value.split('.')[0];
|
||||||
|
}
|
||||||
|
value = Number(value);
|
||||||
|
if (value > this.max) {
|
||||||
|
value = this.max;
|
||||||
|
} else if (value < this.min) {
|
||||||
|
value = this.min;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = this.min;
|
||||||
|
}
|
||||||
|
if ((value == this.value && value != this.inputValue) || !e.detail.value) {
|
||||||
|
this.inputValue = value;
|
||||||
|
}
|
||||||
|
this.handleChange(value, 'blur');
|
||||||
|
},
|
||||||
|
handleChange(value, type) {
|
||||||
|
if (this.disabled) return;
|
||||||
|
this.$emit('change', {
|
||||||
|
value: Number(value),
|
||||||
|
type: type,
|
||||||
|
index: this.index,
|
||||||
|
custom: this.custom
|
||||||
|
});
|
||||||
|
},
|
||||||
|
toFixed(num, s) {
|
||||||
|
let times = Math.pow(10, s)
|
||||||
|
let des = num * times + 0.5
|
||||||
|
des = parseInt(des, 10) / times
|
||||||
|
return des + ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'numberbox';
|
||||||
|
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAASQAA0AAAAABtwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAEdAAAABoAAAAciBpnRUdERUYAAARUAAAAHgAAAB4AKQALT1MvMgAAAZwAAABDAAAAVjxzSINjbWFwAAAB9AAAAEYAAAFK5zLpOGdhc3AAAARMAAAACAAAAAj//wADZ2x5ZgAAAkgAAACHAAAAnIfIEjxoZWFkAAABMAAAAC8AAAA2FZWEOWhoZWEAAAFgAAAAHAAAACQH3gOFaG10eAAAAeAAAAARAAAAEgwAAAFsb2NhAAACPAAAAAwAAAAMADAATm1heHAAAAF8AAAAHwAAACABEAAobmFtZQAAAtAAAAFJAAACiCnmEVVwb3N0AAAEHAAAAC0AAABV/+8iFXjaY2BkYGAA4gVmC5Tj+W2+MnCzMIDATWsFOQT9v5GFgbkeyOVgYAKJAgDrogf+AHjaY2BkYGBu+N/AEMPCAAJAkpEBFbAAAEcKAm142mNgZGBgYGWQYQDRDAxMQMwFhAwM/8F8BgALpAE5AHjaY2BkYWCcwMDKwMDUyXSGgYGhH0IzvmYwYuQAijKwMjNgBQFprikMDs9Yn01kbvjfwBDD3MDQABRmBMkBAOXpDHEAeNpjYYAAFghmZGAAAACdAA4AAAB42mNgYGBmgGAZBkYGEHAB8hjBfBYGDSDNBqQZGZiesT6b+P8/AwOElvwnWQxVDwSMbAxwDiMTkGBiQAWMDMMeAABRZwszAAAAAAAAAAAAAAAwAE542iWKQQrCMBBF5xNpd0pQ7EIoTEnahSCTUNqdWz2A9TrieXKeXCc1qcPn/zfzh0BYv2pVH7oQgbvqdG5Yt/DTrNlPYz+wHvuuqhFSME4sFshTgKUsKfhH5lg8BSul3i5bS3mQdd0RIh2IjnvUrkXDd8zuhuFt86tY9fonIsSYgsXpB+cCGosAeNp9kD1OAzEQhZ/zByQSQiCoXVEA2vyUKRMp9Ailo0g23pBo1155nUg5AS0VB6DlGByAGyDRcgpelkmTImvt6PObmeexAZzjGwr/3yXuhBWO8ShcwREy4Sr1F+Ea+V24jhY+hRvUf4SbuFUD4RYu1BsdVO2Eu5vSbcsKZxgIV3CKJ+Eq9ZVwjfwqXMcVPoQb1L+EmxjjV7iFa2WpDOFhMEFgnEFjig3jAjEcLJIyBtahOfRmEsxMTzd6ETubOBso71dilwMeaDnngCntPbdmvkon/mDLgdSYbh4FS7YpjS4idCgbXyyc1d2oc7D9nu22tNi/a4E1x+xRDWzU/D3bM9JIbAyvkJI18jK3pBJTj2hrrPG7ZynW814IiU68y/SIx5o0dTr3bmniwOLn8owcfbS5kj33qBw+Y1kIeb/dTsQgil2GP5PYcRkAAAB42mNgYoAALjDJyIAOWMGiTIxMjMwiWZmJQJRXVQoigTgjMd9QGIsgAFDsEBsAAAAAAAAB//8AAgABAAAADAAAABYAAAACAAEAAwAEAAEABAAAAAIAAAAAeNpjYGBgZACCq0vUOUD0TWsFORgNADPBBE4AAA==) format('woff');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-numbox-icon {
|
||||||
|
font-family: 'numberbox' !important;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
padding: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-icon-reduce:before {
|
||||||
|
content: '\e691';
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-icon-plus:before {
|
||||||
|
content: '\e605';
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-numberbox {
|
||||||
|
display: -webkit-inline-flex;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-num-input {
|
||||||
|
text-align: center;
|
||||||
|
margin: 0 12rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-disabled {
|
||||||
|
color: #ededed !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,168 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-rate-class tui-rate-box" @touchmove="touchMove">
|
||||||
|
<block v-for="(item, index) in quantity" :key="index">
|
||||||
|
<view class="tui-icon tui-relative"
|
||||||
|
:class="['tui-icon-collection' + (hollow && (current <= index || (disabled && current <= index + 1)) ? '' : '-fill')]"
|
||||||
|
:data-index="index" @tap="handleTap"
|
||||||
|
:style="{ fontSize: size + 'px', color: current > index + 1 || (!disabled && current > index) ? active : normal }">
|
||||||
|
<view class="tui-icon tui-icon-main tui-icon-collection-fill" v-if="disabled && current == index + 1"
|
||||||
|
:style="{ fontSize: size + 'px', color: active, width: percent + '%' }"></view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiRate',
|
||||||
|
emits: ['change'],
|
||||||
|
props: {
|
||||||
|
//数量
|
||||||
|
quantity: {
|
||||||
|
type: Number,
|
||||||
|
default: 5
|
||||||
|
},
|
||||||
|
//当前选中
|
||||||
|
current: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
//当前选中星星分数(大于0,小于等于1的数)
|
||||||
|
score: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
//禁用点击
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//大小
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 20
|
||||||
|
},
|
||||||
|
//未选中颜色
|
||||||
|
normal: {
|
||||||
|
type: String,
|
||||||
|
default: '#b2b2b2'
|
||||||
|
},
|
||||||
|
//选中颜色
|
||||||
|
active: {
|
||||||
|
type: String,
|
||||||
|
default: '#e41f19'
|
||||||
|
},
|
||||||
|
//未选中是否为空心
|
||||||
|
hollow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//自定义参数
|
||||||
|
params: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
pageX: 0,
|
||||||
|
percent: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.percent = Number(this.score || 0) * 100;
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
score(newVal, oldVal) {
|
||||||
|
this.percent = Number(newVal || 0) * 100;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleTap(e) {
|
||||||
|
if (this.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const index = e.currentTarget.dataset.index;
|
||||||
|
this.$emit('change', {
|
||||||
|
index: Number(index) + 1,
|
||||||
|
params: this.params
|
||||||
|
});
|
||||||
|
},
|
||||||
|
touchMove(e) {
|
||||||
|
if (this.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!e.changedTouches[0]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const movePageX = e.changedTouches[0].pageX;
|
||||||
|
const distance = movePageX - this.pageX;
|
||||||
|
|
||||||
|
if (distance <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let index = Math.ceil(distance / this.size);
|
||||||
|
index = index > this.quantity ? this.quantity : index;
|
||||||
|
this.$emit('change', {
|
||||||
|
index: index,
|
||||||
|
params: this.params
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
const className = '.tui-rate-box';
|
||||||
|
let query = uni.createSelectorQuery().in(this);
|
||||||
|
query
|
||||||
|
.select(className)
|
||||||
|
.boundingClientRect(res => {
|
||||||
|
this.pageX = res.left || 0;
|
||||||
|
})
|
||||||
|
.exec();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'rateFont';
|
||||||
|
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAT4AA0AAAAAB4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAE3AAAABoAAAAciBprQUdERUYAAAS8AAAAHgAAAB4AKQALT1MvMgAAAaAAAABDAAAAVj1YSN1jbWFwAAAB+AAAAEIAAAFCAA/qlmdhc3AAAAS0AAAACAAAAAj//wADZ2x5ZgAAAkgAAADwAAABZLMTdXtoZWFkAAABMAAAADAAAAA2FZKISmhoZWEAAAFgAAAAHQAAACQHYgOFaG10eAAAAeQAAAARAAAAEgx6AHpsb2NhAAACPAAAAAwAAAAMAEYAsm1heHAAAAGAAAAAHgAAACABEQBPbmFtZQAAAzgAAAFJAAACiCnmEVVwb3N0AAAEhAAAAC0AAABHLO3vkXjaY2BkYGAA4t2/VF7G89t8ZeBmYQCBm9ZKMnC6ikGMuYXpP5DLwcAEEgUAHPQJOXjaY2BkYGBu+N/AEMPCAALMLQyMDKiABQBQwgLwAAAAeNpjYGRgYGBlcGZgYgABEMkFhAwM/8F8BgAPigFhAAB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PXj17zdzwv4EhhrmBoQEozAiSAwD/YA2wAHjaY2GAABYIrmKoAgACggEBAAAAeNpjYGBgZoBgGQZGBhCwAfIYwXwWBgUgzQKEQP6z1///A8lX//9LSkJVMjCyMcCYDIxMQIKJARUwMgx7AAA/9QiLAAAAAAAAAAAAAABGALJ42mNgZKhiEGNuYfrPoMnAwGimps+ox6jPqKbEz8jHCMLyjHJAmk1czMie0cxInlHMDChrZs6cJyaosI+NlzmU34I/lImPdb+CoHgXCyujIosYtzTfKlYBtlWyuqwKjKwsjNvFTdlkGDnZ1srKrmXjZJRhMxVvZxFgA+rgYI9iYoriV1TYzybAwsDABHeLBIMT0DUg29VBTjEHucvcjtGeUVyOUZ6JaFcybefnZ5HuFdEX6ZVm5uMvniemxuXmzqUmNs+FeOfHCeiKzfPi4vKaJ6YrUCDOIiM8YYKwDIu4OMRbrOtkZdex4vMWACzGM5B42n2QPU4DMRCFn/MHJBJCIKhdUQDa/JQpEyn0CKWjSDbekGjXXnmdSDkBLRUHoOUYHIAbINFyCl6WSZMia+3o85uZ57EBnOMbCv/fJe6EFY7xKFzBETLhKvUX4Rr5XbiOFj6FG9R/hJu4VQPhFi7UGx1U7YS7m9JtywpnGAhXcIon4Sr1lXCN/CpcxxU+hBvUv4SbGONXuIVrZakM4WEwQWCcQWOKDeMCMRwskjIG1qE59GYSzExPN3oRO5s4GyjvV2KXAx5oOeeAKe09t2a+Sif+YMuB1JhuHgVLtimNLiJ0KBtfLJzV3ahzsP2e7ba02L9rgTXH7FENbNT8Pdsz0khsDK+QkjXyMrekElOPaGus8btnKdbzXgiJTrzL9IjHmjR1OvduaeLA4ufyjBx9tLmSPfeoHD5jWQh5v91OxCCKXYY/k9hxGQAAAHjaY2BigAAuMMnIgA5YwaJMjEyMzPzJ+Tk5qcklmfl58WmZOTlcCD4Ak9QKlAAAAAAAAAH//wACAAEAAAAMAAAAFgAAAAIAAQADAAQAAQAEAAAAAgAAAAB42mNgYGBkAIKrS9Q5QPRNayUZGA0AM8UETgAA) format('woff');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-icon {
|
||||||
|
font-family: 'rateFont' !important;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-relative {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-icon-main {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-icon-collection-fill:before {
|
||||||
|
content: '\e6ea';
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-icon-collection:before {
|
||||||
|
content: '\e6eb';
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-rate-box {
|
||||||
|
display: -webkit-inline-flex;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,218 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-slide-vcode" :style="{width:slideBarWidth+'px',height:slideBlockWidth+'px',backgroundColor:backgroundColor}">
|
||||||
|
<text class="tui-text-flashover" :style="{fontSize:size+'rpx',background:getBgColor}">拖动滑块验证</text>
|
||||||
|
<view class="tui-slide-glided" :style="{backgroundColor:activeBgColor}">
|
||||||
|
<text :style="{fontSize:size+'rpx',color:activeColor}" v-if="isPass">{{passText}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="tui-slider-block" :style="{width:slideBlockWidth+'px',height:slideBlockWidth+'px',borderColor:isPass?activeBorderColor: borderColor}"
|
||||||
|
:change:prop="parse.slidereset" :prop="reset" :data-slideBarWidth="slideBarWidth" :data-slideBlockWidth="slideBlockWidth"
|
||||||
|
:data-errorRange="errorRange" :data-disabled="disabled" @touchstart="parse.touchstart" @touchmove="parse.touchmove"
|
||||||
|
@touchend="parse.touchend">
|
||||||
|
<text class="tui-slide-icon tui-icon-double_arrow" :style="{fontSize:iconSize+'rpx',color:arrowColor}" v-if="!isPass"></text>
|
||||||
|
<text class="tui-slide-icon tui-icon-check_mark" :style="{fontSize:iconSize+'rpx',color:checkColor}" v-if="isPass"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script src="./tui-slide-verify.wxs" module="parse" lang="wxs"></script>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "tuiSlideVerify",
|
||||||
|
emits: ['success'],
|
||||||
|
props: {
|
||||||
|
//滑动条宽度 px
|
||||||
|
slideBarWidth: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 300
|
||||||
|
},
|
||||||
|
//滑块宽度 px = 滑动条高度
|
||||||
|
slideBlockWidth: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 40
|
||||||
|
},
|
||||||
|
//滑块border颜色
|
||||||
|
borderColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#E9E9E9'
|
||||||
|
},
|
||||||
|
//通过验证后滑块border颜色
|
||||||
|
activeBorderColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#19be6b'
|
||||||
|
},
|
||||||
|
//误差范围 px 距离右侧多少距离验证通过
|
||||||
|
errorRange: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 2
|
||||||
|
},
|
||||||
|
//重置滑动
|
||||||
|
resetSlide: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
//提示文字大小
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 30
|
||||||
|
},
|
||||||
|
//提示文字颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: "#444"
|
||||||
|
},
|
||||||
|
//验证通过后提示文字颜色
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#fff"
|
||||||
|
},
|
||||||
|
//图标字体大小 rpx
|
||||||
|
iconSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 32
|
||||||
|
},
|
||||||
|
//箭头图标颜色
|
||||||
|
arrowColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#cbcbcb"
|
||||||
|
},
|
||||||
|
checkColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#19be6b"
|
||||||
|
},
|
||||||
|
//滑动条背景色
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#E9E9E9"
|
||||||
|
},
|
||||||
|
//滑过区域背景颜色
|
||||||
|
activeBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#19be6b"
|
||||||
|
},
|
||||||
|
//通过提示文字
|
||||||
|
passText: {
|
||||||
|
type: String,
|
||||||
|
default: '验证通过'
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
getBgColor() {
|
||||||
|
return `-webkit-gradient(linear, left top, right top, color-stop(0, ${this.color}), color-stop(.4, ${this.color}), color-stop(.5, white), color-stop(.6, ${this.color}), color-stop(1, ${this.color}))`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
resetSlide(val) {
|
||||||
|
if (val > 0) {
|
||||||
|
this.slideReset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isPass: false,
|
||||||
|
disabled: false,
|
||||||
|
reset: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
success() {
|
||||||
|
//验证成功
|
||||||
|
this.isPass = true;
|
||||||
|
this.disabled = true;
|
||||||
|
this.$emit('success', {})
|
||||||
|
},
|
||||||
|
slideReset() {
|
||||||
|
this.isPass = false;
|
||||||
|
this.disabled = false;
|
||||||
|
this.reset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'tuiSlideVcode';
|
||||||
|
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAUYAA0AAAAAB1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAE/AAAABoAAAAci6lfG0dERUYAAATcAAAAHgAAAB4AKQALT1MvMgAAAaAAAABCAAAAVjxuSCZjbWFwAAAB+AAAAEUAAAFK5n3pi2dhc3AAAATUAAAACAAAAAj//wADZ2x5ZgAAAkwAAAD8AAABJDQ/n7JoZWFkAAABMAAAADAAAAA2GSR8FGhoZWEAAAFgAAAAHQAAACQHygOFaG10eAAAAeQAAAARAAAAEgwUAD5sb2NhAAACQAAAAAwAAAAMAFQAkm1heHAAAAGAAAAAHgAAACABEQA6bmFtZQAAA0gAAAFJAAACiCnmEVVwb3N0AAAElAAAAD0AAABPYJEgVXjaY2BkYGAA4oqPSw3j+W2+MnCzMIDAbaY5nHBa5P905jfMeUAuBwMTSBQAHycKCHjaY2BkYGBu+N/AEMPCAALMbxgYGVABCwBYegNYAAAAeNpjYGRgYGBl0GNgYgABEMkFhAwM/8F8BgANfQFMAAB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PGJ6ZMDf8b2CIYW5gaAAKM4LkAN6ZDA8AAHjaY2GAABYItmMQAQABaABfAAAAeNpjYGBgZoBgGQZGBhBwAfIYwXwWBg0gzQakGRmYnjE8M/n/n4EBQksxS16AqgcCRjYGOIeRCUgwMaACRoZhDwDR6wnSAAAAAAAAAAAAAAAAVACSeNpFzjFOwzAYxfHv2Yodu4ozxHEq2qoSEilLQYoqh6lIIBaugMTC3hswMcPQhYmBjV4AMSFxAppjQDmDSzJle9L7DX9itNx/8i9+QY7mRPDn8ItTlDOcQLhCwcBVtWLCOl/D10v0L5vHnAGMx+EuLSctvQ8PBpMyxWU30/GxwUvMwXqDW6lkNIikllgnGM1MeAqPyWxkeNktczRGgrXUXOkeETGy+2f+x1c0oGnbKUg6KjzVJWUQh23TwlfTrhW+cpZRE3ZCIG8a5EKE3U34yM/sRttCb5hiuNLDjK+i8PO9Db8igmu2cOE1vNsWDTP9xhiuVXZARP+yvTqbeNp9kD1OAzEQhZ/zByQSQiCoXVEA2vyUKRMp9Ailo0g23pBo1155nUg5AS0VB6DlGByAGyDRcgpelkmTImvt6PObmeexAZzjGwr/3yXuhBWO8ShcwREy4Sr1F+Ea+V24jhY+hRvUf4SbuFUD4RYu1BsdVO2Eu5vSbcsKZxgIV3CKJ+Eq9ZVwjfwqXMcVPoQb1L+EmxjjV7iFa2WpDOFhMEFgnEFjig3jAjEcLJIyBtahOfRmEsxMTzd6ETubOBso71dilwMeaDnngCntPbdmvkon/mDLgdSYbh4FS7YpjS4idCgbXyyc1d2oc7D9nu22tNi/a4E1x+xRDWzU/D3bM9JIbAyvkJI18jK3pBJTj2hrrPG7ZynW814IiU68y/SIx5o0dTr3bmniwOLn8owcfbS5kj33qBw+Y1kIeb/dTsQgil2GP5PYcRkAAAB42mNgYoAALjDJyIAOWMGiTIxMjMyCOalpJbop+aVJOam6iUVF+eUCKaWZ6fmlJZmJeckZ+XnpugDvDw1eAAAAAAAAAf//AAIAAQAAAAwAAAAWAAAAAgABAAMABAABAAQAAAACAAAAAHjaY2BgYGQAgqtL1DlA9G2mOZwwGgA1wQSuAAA=) format('woff');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
font-display: swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-slide-icon {
|
||||||
|
font-family: "tuiSlideVcode" !important;
|
||||||
|
font-size: 34rpx;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-icon-check_mark:before {
|
||||||
|
content: "\e634";
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-icon-double_arrow:before {
|
||||||
|
content: "\e600";
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-slide-vcode {
|
||||||
|
background-color: #EAEEF1;
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-slide-glided {
|
||||||
|
width: 0;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #19BE6B;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-slider-block {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: 1rpx solid;
|
||||||
|
box-sizing: border-box;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
transition: border-color 0.08s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-text-flashover {
|
||||||
|
-webkit-background-clip: text !important;
|
||||||
|
-webkit-text-fill-color: transparent !important;
|
||||||
|
-webkit-animation: animate 1.8s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes animate {
|
||||||
|
from {
|
||||||
|
background-position: -90rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
background-position: 90rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes animate {
|
||||||
|
from {
|
||||||
|
background-position: -90rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
background-position: 90rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,73 @@
|
||||||
|
var slideBarWidth = 200;
|
||||||
|
var slideBlockWidth = 32;
|
||||||
|
var errorRange = 2
|
||||||
|
var disabled = false
|
||||||
|
|
||||||
|
function bool(str) {
|
||||||
|
return str === 'true' || str == true ? true : false
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchstart(e, ins) {
|
||||||
|
var state=e.instance.getState()
|
||||||
|
var touch = e.touches[0] || e.changedTouches[0]
|
||||||
|
var dataset = e.instance.getDataset()
|
||||||
|
state.startX = touch.pageX
|
||||||
|
slideBarWidth = +dataset.slidebarwidth
|
||||||
|
slideBlockWidth = +dataset.slideblockwidth
|
||||||
|
errorRange = +dataset.errorrange
|
||||||
|
disabled = bool(dataset.disabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
function styleChange(left, ins) {
|
||||||
|
if (!ins) return;
|
||||||
|
ins.selectComponent('.tui-slider-block').setStyle({
|
||||||
|
transform: 'translate3d(' + left + 'px,0,0)'
|
||||||
|
})
|
||||||
|
ins.selectComponent('.tui-slide-glided').setStyle({
|
||||||
|
width: left + 'px'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchmove(e, ins) {
|
||||||
|
if (disabled) return;
|
||||||
|
var state=e.instance.getState()
|
||||||
|
var touch = e.touches[0] || e.changedTouches[0]
|
||||||
|
var pageX = touch.pageX;
|
||||||
|
var left = pageX - state.startX + (state.lastLeft || 0);
|
||||||
|
left = left < 0 ? 0 : left;
|
||||||
|
var width = slideBarWidth - slideBlockWidth;
|
||||||
|
left = left >= width ? width : left;
|
||||||
|
state.startX = pageX
|
||||||
|
state.lastLeft = left
|
||||||
|
styleChange(left, ins)
|
||||||
|
}
|
||||||
|
|
||||||
|
function touchend(e, ins) {
|
||||||
|
if (disabled) return;
|
||||||
|
var state=e.instance.getState()
|
||||||
|
let left = slideBarWidth - slideBlockWidth
|
||||||
|
if (left - state.lastLeft <= errorRange) {
|
||||||
|
styleChange(left, ins)
|
||||||
|
ins.callMethod('success')
|
||||||
|
} else {
|
||||||
|
state.startX = 0;
|
||||||
|
state.lastLeft = 0;
|
||||||
|
styleChange(0, ins)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function slidereset(reset, oldreset, owner, ins) {
|
||||||
|
var state=ins.getState()
|
||||||
|
if (reset > 0) {
|
||||||
|
state.startX = 0;
|
||||||
|
state.lastLeft = 0;
|
||||||
|
styleChange(0, owner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
touchstart: touchstart,
|
||||||
|
touchmove: touchmove,
|
||||||
|
touchend: touchend,
|
||||||
|
slidereset: slidereset
|
||||||
|
}
|
|
@ -0,0 +1,253 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-steps-box" :class="{ 'tui-steps-column': direction === 'column' }">
|
||||||
|
<view class="tui-step-item" :style="{ width: direction === 'column' ? '100%' : spacing }"
|
||||||
|
:class="[direction === 'row' ? 'tui-step-horizontal' : 'tui-step-vertical']" v-for="(item, index) in items"
|
||||||
|
:key="index" @tap.stop="handleClick(index)">
|
||||||
|
<view class="tui-step-item-ico" :class="[direction === 'column' ? 'tui-step-column_ico' : 'tui-step-row_ico']" :style="{ width: direction === 'column' ? '36rpx' : '100%' }">
|
||||||
|
<view v-if="!item.name && !item.icon" class="tui-step-ico"
|
||||||
|
:style="{
|
||||||
|
width: type == 2 || activeSteps === index ? '36rpx' : '16rpx',
|
||||||
|
height: type == 2 || activeSteps === index ? '36rpx' : '16rpx',
|
||||||
|
backgroundColor: index <= activeSteps ? activeColor : type == 2 ? '#fff' : deactiveColor,
|
||||||
|
borderColor: index <= activeSteps ? activeColor : deactiveColor
|
||||||
|
}">
|
||||||
|
<text v-if="activeSteps !== index"
|
||||||
|
:style="{ color: index <= activeSteps ? '#fff' : '' }">{{ type == 1 ? '' : index + 1 }}</text>
|
||||||
|
<tui-icon name="check" :size="16" color="#fff" v-if="activeSteps === index"></tui-icon>
|
||||||
|
</view>
|
||||||
|
<view class="tui-step-custom" :style="{ backgroundColor: backgroundColor }"
|
||||||
|
v-if="item.name || item.icon">
|
||||||
|
<tui-icon :name="item.name" :size="20" :color="index <= activeSteps ? activeColor : deactiveColor"
|
||||||
|
v-if="item.name"></tui-icon>
|
||||||
|
<image :src="index <= activeSteps ? item.activeIcon : item.icon" class="tui-step-img"
|
||||||
|
mode="widthFix" v-if="!item.name"></image>
|
||||||
|
</view>
|
||||||
|
<view class="tui-step-line"
|
||||||
|
:class="['tui-step-' + direction + '_line', direction == 'column' && (item.name || item.icon) ? 'tui-custom-left' : '']"
|
||||||
|
:style="{
|
||||||
|
borderColor: index <= activeSteps - 1 ? activeColor : deactiveColor,
|
||||||
|
borderRightStyle: direction == 'column' ? lineStyle : '',
|
||||||
|
borderTopStyle: direction == 'column' ? '' : lineStyle
|
||||||
|
}" v-if="index != items.length - 1"></view>
|
||||||
|
</view>
|
||||||
|
<view class="tui-step-item-main" :class="['tui-step-' + direction + '_item_main']">
|
||||||
|
<view class="tui-step-item-title" :style="{
|
||||||
|
color: index <= activeSteps ? activeColor : deactiveColor,
|
||||||
|
fontSize: titleSize + 'rpx',
|
||||||
|
lineHeight: titleSize + 'rpx',
|
||||||
|
fontWeight: bold ? 'bold' : 'normal'
|
||||||
|
}">
|
||||||
|
{{ item.title }}
|
||||||
|
</view>
|
||||||
|
<view class="tui-step-item-content"
|
||||||
|
:style="{ color: index <= activeSteps ? activeColor : deactiveColor, fontSize: descSize + 'rpx' }">
|
||||||
|
{{ item.desc }}</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
//如果自定义传入图标内容,则需要拆分组件
|
||||||
|
export default {
|
||||||
|
name: 'tuiSteps',
|
||||||
|
emits: ['click'],
|
||||||
|
props: {
|
||||||
|
// 1-默认步骤 2-数字步骤
|
||||||
|
type: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
spacing: {
|
||||||
|
type: String,
|
||||||
|
default: '160rpx'
|
||||||
|
},
|
||||||
|
// 方向 row column
|
||||||
|
direction: {
|
||||||
|
type: String,
|
||||||
|
default: 'row'
|
||||||
|
},
|
||||||
|
// 激活状态成功颜色
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#5677fc'
|
||||||
|
},
|
||||||
|
// 未激活状态颜色
|
||||||
|
deactiveColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#999999'
|
||||||
|
},
|
||||||
|
//title字体大小
|
||||||
|
titleSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 28
|
||||||
|
},
|
||||||
|
//title是否粗体
|
||||||
|
bold: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//desc字体大小
|
||||||
|
descSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 24
|
||||||
|
},
|
||||||
|
// 当前步骤
|
||||||
|
activeSteps: {
|
||||||
|
type: Number,
|
||||||
|
default: -1
|
||||||
|
},
|
||||||
|
//线条样式 同border线条样式
|
||||||
|
lineStyle: {
|
||||||
|
type: String,
|
||||||
|
default: 'solid'
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* [{
|
||||||
|
title: "标题",
|
||||||
|
desc: "描述",
|
||||||
|
name:"字体图标 thorui icon内",
|
||||||
|
icon:"图片图标",
|
||||||
|
activeIcon:"已完成步骤显示图片图标"
|
||||||
|
}]
|
||||||
|
* */
|
||||||
|
items: {
|
||||||
|
type: Array,
|
||||||
|
default () {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//自定义item内容时背景色
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#fff'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClick(index) {
|
||||||
|
this.$emit('click', {
|
||||||
|
index: index
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-steps-box {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-steps-column {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-ico {
|
||||||
|
border-radius: 50%;
|
||||||
|
position: relative;
|
||||||
|
z-index: 3;
|
||||||
|
margin: 0 auto;
|
||||||
|
border-width: 1rpx;
|
||||||
|
border-style: solid;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-row_ico {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-column_ico {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-line {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 20rpx;
|
||||||
|
width: 100%;
|
||||||
|
height: 0rpx;
|
||||||
|
border-top-width: 1rpx;
|
||||||
|
z-index: 2;
|
||||||
|
transform: translateY(-50%) translateZ(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-row_item_main {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-item {
|
||||||
|
font-size: 24rpx;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-item-ico {
|
||||||
|
height: 36rpx;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-custom {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 48rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
position: relative;
|
||||||
|
z-index: 4;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-img {
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-item-main {
|
||||||
|
margin-top: 16rpx;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-item-title {
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-item-content {
|
||||||
|
margin-top: 8rpx;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-vertical {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
padding-bottom: 60rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-column_item_main {
|
||||||
|
margin-top: 0;
|
||||||
|
padding-left: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-step-column_line {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
top: 0;
|
||||||
|
left: 18rpx;
|
||||||
|
margin: 0;
|
||||||
|
width: 0rpx;
|
||||||
|
border-right-width: 1rpx;
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-custom-left {
|
||||||
|
left: 20rpx !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,125 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-sticky-class" :change:prop="parse.stickyChange" :prop="scrollTop" :data-top="top" :data-height="height"
|
||||||
|
:data-stickytop="stickyTop" :data-container="container" :data-isNativeHeader="isNativeHeader" :data-index="index">
|
||||||
|
<!--sticky 容器-->
|
||||||
|
<view class="tui-sticky-seat" :style="{ height: stickyHeight, backgroundColor: backgroundColor }"></view>
|
||||||
|
<view class="tui-sticky-bar">
|
||||||
|
<slot name="header"></slot>
|
||||||
|
</view>
|
||||||
|
<!--sticky 容器-->
|
||||||
|
<!--内容-->
|
||||||
|
<slot name="content"></slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
<script src="./tui-sticky.wxs" module="parse" lang="wxs"></script>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiStickyWxs',
|
||||||
|
emits: ['prop', 'change'],
|
||||||
|
props: {
|
||||||
|
scrollTop: {
|
||||||
|
type: [Number, String],
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
//吸顶时与顶部的距离,单位px
|
||||||
|
stickyTop: {
|
||||||
|
type: [Number, String],
|
||||||
|
// #ifndef H5
|
||||||
|
default: 0,
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
default: 44
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
//是否指定容器,即内容放置插槽content内
|
||||||
|
container: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//是否是原生自带header
|
||||||
|
isNativeHeader: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//吸顶容器 高度 rpx
|
||||||
|
stickyHeight: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
//占位容器背景颜色
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'transparent'
|
||||||
|
},
|
||||||
|
//是否重新计算[有异步加载时使用,设置大于0的数]
|
||||||
|
recalc: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
//列表中的索引值
|
||||||
|
index: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
recalc(newValue, oldValue) {
|
||||||
|
this.updateScrollChange(() => {
|
||||||
|
//更新prop scrollTop值(+0.1即可),触发change事件
|
||||||
|
this.$emit("prop",{})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.updateScrollChange();
|
||||||
|
}, 20);
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
timer: null,
|
||||||
|
top: 0,
|
||||||
|
height: 0
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateScrollChange(callback) {
|
||||||
|
if (this.timer) {
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
}
|
||||||
|
this.timer = setTimeout(() => {
|
||||||
|
const className = '.tui-sticky-class';
|
||||||
|
const query = uni.createSelectorQuery().in(this);
|
||||||
|
query
|
||||||
|
.select(className)
|
||||||
|
.boundingClientRect(res => {
|
||||||
|
if (res) {
|
||||||
|
this.top = res.top + (this.scrollTop || 0);
|
||||||
|
this.height = res.height;
|
||||||
|
callback && callback();
|
||||||
|
this.$emit('change', {
|
||||||
|
index: Number(this.index),
|
||||||
|
top: this.top
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.exec();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-sticky-fixed {
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
z-index: 998;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-sticky-seat {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,44 @@
|
||||||
|
var stickyChange = function(scrollTop, oldScrollTop, ownerInstance, ins) {
|
||||||
|
if (!oldScrollTop && scrollTop === 0) return false;
|
||||||
|
var dataset = ins.getDataset()
|
||||||
|
var top = +dataset.top;
|
||||||
|
var height = +dataset.height;
|
||||||
|
var stickyTop = +dataset.stickytop;
|
||||||
|
var isNativeHeader = dataset.isnativeheader;
|
||||||
|
var isFixed = false;
|
||||||
|
var distance = stickyTop
|
||||||
|
// #ifdef H5
|
||||||
|
if (isNativeHeader) {
|
||||||
|
distance = distance - 44
|
||||||
|
distance = distance < 0 ? 0 : distance
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
if (dataset.container) {
|
||||||
|
isFixed = (scrollTop + distance >= top && scrollTop + distance < top + height) ? true : false
|
||||||
|
} else {
|
||||||
|
isFixed = scrollTop + distance >= top ? true : false
|
||||||
|
}
|
||||||
|
if (isFixed) {
|
||||||
|
ownerInstance.selectComponent('.tui-sticky-bar').setStyle({
|
||||||
|
"top": stickyTop + 'px'
|
||||||
|
}).addClass('tui-sticky-fixed')
|
||||||
|
ownerInstance.selectComponent('.tui-sticky-seat').setStyle({
|
||||||
|
"display": 'block'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ownerInstance.selectComponent('.tui-sticky-bar').setStyle({
|
||||||
|
"top": 'auto'
|
||||||
|
}).removeClass('tui-sticky-fixed')
|
||||||
|
ownerInstance.selectComponent('.tui-sticky-seat').setStyle({
|
||||||
|
"display": 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ownerInstance.triggerEvent("sticky", [{
|
||||||
|
isFixed: isFixed,
|
||||||
|
index: parseInt(dataset.index)
|
||||||
|
}])
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
stickyChange: stickyChange
|
||||||
|
}
|
|
@ -0,0 +1,155 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-sticky-class">
|
||||||
|
<!--sticky 容器-->
|
||||||
|
<view :style="{height: stickyHeight,backgroundColor:backgroundColor}" v-if="isFixed"></view>
|
||||||
|
<view :class="{'tui-sticky-fixed':isFixed}" :style="{top:isFixed?stickyTop+'px':'auto'}">
|
||||||
|
<slot name="header"></slot>
|
||||||
|
</view>
|
||||||
|
<!--sticky 容器-->
|
||||||
|
<!--内容-->
|
||||||
|
<slot name="content"></slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "tuiSticky",
|
||||||
|
emits: ['sticky', 'change'],
|
||||||
|
props: {
|
||||||
|
scrollTop: {
|
||||||
|
type: Number
|
||||||
|
},
|
||||||
|
//吸顶时与顶部的距离,单位px
|
||||||
|
stickyTop: {
|
||||||
|
type: [Number, String]
|
||||||
|
// #ifndef H5
|
||||||
|
,
|
||||||
|
default: 0
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
,
|
||||||
|
default: 44
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
//是否指定容器,即内容放置插槽content内
|
||||||
|
container: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//是否是原生自带header
|
||||||
|
isNativeHeader: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
//吸顶容器 高度 rpx
|
||||||
|
stickyHeight: {
|
||||||
|
type: String,
|
||||||
|
default: "auto"
|
||||||
|
},
|
||||||
|
//占位容器背景颜色
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: "transparent"
|
||||||
|
},
|
||||||
|
//是否重新计算[有异步加载时使用,设置大于0的数]
|
||||||
|
recalc: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
//列表中的索引值
|
||||||
|
index: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
scrollTop(newValue, oldValue) {
|
||||||
|
if (this.initialize != 0) {
|
||||||
|
this.updateScrollChange(() => {
|
||||||
|
this.updateStickyChange();
|
||||||
|
this.initialize = 0
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.updateStickyChange();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
recalc(newValue, oldValue) {
|
||||||
|
this.updateScrollChange(() => {
|
||||||
|
this.updateStickyChange();
|
||||||
|
this.initialize = 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.initialize = this.recalc
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.updateScrollChange();
|
||||||
|
}, 20)
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
timer: null,
|
||||||
|
top: 0,
|
||||||
|
height: 0,
|
||||||
|
isFixed: false,
|
||||||
|
initialize: 0 //重新初始化
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateStickyChange() {
|
||||||
|
const top = this.top;
|
||||||
|
const height = this.height;
|
||||||
|
const scrollTop = this.scrollTop
|
||||||
|
let stickyTop = this.stickyTop
|
||||||
|
// #ifdef H5
|
||||||
|
if (this.isNativeHeader) {
|
||||||
|
stickyTop = stickyTop - 44
|
||||||
|
stickyTop = stickyTop < 0 ? 0 : stickyTop
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
if (this.container) {
|
||||||
|
this.isFixed = (scrollTop + stickyTop >= top && scrollTop + stickyTop < top + height) ? true : false
|
||||||
|
} else {
|
||||||
|
this.isFixed = scrollTop + stickyTop >= top ? true : false
|
||||||
|
}
|
||||||
|
//是否吸顶
|
||||||
|
this.$emit("sticky", {
|
||||||
|
isFixed: this.isFixed,
|
||||||
|
index: this.index
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateScrollChange(callback) {
|
||||||
|
if (this.timer) {
|
||||||
|
clearTimeout(this.timer)
|
||||||
|
this.timer = null
|
||||||
|
}
|
||||||
|
this.timer = setTimeout(() => {
|
||||||
|
const className = '.tui-sticky-class';
|
||||||
|
const query = uni.createSelectorQuery().in(this);
|
||||||
|
query.select(className).boundingClientRect((res) => {
|
||||||
|
if (res) {
|
||||||
|
this.top = res.top + (this.scrollTop || 0);
|
||||||
|
this.height = res.height;
|
||||||
|
callback && callback();
|
||||||
|
this.$emit("change", {
|
||||||
|
index: Number(this.index),
|
||||||
|
top: this.top
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).exec()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-sticky-fixed {
|
||||||
|
width: 100%;
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
z-index: 888;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,360 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-tag" :hover-class="hover ? 'tui-tag-opcity' : ''" :hover-stay-time="150" :class="[originLeft ? 'tui-origin-left' : '', originRight ? 'tui-origin-right' : '', getClassName(shape, plain), getTypeClass(type, plain)]"
|
||||||
|
:style="{ transform: `scale(${scaleMultiple})`, padding: padding, margin: margin, fontSize: size, lineHeight: size }"
|
||||||
|
@tap="handleClick">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiTag',
|
||||||
|
emits: ['click'],
|
||||||
|
props: {
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'primary'
|
||||||
|
},
|
||||||
|
//padding
|
||||||
|
padding: {
|
||||||
|
type: String,
|
||||||
|
default: '16rpx 26rpx'
|
||||||
|
},
|
||||||
|
margin: {
|
||||||
|
type: String,
|
||||||
|
default: '0'
|
||||||
|
},
|
||||||
|
//文字大小 rpx
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: '28rpx'
|
||||||
|
},
|
||||||
|
// circle, square,circleLeft,circleRight
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: 'square'
|
||||||
|
},
|
||||||
|
//是否空心
|
||||||
|
plain: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//点击效果
|
||||||
|
hover: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
//缩放倍数
|
||||||
|
scaleMultiple: {
|
||||||
|
type: Number,
|
||||||
|
default: 1
|
||||||
|
},
|
||||||
|
originLeft: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
originRight: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
index: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleClick() {
|
||||||
|
this.$emit('click', {
|
||||||
|
index: this.index
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getTypeClass: function(type, plain) {
|
||||||
|
return plain ? 'tui-' + type + '-outline' : 'tui-' + type;
|
||||||
|
},
|
||||||
|
getClassName: function(shape, plain) {
|
||||||
|
//circle, square,circleLeft,circleRight
|
||||||
|
var className = plain ? 'tui-tag-outline ' : '';
|
||||||
|
if (shape != 'square') {
|
||||||
|
if (shape == 'circle') {
|
||||||
|
className = className + (plain ? 'tui-tag-outline-fillet' : 'tui-tag-fillet');
|
||||||
|
} else if (shape == 'circleLeft') {
|
||||||
|
className = className + 'tui-tag-fillet-left';
|
||||||
|
} else if (shape == 'circleRight') {
|
||||||
|
className = className + 'tui-tag-fillet-right';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return className;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* color start*/
|
||||||
|
|
||||||
|
.tui-primary {
|
||||||
|
background: #5677fc !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-light-primary {
|
||||||
|
background: #5c8dff !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-dark-primary {
|
||||||
|
background: #4a67d6 !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-dLight-primary {
|
||||||
|
background: #4e77d9 !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-danger {
|
||||||
|
background: #ed3f14 !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-red {
|
||||||
|
background: #ff201f !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-warning {
|
||||||
|
background: #ff7900 !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-green {
|
||||||
|
background: #19be6b !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-high-green {
|
||||||
|
background: #52dcae !important;
|
||||||
|
color: #52dcae;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-black {
|
||||||
|
background: #000 !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-white {
|
||||||
|
background: #fff !important;
|
||||||
|
color: #333 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-translucent {
|
||||||
|
background: rgba(0, 0, 0, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-light-black {
|
||||||
|
background: #333 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray {
|
||||||
|
background: #ededed !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-phcolor-gray {
|
||||||
|
background: #ccc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-divider-gray {
|
||||||
|
background: #eaeef1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-btn-gray {
|
||||||
|
background: #ededed !important;
|
||||||
|
color: #999 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-hover-gray {
|
||||||
|
background: #f7f7f9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-bg-gray {
|
||||||
|
background: #fafafa !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-light-blue {
|
||||||
|
background: #ecf6fd;
|
||||||
|
color: #4dabeb !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-light-brownish {
|
||||||
|
background: #fcebef;
|
||||||
|
color: #8a5966 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-light-orange {
|
||||||
|
background: #fef5eb;
|
||||||
|
color: #faa851 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-light-green {
|
||||||
|
background: #e8f6e8;
|
||||||
|
color: #44cf85 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-primary-outline::after {
|
||||||
|
border: 1px solid #5677fc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-primary-outline {
|
||||||
|
color: #5677fc !important;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-danger-outline {
|
||||||
|
color: #ed3f14 !important;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-danger-outline::after {
|
||||||
|
border: 1px solid #ed3f14 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-red-outline {
|
||||||
|
color: #ff201f !important;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-red-outline::after {
|
||||||
|
border: 1px solid #ff201f !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-warning-outline {
|
||||||
|
color: #ff7900 !important;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-warning-outline::after {
|
||||||
|
border: 1px solid #ff7900 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-green-outline {
|
||||||
|
color: #44cf85 !important;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-green-outline::after {
|
||||||
|
border: 1px solid #44cf85 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-high-green-outline {
|
||||||
|
color: #52dcae !important;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-high-green-outline::after {
|
||||||
|
border: 1px solid #52dcae !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray-outline {
|
||||||
|
color: #999 !important;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-gray-outline::after {
|
||||||
|
border: 1px solid #ccc !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tui-black-outline {
|
||||||
|
color: #333 !important;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-black-outline::after {
|
||||||
|
border: 1px solid #333 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-white-outline {
|
||||||
|
color: #fff !important;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-white-outline::after {
|
||||||
|
border: 1px solid #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* color end*/
|
||||||
|
|
||||||
|
/* tag start*/
|
||||||
|
|
||||||
|
.tui-tag {
|
||||||
|
padding: 16rpx 26rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
/* display: inline-block;
|
||||||
|
vertical-align: middle; */
|
||||||
|
line-height: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tag-small {
|
||||||
|
padding: 10rpx 16rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
/* display: inline-block;
|
||||||
|
vertical-align: middle; */
|
||||||
|
line-height: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tag-outline {
|
||||||
|
position: relative;
|
||||||
|
background: none;
|
||||||
|
color: #5677fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tag-outline::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
width: 200%;
|
||||||
|
height: 200%;
|
||||||
|
-webkit-transform-origin: 0 0;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
-webkit-transform: scale(0.5, 0.5);
|
||||||
|
transform: scale(0.5, 0.5);
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
border-radius: 80rpx;
|
||||||
|
border: 1px solid #5677fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tag-fillet {
|
||||||
|
border-radius: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-white.tui-tag-fillet::after {
|
||||||
|
border-radius: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tag-outline-fillet::after {
|
||||||
|
border-radius: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tag-fillet-left {
|
||||||
|
border-radius: 50rpx 0 0 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tag-fillet-right {
|
||||||
|
border-radius: 0 50rpx 50rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tag-fillet-left.tui-tag-outline::after {
|
||||||
|
border-radius: 100rpx 0 0 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tag-fillet-right.tui-tag-outline::after {
|
||||||
|
border-radius: 0 100rpx 100rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tag end*/
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,129 @@
|
||||||
|
<template>
|
||||||
|
<block v-if="position == 'top'">
|
||||||
|
<view class="tui-tips-class tui-toptips" :style="{backgroundColor:backgroundColor,color:color,fontSize:size+'rpx'}" :class="[show ? 'tui-top-show' : '']">{{ msg }}</view>
|
||||||
|
</block>
|
||||||
|
<block v-else>
|
||||||
|
<view class="tui-tips-class tui-toast" :class="[position == 'center' ? 'tui-centertips' : 'tui-bottomtips', show ? 'tui-toast-show' : '']">
|
||||||
|
<view class="tui-tips-content" :style="{backgroundColor:backgroundColor,color:color,fontSize:size+'rpx'}">{{ msg }}</view>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'tuiTips',
|
||||||
|
props: {
|
||||||
|
//top bottom center
|
||||||
|
position: {
|
||||||
|
type: String,
|
||||||
|
default: 'top'
|
||||||
|
},
|
||||||
|
backgroundColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'rgba(0, 0, 0, 0.7)'
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#fff'
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
timer: null,
|
||||||
|
show: false,
|
||||||
|
msg: '无法连接到服务器~'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
showTips: function(options) {
|
||||||
|
const {duration = 2000 } = options;
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
this.show = true;
|
||||||
|
// this.duration = duration < 2000 ? 2000 : duration;
|
||||||
|
this.msg = options.msg;
|
||||||
|
this.timer = setTimeout(() => {
|
||||||
|
this.show = false;
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
}, duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/*顶部消息提醒 start*/
|
||||||
|
.tui-toptips {
|
||||||
|
width: 100%;
|
||||||
|
padding: 18rpx 30rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9999;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
word-break: break-all;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateZ(0) translateY(-100%);
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-top-show {
|
||||||
|
transform: translateZ(0) translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*顶部消息提醒 end*/
|
||||||
|
|
||||||
|
/*toast消息提醒 start*/
|
||||||
|
|
||||||
|
/*注意问题:
|
||||||
|
1、fixed 元素宽度无法自适应,所以增加了子元素
|
||||||
|
2、fixed 和 display冲突导致动画效果消失,暂时使用visibility替代
|
||||||
|
*/
|
||||||
|
.tui-toast {
|
||||||
|
width: 80%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 28rpx;
|
||||||
|
position: fixed;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
left: 50%;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
z-index: 9999;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-toast-show {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-tips-content {
|
||||||
|
word-wrap: break-word;
|
||||||
|
word-break: break-all;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 18rpx 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-bottomtips {
|
||||||
|
bottom: 120rpx;
|
||||||
|
-webkit-transform: translateX(-50%);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-centertips {
|
||||||
|
top: 50%;
|
||||||
|
-webkit-transform: translate(-50%, -50%);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,121 @@
|
||||||
|
<template>
|
||||||
|
<view class="tui-toast" :class="[visible?'tui-toast-show':'',content?'tui-toast-padding':'',icon?'':'tui-unicon-padding']" :style="{width:getWidth(icon,content),zIndex:zIndex}">
|
||||||
|
<image :src="imgUrl" class="tui-toast-img" v-if="icon"></image>
|
||||||
|
<view class="tui-toast-text" :class="[icon?'':'tui-unicon']">{{title}}</view>
|
||||||
|
<view class="tui-toast-text tui-content-ptop" v-if="content && icon">{{content}}</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "tuiToast",
|
||||||
|
props: {
|
||||||
|
zIndex:{
|
||||||
|
type:Number,
|
||||||
|
default:99999
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
timer: null,
|
||||||
|
//是否显示
|
||||||
|
visible: false,
|
||||||
|
//显示标题
|
||||||
|
title: "操作成功",
|
||||||
|
//显示内容
|
||||||
|
content: "",
|
||||||
|
//是否有icon
|
||||||
|
icon:false,
|
||||||
|
imgUrl:""
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
show: function(options) {
|
||||||
|
let {
|
||||||
|
duration = 2000,
|
||||||
|
icon=false
|
||||||
|
} = options;
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
this.visible = true;
|
||||||
|
this.title = options.title || "";
|
||||||
|
this.content = options.content || "";
|
||||||
|
this.icon=icon;
|
||||||
|
if(icon && options.imgUrl){
|
||||||
|
this.imgUrl=options.imgUrl
|
||||||
|
}
|
||||||
|
this.timer = setTimeout(() => {
|
||||||
|
this.visible = false;
|
||||||
|
clearTimeout(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
}, duration);
|
||||||
|
},
|
||||||
|
getWidth(icon,content){
|
||||||
|
let width="auto";
|
||||||
|
if(icon){
|
||||||
|
width=content?'420rpx':'360rpx'
|
||||||
|
}
|
||||||
|
return width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.tui-toast {
|
||||||
|
background-color: rgba(0, 0, 0, 0.75);
|
||||||
|
border-radius: 10rpx;
|
||||||
|
position: fixed;
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
left: 50%;
|
||||||
|
top: 48%;
|
||||||
|
-webkit-transform: translate(-50%, -50%);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
transition: 0.3s ease-in-out;
|
||||||
|
transition-property:opacity,visibility;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 60rpx 20rpx 54rpx 20rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-toast-padding {
|
||||||
|
padding-top: 50rpx !important;
|
||||||
|
padding-bottom: 50rpx !important;
|
||||||
|
}
|
||||||
|
.tui-unicon-padding {
|
||||||
|
padding: 24rpx 40rpx !important;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-toast-show {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.tui-toast-img {
|
||||||
|
width: 120rpx;
|
||||||
|
height: 120rpx;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tui-toast-text {
|
||||||
|
font-size: 30rpx;
|
||||||
|
line-height: 30rpx;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.tui-unicon{
|
||||||
|
line-height: 40rpx !important;
|
||||||
|
font-size: 32rpx !important;
|
||||||
|
}
|
||||||
|
.tui-content-ptop {
|
||||||
|
padding-top: 10rpx;
|
||||||
|
font-size: 26rpx !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2023 www.uviewui.com
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,66 @@
|
||||||
|
<p align="center">
|
||||||
|
<img alt="logo" src="https://uviewui.com/common/logo.png" width="120" height="120" style="margin-bottom: 10px;">
|
||||||
|
</p>
|
||||||
|
<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uView 2.0</h3>
|
||||||
|
<h3 align="center">多平台快速开发的UI框架</h3>
|
||||||
|
|
||||||
|
[![stars](https://img.shields.io/github/stars/umicro/uView2.0?style=flat-square&logo=GitHub)](https://github.com/umicro/uView2.0)
|
||||||
|
[![forks](https://img.shields.io/github/forks/umicro/uView2.0?style=flat-square&logo=GitHub)](https://github.com/umicro/uView2.0)
|
||||||
|
[![issues](https://img.shields.io/github/issues/umicro/uView2.0?style=flat-square&logo=GitHub)](https://github.com/umicro/uView2.0/issues)
|
||||||
|
[![Website](https://img.shields.io/badge/uView-up-blue?style=flat-square)](https://uviewui.com)
|
||||||
|
[![release](https://img.shields.io/github/v/release/umicro/uView2.0?style=flat-square)](https://gitee.com/umicro/uView2.0/releases)
|
||||||
|
[![license](https://img.shields.io/github/license/umicro/uView2.0?style=flat-square)](https://en.wikipedia.org/wiki/MIT_License)
|
||||||
|
|
||||||
|
## 说明
|
||||||
|
|
||||||
|
uView UI,是[uni-app](https://uniapp.dcloud.io/)全面兼容nvue的uni-app生态框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水
|
||||||
|
|
||||||
|
## [官方文档:https://uviewui.com](https://uviewui.com)
|
||||||
|
|
||||||
|
|
||||||
|
## 预览
|
||||||
|
|
||||||
|
您可以通过**微信**扫码,查看最佳的演示效果。
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<img src="https://uviewui.com/common/weixin_mini_qrcode.png" width="220" height="220" >
|
||||||
|
|
||||||
|
|
||||||
|
## 链接
|
||||||
|
|
||||||
|
- [官方文档](https://www.uviewui.com/)
|
||||||
|
- [更新日志](https://www.uviewui.com/components/changelog.html)
|
||||||
|
- [升级指南](https://www.uviewui.com/components/changeGuide.html)
|
||||||
|
- [关于我们](https://www.uviewui.com/cooperation/about.html)
|
||||||
|
|
||||||
|
## 交流反馈
|
||||||
|
|
||||||
|
欢迎加入我们的QQ群交流反馈:[点此跳转](https://www.uviewui.com/components/addQQGroup.html)
|
||||||
|
|
||||||
|
## 关于PR
|
||||||
|
|
||||||
|
> 我们非常乐意接受各位的优质PR,但在此之前我希望您了解uView2.0是一个需要兼容多个平台的(小程序、h5、ios app、android app)包括nvue页面、vue页面。
|
||||||
|
> 所以希望在您修复bug并提交之前尽可能的去这些平台测试一下兼容性。最好能携带测试截图以方便审核。非常感谢!
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
#### **uni-app插件市场链接** —— [https://ext.dcloud.net.cn/plugin?id=1593](https://ext.dcloud.net.cn/plugin?id=1593)
|
||||||
|
|
||||||
|
请通过[官网安装文档](https://www.uviewui.com/components/install.html)了解更详细的内容
|
||||||
|
|
||||||
|
## 快速上手
|
||||||
|
|
||||||
|
请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<template>
|
||||||
|
<u-button text="按钮"></u-button>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 版权信息
|
||||||
|
uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uView应用到您的产品中。
|
||||||
|
|
|
@ -0,0 +1,374 @@
|
||||||
|
## 2.0.37(2024-03-17)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复表单校验`trigger`触发器参数无效问题
|
||||||
|
2. 修复`u-input`组件的`password`属性在动态切换为`false`时失效的问题
|
||||||
|
3. 添加微信小程序用户同意隐私协议事件回调
|
||||||
|
4. 修复支付宝小程序picker样式问题
|
||||||
|
5. `u-modal`添加`duration`字段控制动画过度时间
|
||||||
|
6. 修复`picker` `lastIndex`异常导致的`column`异常问题
|
||||||
|
7. `tabs`增加长按事件支持
|
||||||
|
8. 修复`u-avatar` `square`属性在小程序`open-data`下无效问题
|
||||||
|
9. 其他一些修复
|
||||||
|
## 2.0.36(2023-03-27)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 重构`deepClone` & `deepMerge`方法
|
||||||
|
2. 其他优化
|
||||||
|
## 2.0.34(2022-09-24)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. `u-input`、`u-textarea`增加`ignoreCompositionEvent`属性
|
||||||
|
2. 修复`route`方法调用可能报错的问题
|
||||||
|
3. 修复`u-no-network`组件`z-index`无效的问题
|
||||||
|
4. 修复`textarea`组件在h5上confirmType=""报错的问题
|
||||||
|
5. `u-rate`适配`nvue`
|
||||||
|
6. 优化验证手机号码的正则表达式(根据工信部发布的《电信网编号计划(2017年版)》进行修改。)
|
||||||
|
7. `form-item`添加`labelPosition`属性
|
||||||
|
8. `u-calendar`修复`maxDate`设置为当前日期,并且当前时间大于08:00时无法显示日期列表的问题 (#724)
|
||||||
|
9. `u-radio`增加一个默认插槽用于自定义修改label内容 (#680)
|
||||||
|
10. 修复`timeFormat`函数在safari重的兼容性问题 (#664)
|
||||||
|
## 2.0.33(2022-06-17)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复`loadmore`组件`lineColor`类型错误问题
|
||||||
|
2. 修复`u-parse`组件`imgtap`、`linktap`不生效问题
|
||||||
|
## 2.0.32(2022-06-16)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
1. `u-loadmore`新增自定义颜色、虚/实线
|
||||||
|
2. 修复`u-swiper-action`组件部分平台不能上下滑动的问题
|
||||||
|
3. 修复`u-list`回弹问题
|
||||||
|
4. 修复`notice-bar`组件动画在低端安卓机可能会抖动的问题
|
||||||
|
5. `u-loading-page`添加控制图标大小的属性`iconSize`
|
||||||
|
6. 修复`u-tooltip`组件`color`参数不生效的问题
|
||||||
|
7. 修复`u--input`组件使用`blur`事件输出为`undefined`的bug
|
||||||
|
8. `u-code-input`组件新增键盘弹起时,是否自动上推页面参数`adjustPosition`
|
||||||
|
9. 修复`image`组件`load`事件无回调对象问题
|
||||||
|
10. 修复`button`组件`loadingSize`设置无效问题
|
||||||
|
10. 其他修复
|
||||||
|
## 2.0.31(2022-04-19)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复`upload`在`vue`页面上传成功后没有成功标志的问题
|
||||||
|
2. 解决演示项目中微信小程序模拟上传图片一直出于上传中问题
|
||||||
|
3. 修复`u-code-input`组件在`nvue`页面编译到`app`平台上光标异常问题(`app`去除此功能)
|
||||||
|
4. 修复`actionSheet`组件标题关闭按钮点击事件名称错误的问题
|
||||||
|
5. 其他修复
|
||||||
|
## 2.0.30(2022-04-04)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. `u-rate`增加`readonly`属性
|
||||||
|
2. `tabs`滑块支持设置背景图片
|
||||||
|
3. 修复`u-subsection` `mode`为`subsection`时,滑块样式不正确的问题
|
||||||
|
4. `u-code-input`添加光标效果动画
|
||||||
|
5. 修复`popup`的`open`事件不触发
|
||||||
|
6. 修复`u-flex-column`无效的问题
|
||||||
|
7. 修复`u-datetime-picker`索引在特定场合异常问题
|
||||||
|
8. 修复`u-datetime-picker`最小时间字符串模板错误问题
|
||||||
|
9. `u-swiper`添加`m3u8`验证
|
||||||
|
10. `u-swiper`修改判断image和video逻辑
|
||||||
|
11. 修复`swiper`无法使用本地图片问题,增加`type`参数
|
||||||
|
12. 修复`u-row-notice`格式错误问题
|
||||||
|
13. 修复`u-switch`组件当`unit`为`rpx`时,`nodeStyle`消失的问题
|
||||||
|
14. 修复`datetime-picker`组件`showToolbar`与`visibleItemCount`属性无效的问题
|
||||||
|
15. 修复`upload`组件条件编译位置判断错误,导致`previewImage`属性设置为`false`时,整个组件都会被隐藏的问题
|
||||||
|
16. 修复`u-checkbox-group`设置`shape`属性无效的问题
|
||||||
|
17. 修复`u-upload`的`capture`传入字符串的时候不生效的问题
|
||||||
|
18. 修复`u-action-sheet`组件,关闭事件逻辑错误的问题
|
||||||
|
19. 修复`u-list`触顶事件的触发错误的问题
|
||||||
|
20. 修复`u-text`只有手机号可拨打的问题
|
||||||
|
21. 修复`u-textarea`不能换行的问题
|
||||||
|
22. 其他修复
|
||||||
|
## 2.0.29(2022-03-13)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复`u--text`组件设置`decoration`属性未生效的问题
|
||||||
|
2. 修复`u-datetime-picker`使用`formatter`后返回值不正确
|
||||||
|
3. 修复`u-datetime-picker` `intercept` 可能为undefined
|
||||||
|
4. 修复已设置单位 uni..config.unit = 'rpx'时,线型指示器 `transform` 的位置翻倍,导致指示器超出宽度
|
||||||
|
5. 修复mixin中bem方法生成的类名在支付宝和字节小程序中失效
|
||||||
|
6. 修复默认值传值为空的时候,打开`u-datetime-picker`报错,不能选中第一列时间的bug
|
||||||
|
7. 修复`u-datetime-picker`使用`formatter`后返回值不正确
|
||||||
|
8. 修复`u-image`组件`loading`无效果的问题
|
||||||
|
9. 修复`config.unit`属性设为`rpx`时,导航栏占用高度不足导致塌陷的问题
|
||||||
|
10. 修复`u-datetime-picker`组件`itemHeight`无效问题
|
||||||
|
11. 其他修复
|
||||||
|
## 2.0.28(2022-02-22)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. search组件新增searchIconSize属性
|
||||||
|
2. 兼容Safari/Webkit中传入时间格式如2022-02-17 12:00:56
|
||||||
|
3. 修复text value.js 判断日期出format错误问题
|
||||||
|
4. priceFormat格式化金额出现精度错误
|
||||||
|
5. priceFormat在部分情况下出现精度损失问题
|
||||||
|
6. 优化表单rules提示
|
||||||
|
7. 修复avatar组件src为空时,展示状态不对
|
||||||
|
8. 其他修复
|
||||||
|
## 2.0.27(2022-01-28)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1.样式修复
|
||||||
|
## 2.0.26(2022-01-28)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1.样式修复
|
||||||
|
## 2.0.25(2022-01-27)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复text组件mode=price时,可能会导致精度错误的问题
|
||||||
|
2. 添加$u.setConfig()方法,可设置uView内置的config, props, zIndex, color属性,详见:[修改uView内置配置方案](https://uviewui.com/components/setting.html#%E9%BB%98%E8%AE%A4%E5%8D%95%E4%BD%8D%E9%85%8D%E7%BD%AE)
|
||||||
|
3. 优化form组件在errorType=toast时,如果输入错误页面会有抖动的问题
|
||||||
|
4. 修复$u.addUnit()对配置默认单位可能无效的问题
|
||||||
|
## 2.0.24(2022-01-25)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复swiper在current指定非0时缩放有误
|
||||||
|
2. 修复u-icon添加stop属性的时候报错
|
||||||
|
3. 优化遗留的通过正则判断rpx单位的问题
|
||||||
|
4. 优化Layout布局 vue使用gutter时,会超出固定区域
|
||||||
|
5. 优化search组件高度单位问题(rpx -> px)
|
||||||
|
6. 修复u-image slot 加载和错误的图片失去了高度
|
||||||
|
7. 修复u-index-list中footer插槽与header插槽存在性判断错误
|
||||||
|
8. 修复部分机型下u-popup关闭时会闪烁
|
||||||
|
9. 修复u-image在nvue-app下失去宽高
|
||||||
|
10. 修复u-popup运行报错
|
||||||
|
11. 修复u-tooltip报错
|
||||||
|
12. 修复box-sizing在app下的警告
|
||||||
|
13. 修复u-navbar在小程序中报运行时错误
|
||||||
|
14. 其他修复
|
||||||
|
## 2.0.23(2022-01-24)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复image组件在hx3.3.9的nvue下可能会显示异常的问题
|
||||||
|
2. 修复col组件gutter参数带rpx单位处理不正确的问题
|
||||||
|
3. 修复text组件单行时无法显示省略号的问题
|
||||||
|
4. navbar添加titleStyle参数
|
||||||
|
5. 升级到hx3.3.9可消除nvue下控制台样式警告的问题
|
||||||
|
## 2.0.22(2022-01-19)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. $u.page()方法优化,避免在特殊场景可能报错的问题
|
||||||
|
2. picker组件添加immediateChange参数
|
||||||
|
3. 新增$u.pages()方法
|
||||||
|
## 2.0.21(2022-01-19)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 优化:form组件在用户设置rules的时候提示用户model必传
|
||||||
|
2. 优化遗留的通过正则判断rpx单位的问题
|
||||||
|
3. 修复微信小程序环境中tabbar组件开启safeAreaInsetBottom属性后,placeholder高度填充不正确
|
||||||
|
4. 修复swiper在current指定非0时缩放有误
|
||||||
|
5. 修复u-icon添加stop属性的时候报错
|
||||||
|
6. 修复upload组件在accept=all的时候没有作用
|
||||||
|
7. 修复在text组件mode为phone时call属性无效的问题
|
||||||
|
8. 处理u-form clearValidate方法
|
||||||
|
9. 其他修复
|
||||||
|
## 2.0.20(2022-01-14)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复calendar默认会选择一个日期,如果直接点确定的话,无法取到值的问题
|
||||||
|
2. 修复Slider缺少disabled props 还有注释
|
||||||
|
3. 修复u-notice-bar点击事件无法拿到index索引值的问题
|
||||||
|
4. 修复u-collapse-item在vue文件下,app端自定义插槽不生效的问题
|
||||||
|
5. 优化头像为空时显示默认头像
|
||||||
|
6. 修复图片地址赋值后判断加载状态为完成问题
|
||||||
|
7. 修复日历滚动到默认日期月份区域
|
||||||
|
8. search组件暴露点击左边icon事件
|
||||||
|
9. 修复u-form clearValidate方法不生效
|
||||||
|
10. upload h5端增加返回文件参数(文件的name参数)
|
||||||
|
11. 处理upload选择文件后url为blob类型无法预览的问题
|
||||||
|
12. u-code-input 修复输入框没有往左移出一半屏幕
|
||||||
|
13. 修复Upload上传 disabled为true时,控制台报hoverClass类型错误
|
||||||
|
14. 临时处理ios app下grid点击坍塌问题
|
||||||
|
15. 其他修复
|
||||||
|
## 2.0.19(2021-12-29)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 优化微信小程序包体积可在微信中预览,请升级HbuilderX3.3.4,同时在“运行->运行到小程序模拟器”中勾选“运行时是否压缩代码”
|
||||||
|
2. 优化微信小程序setData性能,处理某些方法如$u.route()无法在模板中使用的问题
|
||||||
|
3. navbar添加autoBack参数
|
||||||
|
4. 允许avatar组件的事件冒泡
|
||||||
|
5. 修复cell组件报错问题
|
||||||
|
6. 其他修复
|
||||||
|
## 2.0.18(2021-12-28)
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复app端编译报错问题
|
||||||
|
2. 重新处理微信小程序端setData过大的性能问题
|
||||||
|
3. 修复边框问题
|
||||||
|
4. 修复最大最小月份不大于0则没有数据出现的问题
|
||||||
|
5. 修复SwipeAction微信小程序端无法上下滑动问题
|
||||||
|
6. 修复input的placeholder在小程序端默认显示为true问题
|
||||||
|
7. 修复divider组件click事件无效问题
|
||||||
|
8. 修复u-code-input maxlength 属性值为 String 类型时显示异常
|
||||||
|
9. 修复当 grid只有 1到2时 在小程序端algin设置无效的问题
|
||||||
|
10. 处理form-item的label为top时,取消错误提示的左边距
|
||||||
|
11. 其他修复
|
||||||
|
## 2.0.17(2021-12-26)
|
||||||
|
## uView正在参与开源中国的“年度最佳项目”评选,之前投过票的现在也可以投票,恳请同学们投一票,[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 解决HBuilderX3.3.3.20211225版本导致的样式问题
|
||||||
|
2. calendar日历添加monthNum参数
|
||||||
|
3. navbar添加center slot
|
||||||
|
## 2.0.16(2021-12-25)
|
||||||
|
## uView正在参与开源中国的“年度最佳项目”评选,之前投过票的现在也可以投票,恳请同学们投一票,[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 解决微信小程序setData性能问题
|
||||||
|
2. 修复count-down组件change事件不触发问题
|
||||||
|
## 2.0.15(2021-12-21)
|
||||||
|
## uView正在参与开源中国的“年度最佳项目”评选,之前投过票的现在也可以投票,恳请同学们投一票,[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复Cell单元格titleWidth无效
|
||||||
|
2. 修复cheakbox组件ischecked不更新
|
||||||
|
3. 修复keyboard是否显示"."按键默认值问题
|
||||||
|
4. 修复number-keyboard是否显示键盘的"."符号问题
|
||||||
|
5. 修复Input输入框 readonly无效
|
||||||
|
6. 修复u-avatar 导致打包app、H5时候报错问题
|
||||||
|
7. 修复Upload上传deletable无效
|
||||||
|
8. 修复upload当设置maxSize时无效的问题
|
||||||
|
9. 修复tabs lineWidth传入带单位的字符串的时候偏移量计算错误问题
|
||||||
|
10. 修复rate组件在有padding的view内,显示的星星位置和可触摸区域不匹配,无法正常选中星星
|
||||||
|
## 2.0.13(2021-12-14)
|
||||||
|
## [点击加群交流反馈:364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复配置默认单位为rpx可能会导致自定义导航栏高度异常的问题
|
||||||
|
## 2.0.12(2021-12-14)
|
||||||
|
## [点击加群交流反馈:364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复tabs组件在vue环境下划线消失的问题
|
||||||
|
2. 修复upload组件在安卓小程序无法选择视频的问题
|
||||||
|
3. 添加uni.$u.config.unit配置,用于配置参数默认单位,详见:[默认单位配置](https://www.uviewui.com/components/setting.html#%E9%BB%98%E8%AE%A4%E5%8D%95%E4%BD%8D%E9%85%8D%E7%BD%AE)
|
||||||
|
4. 修复textarea组件在没绑定v-model时,字符统计不生效问题
|
||||||
|
5. 修复nvue下控制是否出现滚动条失效问题
|
||||||
|
## 2.0.11(2021-12-13)
|
||||||
|
## [点击加群交流反馈:364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. text组件align参数无效的问题
|
||||||
|
2. subsection组件添加keyName参数
|
||||||
|
3. upload组件无法判断[Object file]类型的问题
|
||||||
|
4. 处理notify层级过低问题
|
||||||
|
5. codeInput组件添加disabledDot参数
|
||||||
|
6. 处理actionSheet组件round参数无效的问题
|
||||||
|
7. calendar组件添加round参数用于控制圆角值
|
||||||
|
8. 处理swipeAction组件在vue环境下默认被打开的问题
|
||||||
|
9. button组件的throttleTime节流参数无效的问题
|
||||||
|
10. 解决u-notify手动关闭方法close()无效的问题
|
||||||
|
11. input组件readonly不生效问题
|
||||||
|
12. tag组件type参数为info不生效问题
|
||||||
|
## 2.0.10(2021-12-08)
|
||||||
|
## [点击加群交流反馈:364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复button sendMessagePath属性不生效
|
||||||
|
2. 修复DatetimePicker选择器title无效
|
||||||
|
3. 修复u-toast设置loading=true不生效
|
||||||
|
4. 修复u-text金额模式传0报错
|
||||||
|
5. 修复u-toast组件的icon属性配置不生效
|
||||||
|
6. button的icon在特殊场景下的颜色优化
|
||||||
|
7. IndexList优化,增加#
|
||||||
|
## 2.0.9(2021-12-01)
|
||||||
|
## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 优化swiper的height支持100%值(仅vue有效),修复嵌入视频时click事件无法触发的问题
|
||||||
|
2. 优化tabs组件对list值为空的判断,或者动态变化list时重新计算相关尺寸的问题
|
||||||
|
3. 优化datetime-picker组件逻辑,让其后续打开的默认值为上一次的选中值,需要通过v-model绑定值才有效
|
||||||
|
4. 修复upload内嵌在其他组件中,选择图片可能不会换行的问题
|
||||||
|
## 2.0.8(2021-12-01)
|
||||||
|
## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复toast的position参数无效问题
|
||||||
|
2. 处理input在ios nvue上无法获得焦点的问题
|
||||||
|
3. avatar-group组件添加extraValue参数,让剩余展示数量可手动控制
|
||||||
|
4. tabs组件添加keyName参数用于配置从对象中读取的键名
|
||||||
|
5. 处理text组件名字脱敏默认配置无效的问题
|
||||||
|
6. 处理picker组件item文本太长换行问题
|
||||||
|
## 2.0.7(2021-11-30)
|
||||||
|
## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 修复radio和checkbox动态改变v-model无效的问题。
|
||||||
|
2. 优化form规则validator在微信小程序用法
|
||||||
|
3. 修复backtop组件mode参数在微信小程序无效的问题
|
||||||
|
4. 处理Album的previewFullImage属性无效的问题
|
||||||
|
5. 处理u-datetime-picker组件mode='time'在选择改变时间时,控制台报错的问题
|
||||||
|
## 2.0.6(2021-11-27)
|
||||||
|
## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. 处理tag组件在vue下边框无效的问题。
|
||||||
|
2. 处理popup组件圆角参数可能无效的问题。
|
||||||
|
3. 处理tabs组件lineColor参数可能无效的问题。
|
||||||
|
4. propgress组件在值很小时,显示异常的问题。
|
||||||
|
## 2.0.5(2021-11-25)
|
||||||
|
## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. calendar在vue下显示异常问题。
|
||||||
|
2. form组件labelPosition和errorType参数无效的问题
|
||||||
|
3. input组件inputAlign无效的问题
|
||||||
|
4. 其他一些修复
|
||||||
|
## 2.0.4(2021-11-23)
|
||||||
|
## [点击加群交流反馈:232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
0. input组件缺失@confirm事件,以及subfix和prefix无效问题
|
||||||
|
1. component.scss文件样式在vue下干扰全局布局问题
|
||||||
|
2. 修复subsection在vue环境下表现异常的问题
|
||||||
|
3. tag组件的bgColor等参数无效的问题
|
||||||
|
4. upload组件不换行的问题
|
||||||
|
5. 其他的一些修复处理
|
||||||
|
## 2.0.3(2021-11-16)
|
||||||
|
## [点击加群交流反馈:1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. uView2.0已实现全面兼容nvue
|
||||||
|
2. uView2.0对1.x进行了架构重构,细节和性能都有极大提升
|
||||||
|
3. 目前uView2.0为公测阶段,相关细节可能会有变动
|
||||||
|
4. 我们写了一份与1.x的对比指南,详见[对比1.x](https://www.uviewui.com/components/diff1.x.html)
|
||||||
|
5. 处理modal的confirm回调事件拼写错误问题
|
||||||
|
6. 处理input组件@input事件参数错误问题
|
||||||
|
7. 其他一些修复
|
||||||
|
## 2.0.2(2021-11-16)
|
||||||
|
## [点击加群交流反馈:1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. uView2.0已实现全面兼容nvue
|
||||||
|
2. uView2.0对1.x进行了架构重构,细节和性能都有极大提升
|
||||||
|
3. 目前uView2.0为公测阶段,相关细节可能会有变动
|
||||||
|
4. 我们写了一份与1.x的对比指南,详见[对比1.x](https://www.uviewui.com/components/diff1.x.html)
|
||||||
|
5. 修复input组件formatter参数缺失问题
|
||||||
|
6. 优化loading-icon组件的scss写法问题,防止不兼容新版本scss
|
||||||
|
## 2.0.0(2020-11-15)
|
||||||
|
## [点击加群交流反馈:1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
|
||||||
|
|
||||||
|
# uView2.0重磅发布,利剑出鞘,一统江湖
|
||||||
|
|
||||||
|
1. uView2.0已实现全面兼容nvue
|
||||||
|
2. uView2.0对1.x进行了架构重构,细节和性能都有极大提升
|
||||||
|
3. 目前uView2.0为公测阶段,相关细节可能会有变动
|
||||||
|
4. 我们写了一份与1.x的对比指南,详见[对比1.x](https://www.uviewui.com/components/diff1.x.html)
|
||||||
|
5. 修复input组件formatter参数缺失问题
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
<template>
|
||||||
|
<uvForm
|
||||||
|
ref="uForm"
|
||||||
|
:model="model"
|
||||||
|
:rules="rules"
|
||||||
|
:errorType="errorType"
|
||||||
|
:borderBottom="borderBottom"
|
||||||
|
:labelPosition="labelPosition"
|
||||||
|
:labelWidth="labelWidth"
|
||||||
|
:labelAlign="labelAlign"
|
||||||
|
:labelStyle="labelStyle"
|
||||||
|
:customStyle="customStyle"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</uvForm>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 此组件存在的理由是,在nvue下,u-form被uni-app官方占用了,u-form在nvue中相当于form组件
|
||||||
|
* 所以在nvue下,取名为u--form,内部其实还是u-form.vue,只不过做一层中转
|
||||||
|
*/
|
||||||
|
import uvForm from '../u-form/u-form.vue';
|
||||||
|
import props from '../u-form/props.js'
|
||||||
|
export default {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
name: 'u-form',
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
name: 'u--form',
|
||||||
|
// #endif
|
||||||
|
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
|
||||||
|
components: {
|
||||||
|
uvForm
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.children = []
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 手动设置校验的规则,如果规则中有函数的话,微信小程序中会过滤掉,所以只能手动调用设置规则
|
||||||
|
setRules(rules) {
|
||||||
|
this.$refs.uForm.setRules(rules)
|
||||||
|
},
|
||||||
|
validate() {
|
||||||
|
/**
|
||||||
|
* 在微信小程序中,通过this.$parent拿到的父组件是u--form,而不是其内嵌的u-form
|
||||||
|
* 导致在u-form组件中,拿不到对应的children数组,从而校验无效,所以这里每次调用u-form组件中的
|
||||||
|
* 对应方法的时候,在小程序中都先将u--form的children赋值给u-form中的children
|
||||||
|
*/
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
this.setMpData()
|
||||||
|
// #endif
|
||||||
|
return this.$refs.uForm.validate()
|
||||||
|
},
|
||||||
|
validateField(value, callback, event) {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
this.setMpData()
|
||||||
|
// #endif
|
||||||
|
return this.$refs.uForm.validateField(value, callback, event)
|
||||||
|
},
|
||||||
|
resetFields() {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
this.setMpData()
|
||||||
|
// #endif
|
||||||
|
return this.$refs.uForm.resetFields()
|
||||||
|
},
|
||||||
|
clearValidate(props) {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
this.setMpData()
|
||||||
|
// #endif
|
||||||
|
return this.$refs.uForm.clearValidate(props)
|
||||||
|
},
|
||||||
|
setMpData() {
|
||||||
|
this.$refs.uForm.children = this.children
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,47 @@
|
||||||
|
<template>
|
||||||
|
<uvImage
|
||||||
|
:src="src"
|
||||||
|
:mode="mode"
|
||||||
|
:width="width"
|
||||||
|
:height="height"
|
||||||
|
:shape="shape"
|
||||||
|
:radius="radius"
|
||||||
|
:lazyLoad="lazyLoad"
|
||||||
|
:showMenuByLongpress="showMenuByLongpress"
|
||||||
|
:loadingIcon="loadingIcon"
|
||||||
|
:errorIcon="errorIcon"
|
||||||
|
:showLoading="showLoading"
|
||||||
|
:showError="showError"
|
||||||
|
:fade="fade"
|
||||||
|
:webp="webp"
|
||||||
|
:duration="duration"
|
||||||
|
:bgColor="bgColor"
|
||||||
|
:customStyle="customStyle"
|
||||||
|
@click="$emit('click')"
|
||||||
|
@error="$emit('error')"
|
||||||
|
@load="$emit('load')"
|
||||||
|
>
|
||||||
|
<template v-slot:loading>
|
||||||
|
<slot name="loading"></slot>
|
||||||
|
</template>
|
||||||
|
<template v-slot:error>
|
||||||
|
<slot name="error"></slot>
|
||||||
|
</template>
|
||||||
|
</uvImage>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 此组件存在的理由是,在nvue下,u-image被uni-app官方占用了,u-image在nvue中相当于image组件
|
||||||
|
* 所以在nvue下,取名为u--image,内部其实还是u-iamge.vue,只不过做一层中转
|
||||||
|
*/
|
||||||
|
import uvImage from '../u-image/u-image.vue';
|
||||||
|
import props from '../u-image/props.js';
|
||||||
|
export default {
|
||||||
|
name: 'u--image',
|
||||||
|
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
|
||||||
|
components: {
|
||||||
|
uvImage
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,73 @@
|
||||||
|
<template>
|
||||||
|
<uvInput
|
||||||
|
:value="value"
|
||||||
|
:type="type"
|
||||||
|
:fixed="fixed"
|
||||||
|
:disabled="disabled"
|
||||||
|
:disabledColor="disabledColor"
|
||||||
|
:clearable="clearable"
|
||||||
|
:password="password"
|
||||||
|
:maxlength="maxlength"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:placeholderClass="placeholderClass"
|
||||||
|
:placeholderStyle="placeholderStyle"
|
||||||
|
:showWordLimit="showWordLimit"
|
||||||
|
:confirmType="confirmType"
|
||||||
|
:confirmHold="confirmHold"
|
||||||
|
:holdKeyboard="holdKeyboard"
|
||||||
|
:focus="focus"
|
||||||
|
:autoBlur="autoBlur"
|
||||||
|
:disableDefaultPadding="disableDefaultPadding"
|
||||||
|
:cursor="cursor"
|
||||||
|
:cursorSpacing="cursorSpacing"
|
||||||
|
:selectionStart="selectionStart"
|
||||||
|
:selectionEnd="selectionEnd"
|
||||||
|
:adjustPosition="adjustPosition"
|
||||||
|
:inputAlign="inputAlign"
|
||||||
|
:fontSize="fontSize"
|
||||||
|
:color="color"
|
||||||
|
:prefixIcon="prefixIcon"
|
||||||
|
:suffixIcon="suffixIcon"
|
||||||
|
:suffixIconStyle="suffixIconStyle"
|
||||||
|
:prefixIconStyle="prefixIconStyle"
|
||||||
|
:border="border"
|
||||||
|
:readonly="readonly"
|
||||||
|
:shape="shape"
|
||||||
|
:customStyle="customStyle"
|
||||||
|
:formatter="formatter"
|
||||||
|
:ignoreCompositionEvent="ignoreCompositionEvent"
|
||||||
|
@focus="$emit('focus')"
|
||||||
|
@blur="e => $emit('blur', e)"
|
||||||
|
@keyboardheightchange="$emit('keyboardheightchange')"
|
||||||
|
@change="e => $emit('change', e)"
|
||||||
|
@input="e => $emit('input', e)"
|
||||||
|
@confirm="e => $emit('confirm', e)"
|
||||||
|
@clear="$emit('clear')"
|
||||||
|
@click="$emit('click')"
|
||||||
|
>
|
||||||
|
<!-- #ifdef MP -->
|
||||||
|
<slot name="prefix"></slot>
|
||||||
|
<slot name="suffix"></slot>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef MP -->
|
||||||
|
<slot name="prefix" slot="prefix"></slot>
|
||||||
|
<slot name="suffix" slot="suffix"></slot>
|
||||||
|
<!-- #endif -->
|
||||||
|
</uvInput>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 此组件存在的理由是,在nvue下,u-input被uni-app官方占用了,u-input在nvue中相当于input组件
|
||||||
|
* 所以在nvue下,取名为u--input,内部其实还是u-input.vue,只不过做一层中转
|
||||||
|
*/
|
||||||
|
import uvInput from '../u-input/u-input.vue';
|
||||||
|
import props from '../u-input/props.js'
|
||||||
|
export default {
|
||||||
|
name: 'u--input',
|
||||||
|
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
|
||||||
|
components: {
|
||||||
|
uvInput
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,44 @@
|
||||||
|
<template>
|
||||||
|
<uvText
|
||||||
|
:type="type"
|
||||||
|
:show="show"
|
||||||
|
:text="text"
|
||||||
|
:prefixIcon="prefixIcon"
|
||||||
|
:suffixIcon="suffixIcon"
|
||||||
|
:mode="mode"
|
||||||
|
:href="href"
|
||||||
|
:format="format"
|
||||||
|
:call="call"
|
||||||
|
:openType="openType"
|
||||||
|
:bold="bold"
|
||||||
|
:block="block"
|
||||||
|
:lines="lines"
|
||||||
|
:color="color"
|
||||||
|
:decoration="decoration"
|
||||||
|
:size="size"
|
||||||
|
:iconStyle="iconStyle"
|
||||||
|
:margin="margin"
|
||||||
|
:lineHeight="lineHeight"
|
||||||
|
:align="align"
|
||||||
|
:wordWrap="wordWrap"
|
||||||
|
:customStyle="customStyle"
|
||||||
|
@click="$emit('click')"
|
||||||
|
></uvText>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 此组件存在的理由是,在nvue下,u-text被uni-app官方占用了,u-text在nvue中相当于input组件
|
||||||
|
* 所以在nvue下,取名为u--input,内部其实还是u-text.vue,只不过做一层中转
|
||||||
|
* 不使用v-bind="$attrs",而是分开独立写传参,是因为微信小程序不支持此写法
|
||||||
|
*/
|
||||||
|
import uvText from "../u-text/u-text.vue";
|
||||||
|
import props from "../u-text/props.js";
|
||||||
|
export default {
|
||||||
|
name: "u--text",
|
||||||
|
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
|
||||||
|
components: {
|
||||||
|
uvText,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,48 @@
|
||||||
|
<template>
|
||||||
|
<uvTextarea
|
||||||
|
:value="value"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:height="height"
|
||||||
|
:confirmType="confirmType"
|
||||||
|
:disabled="disabled"
|
||||||
|
:count="count"
|
||||||
|
:focus="focus"
|
||||||
|
:autoHeight="autoHeight"
|
||||||
|
:fixed="fixed"
|
||||||
|
:cursorSpacing="cursorSpacing"
|
||||||
|
:cursor="cursor"
|
||||||
|
:showConfirmBar="showConfirmBar"
|
||||||
|
:selectionStart="selectionStart"
|
||||||
|
:selectionEnd="selectionEnd"
|
||||||
|
:adjustPosition="adjustPosition"
|
||||||
|
:disableDefaultPadding="disableDefaultPadding"
|
||||||
|
:holdKeyboard="holdKeyboard"
|
||||||
|
:maxlength="maxlength"
|
||||||
|
:border="border"
|
||||||
|
:customStyle="customStyle"
|
||||||
|
:formatter="formatter"
|
||||||
|
:ignoreCompositionEvent="ignoreCompositionEvent"
|
||||||
|
@focus="e => $emit('focus')"
|
||||||
|
@blur="e => $emit('blur')"
|
||||||
|
@linechange="e => $emit('linechange', e)"
|
||||||
|
@confirm="e => $emit('confirm')"
|
||||||
|
@input="e => $emit('input', e)"
|
||||||
|
@keyboardheightchange="e => $emit('keyboardheightchange')"
|
||||||
|
></uvTextarea>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* 此组件存在的理由是,在nvue下,u--textarea被uni-app官方占用了,u-textarea在nvue中相当于textarea组件
|
||||||
|
* 所以在nvue下,取名为u--textarea,内部其实还是u-textarea.vue,只不过做一层中转
|
||||||
|
*/
|
||||||
|
import uvTextarea from '../u-textarea/u-textarea.vue';
|
||||||
|
import props from '../u-textarea/props.js'
|
||||||
|
export default {
|
||||||
|
name: 'u--textarea',
|
||||||
|
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
|
||||||
|
components: {
|
||||||
|
uvTextarea
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,54 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 操作菜单是否展示 (默认false)
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.actionSheet.show
|
||||||
|
},
|
||||||
|
// 标题
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.actionSheet.title
|
||||||
|
},
|
||||||
|
// 选项上方的描述信息
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.actionSheet.description
|
||||||
|
},
|
||||||
|
// 数据
|
||||||
|
actions: {
|
||||||
|
type: Array,
|
||||||
|
default: uni.$u.props.actionSheet.actions
|
||||||
|
},
|
||||||
|
// 取消按钮的文字,不为空时显示按钮
|
||||||
|
cancelText: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.actionSheet.cancelText
|
||||||
|
},
|
||||||
|
// 点击某个菜单项时是否关闭弹窗
|
||||||
|
closeOnClickAction: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.actionSheet.closeOnClickAction
|
||||||
|
},
|
||||||
|
// 处理底部安全区(默认true)
|
||||||
|
safeAreaInsetBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.actionSheet.safeAreaInsetBottom
|
||||||
|
},
|
||||||
|
// 小程序的打开方式
|
||||||
|
openType: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.actionSheet.openType
|
||||||
|
},
|
||||||
|
// 点击遮罩是否允许关闭 (默认true)
|
||||||
|
closeOnClickOverlay: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.actionSheet.closeOnClickOverlay
|
||||||
|
},
|
||||||
|
// 圆角值
|
||||||
|
round: {
|
||||||
|
type: [Boolean, String, Number],
|
||||||
|
default: uni.$u.props.actionSheet.round
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,278 @@
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<u-popup
|
||||||
|
:show="show"
|
||||||
|
mode="bottom"
|
||||||
|
@close="closeHandler"
|
||||||
|
:safeAreaInsetBottom="safeAreaInsetBottom"
|
||||||
|
:round="round"
|
||||||
|
>
|
||||||
|
<view class="u-action-sheet">
|
||||||
|
<view
|
||||||
|
class="u-action-sheet__header"
|
||||||
|
v-if="title"
|
||||||
|
>
|
||||||
|
<text class="u-action-sheet__header__title u-line-1">{{title}}</text>
|
||||||
|
<view
|
||||||
|
class="u-action-sheet__header__icon-wrap"
|
||||||
|
@tap.stop="cancel"
|
||||||
|
>
|
||||||
|
<u-icon
|
||||||
|
name="close"
|
||||||
|
size="17"
|
||||||
|
color="#c8c9cc"
|
||||||
|
bold
|
||||||
|
></u-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<text
|
||||||
|
class="u-action-sheet__description"
|
||||||
|
:style="[{
|
||||||
|
marginTop: `${title && description ? 0 : '18px'}`
|
||||||
|
}]"
|
||||||
|
v-if="description"
|
||||||
|
>{{description}}</text>
|
||||||
|
<slot>
|
||||||
|
<u-line v-if="description"></u-line>
|
||||||
|
<view class="u-action-sheet__item-wrap">
|
||||||
|
<template v-for="(item, index) in actions">
|
||||||
|
<!-- #ifdef MP -->
|
||||||
|
<button
|
||||||
|
:key="index"
|
||||||
|
class="u-reset-button"
|
||||||
|
:openType="item.openType"
|
||||||
|
@getuserinfo="onGetUserInfo"
|
||||||
|
@contact="onContact"
|
||||||
|
@getphonenumber="onGetPhoneNumber"
|
||||||
|
@error="onError"
|
||||||
|
@launchapp="onLaunchApp"
|
||||||
|
@opensetting="onOpenSetting"
|
||||||
|
:lang="lang"
|
||||||
|
:session-from="sessionFrom"
|
||||||
|
:send-message-title="sendMessageTitle"
|
||||||
|
:send-message-path="sendMessagePath"
|
||||||
|
:send-message-img="sendMessageImg"
|
||||||
|
:show-message-card="showMessageCard"
|
||||||
|
:app-parameter="appParameter"
|
||||||
|
@tap="selectHandler(index)"
|
||||||
|
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
|
||||||
|
>
|
||||||
|
<!-- #endif -->
|
||||||
|
<view
|
||||||
|
class="u-action-sheet__item-wrap__item"
|
||||||
|
@tap.stop="selectHandler(index)"
|
||||||
|
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
|
||||||
|
:hover-stay-time="150"
|
||||||
|
>
|
||||||
|
<template v-if="!item.loading">
|
||||||
|
<text
|
||||||
|
class="u-action-sheet__item-wrap__item__name"
|
||||||
|
:style="[itemStyle(index)]"
|
||||||
|
>{{ item.name }}</text>
|
||||||
|
<text
|
||||||
|
v-if="item.subname"
|
||||||
|
class="u-action-sheet__item-wrap__item__subname"
|
||||||
|
>{{ item.subname }}</text>
|
||||||
|
</template>
|
||||||
|
<u-loading-icon
|
||||||
|
v-else
|
||||||
|
custom-class="van-action-sheet__loading"
|
||||||
|
size="18"
|
||||||
|
mode="circle"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
<!-- #ifdef MP -->
|
||||||
|
</button>
|
||||||
|
<!-- #endif -->
|
||||||
|
<u-line v-if="index !== actions.length - 1"></u-line>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
</slot>
|
||||||
|
<u-gap
|
||||||
|
bgColor="#eaeaec"
|
||||||
|
height="6"
|
||||||
|
v-if="cancelText"
|
||||||
|
></u-gap>
|
||||||
|
<view hover-class="u-action-sheet--hover">
|
||||||
|
<text
|
||||||
|
@touchmove.stop.prevent
|
||||||
|
:hover-stay-time="150"
|
||||||
|
v-if="cancelText"
|
||||||
|
class="u-action-sheet__cancel-text"
|
||||||
|
@tap="cancel"
|
||||||
|
>{{cancelText}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import openType from '../../libs/mixin/openType'
|
||||||
|
import button from '../../libs/mixin/button'
|
||||||
|
import props from './props.js';
|
||||||
|
/**
|
||||||
|
* ActionSheet 操作菜单
|
||||||
|
* @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
|
||||||
|
* @tutorial https://www.uviewui.com/components/actionSheet.html
|
||||||
|
*
|
||||||
|
* @property {Boolean} show 操作菜单是否展示 (默认 false )
|
||||||
|
* @property {String} title 操作菜单标题
|
||||||
|
* @property {String} description 选项上方的描述信息
|
||||||
|
* @property {Array<Object>} actions 按钮的文字数组,见官方文档示例
|
||||||
|
* @property {String} cancelText 取消按钮的提示文字,不为空时显示按钮
|
||||||
|
* @property {Boolean} closeOnClickAction 点击某个菜单项时是否关闭弹窗 (默认 true )
|
||||||
|
* @property {Boolean} safeAreaInsetBottom 处理底部安全区 (默认 true )
|
||||||
|
* @property {String} openType 小程序的打开方式 (contact | launchApp | getUserInfo | openSetting |getPhoneNumber |error )
|
||||||
|
* @property {Boolean} closeOnClickOverlay 点击遮罩是否允许关闭 (默认 true )
|
||||||
|
* @property {Number|String} round 圆角值,默认无圆角 (默认 0 )
|
||||||
|
* @property {String} lang 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文
|
||||||
|
* @property {String} sessionFrom 会话来源,openType="contact"时有效
|
||||||
|
* @property {String} sendMessageTitle 会话内消息卡片标题,openType="contact"时有效
|
||||||
|
* @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径,openType="contact"时有效
|
||||||
|
* @property {String} sendMessageImg 会话内消息卡片图片,openType="contact"时有效
|
||||||
|
* @property {Boolean} showMessageCard 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效 (默认 false )
|
||||||
|
* @property {String} appParameter 打开 APP 时,向 APP 传递的参数,openType=launchApp 时有效
|
||||||
|
*
|
||||||
|
* @event {Function} select 点击ActionSheet列表项时触发
|
||||||
|
* @event {Function} close 点击取消按钮时触发
|
||||||
|
* @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,回调的 detail 数据与 wx.getUserInfo 返回的一致,openType="getUserInfo"时有效
|
||||||
|
* @event {Function} contact 客服消息回调,openType="contact"时有效
|
||||||
|
* @event {Function} getphonenumber 获取用户手机号回调,openType="getPhoneNumber"时有效
|
||||||
|
* @event {Function} error 当使用开放能力时,发生错误的回调,openType="error"时有效
|
||||||
|
* @event {Function} launchapp 打开 APP 成功的回调,openType="launchApp"时有效
|
||||||
|
* @event {Function} opensetting 在打开授权设置页后回调,openType="openSetting"时有效
|
||||||
|
* @example <u-action-sheet :actions="list" :title="title" :show="show"></u-action-sheet>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-action-sheet",
|
||||||
|
// 一些props参数和methods方法,通过mixin混入,因为其他文件也会用到
|
||||||
|
mixins: [openType, button, uni.$u.mixin, props],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 操作项目的样式
|
||||||
|
itemStyle() {
|
||||||
|
return (index) => {
|
||||||
|
let style = {};
|
||||||
|
if (this.actions[index].color) style.color = this.actions[index].color
|
||||||
|
if (this.actions[index].fontSize) style.fontSize = uni.$u.addUnit(this.actions[index].fontSize)
|
||||||
|
// 选项被禁用的样式
|
||||||
|
if (this.actions[index].disabled) style.color = '#c0c4cc'
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
closeHandler() {
|
||||||
|
// 允许点击遮罩关闭时,才发出close事件
|
||||||
|
if(this.closeOnClickOverlay) {
|
||||||
|
this.$emit('close')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 点击取消按钮
|
||||||
|
cancel() {
|
||||||
|
this.$emit('close')
|
||||||
|
},
|
||||||
|
selectHandler(index) {
|
||||||
|
const item = this.actions[index]
|
||||||
|
if (item && !item.disabled && !item.loading) {
|
||||||
|
this.$emit('select', item)
|
||||||
|
if (this.closeOnClickAction) {
|
||||||
|
this.$emit('close')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
$u-action-sheet-reset-button-width:100% !default;
|
||||||
|
$u-action-sheet-title-font-size: 16px !default;
|
||||||
|
$u-action-sheet-title-padding: 12px 30px !default;
|
||||||
|
$u-action-sheet-title-color: $u-main-color !default;
|
||||||
|
$u-action-sheet-header-icon-wrap-right:15px !default;
|
||||||
|
$u-action-sheet-header-icon-wrap-top:15px !default;
|
||||||
|
$u-action-sheet-description-font-size:13px !default;
|
||||||
|
$u-action-sheet-description-color:14px !default;
|
||||||
|
$u-action-sheet-description-margin: 18px 15px !default;
|
||||||
|
$u-action-sheet-item-wrap-item-padding:15px !default;
|
||||||
|
$u-action-sheet-item-wrap-name-font-size:16px !default;
|
||||||
|
$u-action-sheet-item-wrap-subname-font-size:13px !default;
|
||||||
|
$u-action-sheet-item-wrap-subname-color: #c0c4cc !default;
|
||||||
|
$u-action-sheet-item-wrap-subname-margin-top:10px !default;
|
||||||
|
$u-action-sheet-cancel-text-font-size:16px !default;
|
||||||
|
$u-action-sheet-cancel-text-color:$u-content-color !default;
|
||||||
|
$u-action-sheet-cancel-text-font-size:15px !default;
|
||||||
|
$u-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default;
|
||||||
|
|
||||||
|
.u-reset-button {
|
||||||
|
width: $u-action-sheet-reset-button-width;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-action-sheet {
|
||||||
|
text-align: center;
|
||||||
|
&__header {
|
||||||
|
position: relative;
|
||||||
|
padding: $u-action-sheet-title-padding;
|
||||||
|
&__title {
|
||||||
|
font-size: $u-action-sheet-title-font-size;
|
||||||
|
color: $u-action-sheet-title-color;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon-wrap {
|
||||||
|
position: absolute;
|
||||||
|
right: $u-action-sheet-header-icon-wrap-right;
|
||||||
|
top: $u-action-sheet-header-icon-wrap-top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__description {
|
||||||
|
font-size: $u-action-sheet-description-font-size;
|
||||||
|
color: $u-tips-color;
|
||||||
|
margin: $u-action-sheet-description-margin;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item-wrap {
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
padding: $u-action-sheet-item-wrap-item-padding;
|
||||||
|
@include flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
font-size: $u-action-sheet-item-wrap-name-font-size;
|
||||||
|
color: $u-main-color;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subname {
|
||||||
|
font-size: $u-action-sheet-item-wrap-subname-font-size;
|
||||||
|
color: $u-action-sheet-item-wrap-subname-color;
|
||||||
|
margin-top: $u-action-sheet-item-wrap-subname-margin-top;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__cancel-text {
|
||||||
|
font-size: $u-action-sheet-cancel-text-font-size;
|
||||||
|
color: $u-action-sheet-cancel-text-color;
|
||||||
|
text-align: center;
|
||||||
|
padding: $u-action-sheet-cancel-text-font-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--hover {
|
||||||
|
background-color: $u-action-sheet-cancel-text-hover-background-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,59 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 图片地址,Array<String>|Array<Object>形式
|
||||||
|
urls: {
|
||||||
|
type: Array,
|
||||||
|
default: uni.$u.props.album.urls
|
||||||
|
},
|
||||||
|
// 指定从数组的对象元素中读取哪个属性作为图片地址
|
||||||
|
keyName: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.album.keyName
|
||||||
|
},
|
||||||
|
// 单图时,图片长边的长度
|
||||||
|
singleSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.album.singleSize
|
||||||
|
},
|
||||||
|
// 多图时,图片边长
|
||||||
|
multipleSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.album.multipleSize
|
||||||
|
},
|
||||||
|
// 多图时,图片水平和垂直之间的间隔
|
||||||
|
space: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.album.space
|
||||||
|
},
|
||||||
|
// 单图时,图片缩放裁剪的模式
|
||||||
|
singleMode: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.album.singleMode
|
||||||
|
},
|
||||||
|
// 多图时,图片缩放裁剪的模式
|
||||||
|
multipleMode: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.album.multipleMode
|
||||||
|
},
|
||||||
|
// 最多展示的图片数量,超出时最后一个位置将会显示剩余图片数量
|
||||||
|
maxCount: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.album.maxCount
|
||||||
|
},
|
||||||
|
// 是否可以预览图片
|
||||||
|
previewFullImage: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.album.previewFullImage
|
||||||
|
},
|
||||||
|
// 每行展示图片数量,如设置,singleSize和multipleSize将会无效
|
||||||
|
rowCount: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.album.rowCount
|
||||||
|
},
|
||||||
|
// 超出maxCount时是否显示查看更多的提示
|
||||||
|
showMore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.album.showMore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,259 @@
|
||||||
|
<template>
|
||||||
|
<view class="u-album">
|
||||||
|
<view
|
||||||
|
class="u-album__row"
|
||||||
|
ref="u-album__row"
|
||||||
|
v-for="(arr, index) in showUrls"
|
||||||
|
:forComputedUse="albumWidth"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="u-album__row__wrapper"
|
||||||
|
v-for="(item, index1) in arr"
|
||||||
|
:key="index1"
|
||||||
|
:style="[imageStyle(index + 1, index1 + 1)]"
|
||||||
|
@tap="previewFullImage ? onPreviewTap(getSrc(item)) : ''"
|
||||||
|
>
|
||||||
|
<image
|
||||||
|
:src="getSrc(item)"
|
||||||
|
:mode="
|
||||||
|
urls.length === 1
|
||||||
|
? imageHeight > 0
|
||||||
|
? singleMode
|
||||||
|
: 'widthFix'
|
||||||
|
: multipleMode
|
||||||
|
"
|
||||||
|
:style="[
|
||||||
|
{
|
||||||
|
width: imageWidth,
|
||||||
|
height: imageHeight
|
||||||
|
}
|
||||||
|
]"
|
||||||
|
></image>
|
||||||
|
<view
|
||||||
|
v-if="
|
||||||
|
showMore &&
|
||||||
|
urls.length > rowCount * showUrls.length &&
|
||||||
|
index === showUrls.length - 1 &&
|
||||||
|
index1 === showUrls[showUrls.length - 1].length - 1
|
||||||
|
"
|
||||||
|
class="u-album__row__wrapper__text"
|
||||||
|
>
|
||||||
|
<u--text
|
||||||
|
:text="`+${urls.length - maxCount}`"
|
||||||
|
color="#fff"
|
||||||
|
:size="multipleSize * 0.3"
|
||||||
|
align="center"
|
||||||
|
customStyle="justify-content: center"
|
||||||
|
></u--text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js'
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
// 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度
|
||||||
|
const dom = uni.requireNativePlugin('dom')
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Album 相册
|
||||||
|
* @description 本组件提供一个类似相册的功能,让开发者开发起来更加得心应手。减少重复的模板代码
|
||||||
|
* @tutorial https://www.uviewui.com/components/album.html
|
||||||
|
*
|
||||||
|
* @property {Array} urls 图片地址列表 Array<String>|Array<Object>形式
|
||||||
|
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
|
||||||
|
* @property {String | Number} singleSize 单图时,图片长边的长度 (默认 180 )
|
||||||
|
* @property {String | Number} multipleSize 多图时,图片边长 (默认 70 )
|
||||||
|
* @property {String | Number} space 多图时,图片水平和垂直之间的间隔 (默认 6 )
|
||||||
|
* @property {String} singleMode 单图时,图片缩放裁剪的模式 (默认 'scaleToFill' )
|
||||||
|
* @property {String} multipleMode 多图时,图片缩放裁剪的模式 (默认 'aspectFill' )
|
||||||
|
* @property {String | Number} maxCount 取消按钮的提示文字 (默认 9 )
|
||||||
|
* @property {Boolean} previewFullImage 是否可以预览图片 (默认 true )
|
||||||
|
* @property {String | Number} rowCount 每行展示图片数量,如设置,singleSize和multipleSize将会无效 (默认 3 )
|
||||||
|
* @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 (默认 true )
|
||||||
|
*
|
||||||
|
* @event {Function} albumWidth 某些特殊的情况下,需要让文字与相册的宽度相等,这里事件的形式对外发送 (回调参数 width )
|
||||||
|
* @example <u-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></u-album>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-album',
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 单图的宽度
|
||||||
|
singleWidth: 0,
|
||||||
|
// 单图的高度
|
||||||
|
singleHeight: 0,
|
||||||
|
// 单图时,如果无法获取图片的尺寸信息,让图片宽度默认为容器的一定百分比
|
||||||
|
singlePercent: 0.6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
urls: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newVal) {
|
||||||
|
if (newVal.length === 1) {
|
||||||
|
this.getImageRect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
imageStyle() {
|
||||||
|
return (index1, index2) => {
|
||||||
|
const { space, rowCount, multipleSize, urls } = this,
|
||||||
|
{ addUnit, addStyle } = uni.$u,
|
||||||
|
rowLen = this.showUrls.length,
|
||||||
|
allLen = this.urls.length
|
||||||
|
const style = {
|
||||||
|
marginRight: addUnit(space),
|
||||||
|
marginBottom: addUnit(space)
|
||||||
|
}
|
||||||
|
// 如果为最后一行,则每个图片都无需下边框
|
||||||
|
if (index1 === rowLen) style.marginBottom = 0
|
||||||
|
// 每行的最右边一张和总长度的最后一张无需右边框
|
||||||
|
if (
|
||||||
|
index2 === rowCount ||
|
||||||
|
(index1 === rowLen &&
|
||||||
|
index2 === this.showUrls[index1 - 1].length)
|
||||||
|
)
|
||||||
|
style.marginRight = 0
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 将数组划分为二维数组
|
||||||
|
showUrls() {
|
||||||
|
const arr = []
|
||||||
|
this.urls.map((item, index) => {
|
||||||
|
// 限制最大展示数量
|
||||||
|
if (index + 1 <= this.maxCount) {
|
||||||
|
// 计算该元素为第几个素组内
|
||||||
|
const itemIndex = Math.floor(index / this.rowCount)
|
||||||
|
// 判断对应的索引是否存在
|
||||||
|
if (!arr[itemIndex]) {
|
||||||
|
arr[itemIndex] = []
|
||||||
|
}
|
||||||
|
arr[itemIndex].push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return arr
|
||||||
|
},
|
||||||
|
imageWidth() {
|
||||||
|
return uni.$u.addUnit(
|
||||||
|
this.urls.length === 1 ? this.singleWidth : this.multipleSize
|
||||||
|
)
|
||||||
|
},
|
||||||
|
imageHeight() {
|
||||||
|
return uni.$u.addUnit(
|
||||||
|
this.urls.length === 1 ? this.singleHeight : this.multipleSize
|
||||||
|
)
|
||||||
|
},
|
||||||
|
// 此变量无实际用途,仅仅是为了利用computed特性,让其在urls长度等变化时,重新计算图片的宽度
|
||||||
|
// 因为用户在某些特殊的情况下,需要让文字与相册的宽度相等,所以这里事件的形式对外发送
|
||||||
|
albumWidth() {
|
||||||
|
let width = 0
|
||||||
|
if (this.urls.length === 1) {
|
||||||
|
width = this.singleWidth
|
||||||
|
} else {
|
||||||
|
width =
|
||||||
|
this.showUrls[0].length * this.multipleSize +
|
||||||
|
this.space * (this.showUrls[0].length - 1)
|
||||||
|
}
|
||||||
|
this.$emit('albumWidth', width)
|
||||||
|
return width
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 预览图片
|
||||||
|
onPreviewTap(url) {
|
||||||
|
const urls = this.urls.map((item) => {
|
||||||
|
return this.getSrc(item)
|
||||||
|
})
|
||||||
|
uni.previewImage({
|
||||||
|
current: url,
|
||||||
|
urls
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取图片的路径
|
||||||
|
getSrc(item) {
|
||||||
|
return uni.$u.test.object(item)
|
||||||
|
? (this.keyName && item[this.keyName]) || item.src
|
||||||
|
: item
|
||||||
|
},
|
||||||
|
// 单图时,获取图片的尺寸
|
||||||
|
// 在小程序中,需要将网络图片的的域名添加到小程序的download域名才可能获取尺寸
|
||||||
|
// 在没有添加的情况下,让单图宽度默认为盒子的一定宽度(singlePercent)
|
||||||
|
getImageRect() {
|
||||||
|
const src = this.getSrc(this.urls[0])
|
||||||
|
uni.getImageInfo({
|
||||||
|
src,
|
||||||
|
success: (res) => {
|
||||||
|
// 判断图片横向还是竖向展示方式
|
||||||
|
const isHorizotal = res.width >= res.height
|
||||||
|
this.singleWidth = isHorizotal
|
||||||
|
? this.singleSize
|
||||||
|
: (res.width / res.height) * this.singleSize
|
||||||
|
this.singleHeight = !isHorizotal
|
||||||
|
? this.singleSize
|
||||||
|
: (res.height / res.width) * this.singleWidth
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
this.getComponentWidth()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取组件的宽度
|
||||||
|
async getComponentWidth() {
|
||||||
|
// 延时一定时间,以获取dom尺寸
|
||||||
|
await uni.$u.sleep(30)
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
this.$uGetRect('.u-album__row').then((size) => {
|
||||||
|
this.singleWidth = size.width * this.singlePercent
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
// 这里ref="u-album__row"所在的标签为通过for循环出来,导致this.$refs['u-album__row']是一个数组
|
||||||
|
const ref = this.$refs['u-album__row'][0]
|
||||||
|
ref &&
|
||||||
|
dom.getComponentRect(ref, (res) => {
|
||||||
|
this.singleWidth = res.size.width * this.singlePercent
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../libs/css/components.scss';
|
||||||
|
|
||||||
|
.u-album {
|
||||||
|
@include flex(column);
|
||||||
|
|
||||||
|
&__row {
|
||||||
|
@include flex(row);
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
&__wrapper {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
@include flex(row);
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,256 @@
|
||||||
|
<template>
|
||||||
|
<view class="u-alert-tips" v-if="show" :class="[
|
||||||
|
!show ? 'u-close-alert-tips': '',
|
||||||
|
type ? 'u-alert-tips--bg--' + type + '-light' : '',
|
||||||
|
type ? 'u-alert-tips--border--' + type + '-disabled' : '',
|
||||||
|
]" :style="{
|
||||||
|
backgroundColor: bgColor,
|
||||||
|
borderColor: borderColor
|
||||||
|
}">
|
||||||
|
<view class="u-icon-wrap">
|
||||||
|
<u-icon v-if="showIcon" :name="uIcon" :size="description ? 40 : 32" class="u-icon" :color="uIconType" :custom-style="iconStyle"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="u-alert-content" @tap.stop="click">
|
||||||
|
<view class="u-alert-title" :style="[uTitleStyle]">
|
||||||
|
{{title}}
|
||||||
|
</view>
|
||||||
|
<view v-if="description" class="u-alert-desc" :style="[descStyle]">
|
||||||
|
{{description}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-icon-wrap">
|
||||||
|
<u-icon @click="close" v-if="closeAble && !closeText" hoverClass="u-type-error-hover-color" name="close" color="#c0c4cc"
|
||||||
|
:size="22" class="u-close-icon" :style="{
|
||||||
|
top: description ? '18rpx' : '24rpx'
|
||||||
|
}"></u-icon>
|
||||||
|
</view>
|
||||||
|
<text v-if="closeAble && closeText" class="u-close-text" :style="{
|
||||||
|
top: description ? '18rpx' : '24rpx'
|
||||||
|
}">{{closeText}}</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* alertTips 警告提示
|
||||||
|
* @description 警告提示,展现需要关注的信息
|
||||||
|
* @tutorial https://uviewui.com/components/alertTips.html
|
||||||
|
* @property {String} title 显示的标题文字
|
||||||
|
* @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选
|
||||||
|
* @property {String} type 关闭按钮(默认为叉号icon图标)
|
||||||
|
* @property {String} icon 图标名称
|
||||||
|
* @property {Object} icon-style 图标的样式,对象形式
|
||||||
|
* @property {Object} title-style 标题的样式,对象形式
|
||||||
|
* @property {Object} desc-style 描述的样式,对象形式
|
||||||
|
* @property {String} close-able 用文字替代关闭图标,close-able为true时有效
|
||||||
|
* @property {Boolean} show-icon 是否显示左边的辅助图标
|
||||||
|
* @property {Boolean} show 显示或隐藏组件
|
||||||
|
* @event {Function} click 点击组件时触发
|
||||||
|
* @event {Function} close 点击关闭按钮时触发
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-alert-tips',
|
||||||
|
props: {
|
||||||
|
// 显示文字
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 主题,success/warning/info/error
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'warning'
|
||||||
|
},
|
||||||
|
// 辅助性文字
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否可关闭
|
||||||
|
closeAble: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 关闭按钮自定义文本
|
||||||
|
closeText: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否显示图标
|
||||||
|
showIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 文字颜色,如果定义了color值,icon会失效
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 背景颜色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 边框颜色
|
||||||
|
borderColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否显示
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 左边显示的icon
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// icon的样式
|
||||||
|
iconStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 标题的样式
|
||||||
|
titleStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 描述文字的样式
|
||||||
|
descStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
uTitleStyle() {
|
||||||
|
let style = {};
|
||||||
|
// 如果有描述文字的话,标题进行加粗
|
||||||
|
style.fontWeight = this.description ? 500 : 'normal';
|
||||||
|
// 将用户传入样式对象和style合并,传入的优先级比style高,同属性会被覆盖
|
||||||
|
return this.$u.deepMerge(style, this.titleStyle);
|
||||||
|
},
|
||||||
|
uIcon() {
|
||||||
|
// 如果有设置icon名称就使用,否则根据type主题,推定一个默认的图标
|
||||||
|
return this.icon ? this.icon : this.$u.type2icon(this.type);
|
||||||
|
},
|
||||||
|
uIconType() {
|
||||||
|
// 如果有设置图标的样式,优先使用,没有的话,则用type的样式
|
||||||
|
return Object.keys(this.iconStyle).length ? '' : this.type;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 点击内容
|
||||||
|
click() {
|
||||||
|
this.$emit('click');
|
||||||
|
},
|
||||||
|
// 点击关闭按钮
|
||||||
|
close() {
|
||||||
|
this.$emit('close');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-alert-tips {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16rpx 30rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.3s linear;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
|
||||||
|
&--bg--primary-light {
|
||||||
|
background-color: $u-type-primary-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bg--info-light {
|
||||||
|
background-color: $u-type-info-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bg--success-light {
|
||||||
|
background-color: $u-type-success-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bg--warning-light {
|
||||||
|
background-color: $u-type-warning-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bg--error-light {
|
||||||
|
background-color: $u-type-error-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border--primary-disabled {
|
||||||
|
border-color: $u-type-primary-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border--success-disabled {
|
||||||
|
border-color: $u-type-success-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border--error-disabled {
|
||||||
|
border-color: $u-type-error-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border--warning-disabled {
|
||||||
|
border-color: $u-type-warning-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border--info-disabled {
|
||||||
|
border-color: $u-type-info-disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-close-alert-tips {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-icon {
|
||||||
|
margin-right: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-alert-title {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: $u-main-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-alert-desc {
|
||||||
|
font-size: 26rpx;
|
||||||
|
text-align: left;
|
||||||
|
color: $u-content-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-close-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 20rpx;
|
||||||
|
right: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-close-hover {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-close-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: $u-tips-color;
|
||||||
|
position: absolute;
|
||||||
|
top: 20rpx;
|
||||||
|
right: 20rpx;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,44 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 显示文字
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.alert.title
|
||||||
|
},
|
||||||
|
// 主题,success/warning/info/error
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.alert.type
|
||||||
|
},
|
||||||
|
// 辅助性文字
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.alert.description
|
||||||
|
},
|
||||||
|
// 是否可关闭
|
||||||
|
closable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.alert.closable
|
||||||
|
},
|
||||||
|
// 是否显示图标
|
||||||
|
showIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.alert.showIcon
|
||||||
|
},
|
||||||
|
// 浅或深色调,light-浅色,dark-深色
|
||||||
|
effect: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.alert.effect
|
||||||
|
},
|
||||||
|
// 文字是否居中
|
||||||
|
center: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.alert.center
|
||||||
|
},
|
||||||
|
// 字体大小
|
||||||
|
fontSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.alert.fontSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,243 @@
|
||||||
|
<template>
|
||||||
|
<u-transition
|
||||||
|
mode="fade"
|
||||||
|
:show="show"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="u-alert"
|
||||||
|
:class="[`u-alert--${type}--${effect}`]"
|
||||||
|
@tap.stop="clickHandler"
|
||||||
|
:style="[$u.addStyle(customStyle)]"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="u-alert__icon"
|
||||||
|
v-if="showIcon"
|
||||||
|
>
|
||||||
|
<u-icon
|
||||||
|
:name="iconName"
|
||||||
|
size="18"
|
||||||
|
:color="iconColor"
|
||||||
|
></u-icon>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="u-alert__content"
|
||||||
|
:style="[{
|
||||||
|
paddingRight: closable ? '20px' : 0
|
||||||
|
}]"
|
||||||
|
>
|
||||||
|
<text
|
||||||
|
class="u-alert__content__title"
|
||||||
|
v-if="title"
|
||||||
|
:style="[{
|
||||||
|
fontSize: $u.addUnit(fontSize),
|
||||||
|
textAlign: center ? 'center' : 'left'
|
||||||
|
}]"
|
||||||
|
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
|
||||||
|
>{{ title }}</text>
|
||||||
|
<text
|
||||||
|
class="u-alert__content__desc"
|
||||||
|
v-if="description"
|
||||||
|
:style="[{
|
||||||
|
fontSize: $u.addUnit(fontSize),
|
||||||
|
textAlign: center ? 'center' : 'left'
|
||||||
|
}]"
|
||||||
|
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
|
||||||
|
>{{ description }}</text>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="u-alert__close"
|
||||||
|
v-if="closable"
|
||||||
|
@tap.stop="closeHandler"
|
||||||
|
>
|
||||||
|
<u-icon
|
||||||
|
name="close"
|
||||||
|
:color="iconColor"
|
||||||
|
size="15"
|
||||||
|
></u-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js';
|
||||||
|
/**
|
||||||
|
* Alert 警告提示
|
||||||
|
* @description 警告提示,展现需要关注的信息。
|
||||||
|
* @tutorial https://www.uviewui.com/components/alertTips.html
|
||||||
|
*
|
||||||
|
* @property {String} title 显示的文字
|
||||||
|
* @property {String} type 使用预设的颜色 (默认 'warning' )
|
||||||
|
* @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选
|
||||||
|
* @property {Boolean} closable 关闭按钮(默认为叉号icon图标) (默认 false )
|
||||||
|
* @property {Boolean} showIcon 是否显示左边的辅助图标 ( 默认 false )
|
||||||
|
* @property {String} effect 多图时,图片缩放裁剪的模式 (默认 'light' )
|
||||||
|
* @property {Boolean} center 文字是否居中 (默认 false )
|
||||||
|
* @property {String | Number} fontSize 字体大小 (默认 14 )
|
||||||
|
* @property {Object} customStyle 定义需要用到的外部样式
|
||||||
|
* @event {Function} click 点击组件时触发
|
||||||
|
* @example <u-alert :title="title" type = "warning" :closable="closable" :description = "description"></u-alert>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-alert',
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
iconColor() {
|
||||||
|
return this.effect === 'light' ? this.type : '#fff'
|
||||||
|
},
|
||||||
|
// 不同主题对应不同的图标
|
||||||
|
iconName() {
|
||||||
|
switch (this.type) {
|
||||||
|
case 'success':
|
||||||
|
return 'checkmark-circle-fill';
|
||||||
|
break;
|
||||||
|
case 'error':
|
||||||
|
return 'close-circle-fill';
|
||||||
|
break;
|
||||||
|
case 'warning':
|
||||||
|
return 'error-circle-fill';
|
||||||
|
break;
|
||||||
|
case 'info':
|
||||||
|
return 'info-circle-fill';
|
||||||
|
break;
|
||||||
|
case 'primary':
|
||||||
|
return 'more-circle-fill';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 'error-circle-fill';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 点击内容
|
||||||
|
clickHandler() {
|
||||||
|
this.$emit('click')
|
||||||
|
},
|
||||||
|
// 点击关闭按钮
|
||||||
|
closeHandler() {
|
||||||
|
this.show = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
|
.u-alert {
|
||||||
|
position: relative;
|
||||||
|
background-color: $u-primary;
|
||||||
|
padding: 8px 10px;
|
||||||
|
@include flex(row);
|
||||||
|
align-items: center;
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
|
||||||
|
&--primary--dark {
|
||||||
|
background-color: $u-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--primary--light {
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error--dark {
|
||||||
|
background-color: $u-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error--light {
|
||||||
|
background-color: #FEF0F0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--success--dark {
|
||||||
|
background-color: $u-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--success--light {
|
||||||
|
background-color: #f5fff0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--warning--dark {
|
||||||
|
background-color: $u-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--warning--light {
|
||||||
|
background-color: #FDF6EC;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--info--dark {
|
||||||
|
background-color: $u-info;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--info--light {
|
||||||
|
background-color: #f4f4f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
@include flex(column);
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
color: $u-main-color;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #fff;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__desc {
|
||||||
|
color: $u-main-color;
|
||||||
|
font-size: 14px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title--dark,
|
||||||
|
&__desc--dark {
|
||||||
|
color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text--primary--light,
|
||||||
|
&__text--primary--light {
|
||||||
|
color: $u-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text--success--light,
|
||||||
|
&__text--success--light {
|
||||||
|
color: $u-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text--warning--light,
|
||||||
|
&__text--warning--light {
|
||||||
|
color: $u-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text--error--light,
|
||||||
|
&__text--error--light {
|
||||||
|
color: $u-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text--info--light,
|
||||||
|
&__text--info--light {
|
||||||
|
color: $u-info;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__close {
|
||||||
|
position: absolute;
|
||||||
|
top: 11px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,290 @@
|
||||||
|
<template>
|
||||||
|
<view class="content">
|
||||||
|
<view class="cropper-wrapper" :style="{ height: cropperOpt.height + 'px' }">
|
||||||
|
<canvas
|
||||||
|
class="cropper"
|
||||||
|
:disable-scroll="true"
|
||||||
|
@touchstart="touchStart"
|
||||||
|
@touchmove="touchMove"
|
||||||
|
@touchend="touchEnd"
|
||||||
|
:style="{ width: cropperOpt.width, height: cropperOpt.height, backgroundColor: 'rgba(0, 0, 0, 0.8)' }"
|
||||||
|
canvas-id="cropper"
|
||||||
|
id="cropper"
|
||||||
|
></canvas>
|
||||||
|
<canvas
|
||||||
|
class="cropper"
|
||||||
|
:disable-scroll="true"
|
||||||
|
:style="{
|
||||||
|
position: 'fixed',
|
||||||
|
top: `-${cropperOpt.width * cropperOpt.pixelRatio}px`,
|
||||||
|
left: `-${cropperOpt.height * cropperOpt.pixelRatio}px`,
|
||||||
|
width: `${cropperOpt.width * cropperOpt.pixelRatio}px`,
|
||||||
|
height: `${cropperOpt.height * cropperOpt.pixelRatio}`
|
||||||
|
}"
|
||||||
|
canvas-id="targetId"
|
||||||
|
id="targetId"
|
||||||
|
></canvas>
|
||||||
|
</view>
|
||||||
|
<view class="cropper-buttons safe-area-padding" :style="{ height: bottomNavHeight + 'px' }">
|
||||||
|
<!-- #ifdef H5 -->
|
||||||
|
<view class="upload" @tap="uploadTap">选择图片</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef H5 -->
|
||||||
|
<view class="upload" @tap="uploadTap">重新选择</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<view class="getCropperImage" @tap="getCropperImage(false)">确定</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import WeCropper from './weCropper.js';
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 裁剪矩形框的样式,其中可包含的属性为lineWidth-边框宽度(单位rpx),color: 边框颜色,
|
||||||
|
// mask-遮罩颜色,一般设置为一个rgba的透明度,如"rgba(0, 0, 0, 0.35)"
|
||||||
|
boundStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {
|
||||||
|
lineWidth: 4,
|
||||||
|
borderColor: 'rgb(245, 245, 245)',
|
||||||
|
mask: 'rgba(0, 0, 0, 0.35)'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// // 裁剪框宽度,单位rpx
|
||||||
|
// rectWidth: {
|
||||||
|
// type: [String, Number],
|
||||||
|
// default: 400
|
||||||
|
// },
|
||||||
|
// // 裁剪框高度,单位rpx
|
||||||
|
// rectHeight: {
|
||||||
|
// type: [String, Number],
|
||||||
|
// default: 400
|
||||||
|
// },
|
||||||
|
// // 输出图片宽度,单位rpx
|
||||||
|
// destWidth: {
|
||||||
|
// type: [String, Number],
|
||||||
|
// default: 400
|
||||||
|
// },
|
||||||
|
// // 输出图片高度,单位rpx
|
||||||
|
// destHeight: {
|
||||||
|
// type: [String, Number],
|
||||||
|
// default: 400
|
||||||
|
// },
|
||||||
|
// // 输出的图片类型,如果发现裁剪的图片很大,可能是因为设置为了"png",改成"jpg"即可
|
||||||
|
// fileType: {
|
||||||
|
// type: String,
|
||||||
|
// default: 'jpg',
|
||||||
|
// },
|
||||||
|
// // 生成的图片质量
|
||||||
|
// // H5上无效,目前不考虑使用此参数
|
||||||
|
// quality: {
|
||||||
|
// type: [Number, String],
|
||||||
|
// default: 1
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 底部导航的高度
|
||||||
|
bottomNavHeight: 50,
|
||||||
|
originWidth: 200,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
cropperOpt: {
|
||||||
|
id: 'cropper',
|
||||||
|
targetId: 'targetCropper',
|
||||||
|
pixelRatio: 1,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
scale: 2.5,
|
||||||
|
zoom: 8,
|
||||||
|
cut: {
|
||||||
|
x: (this.width - this.originWidth) / 2,
|
||||||
|
y: (this.height - this.originWidth) / 2,
|
||||||
|
width: this.originWidth,
|
||||||
|
height: this.originWidth
|
||||||
|
},
|
||||||
|
boundStyle: {
|
||||||
|
lineWidth: uni.upx2px(this.boundStyle.lineWidth),
|
||||||
|
mask: this.boundStyle.mask,
|
||||||
|
color: this.boundStyle.borderColor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 裁剪框和输出图片的尺寸,高度默认等于宽度
|
||||||
|
// 输出图片宽度,单位px
|
||||||
|
destWidth: 200,
|
||||||
|
// 裁剪框宽度,单位px
|
||||||
|
rectWidth: 200,
|
||||||
|
// 输出的图片类型,如果'png'类型发现裁剪的图片太大,改成"jpg"即可
|
||||||
|
fileType: 'jpg',
|
||||||
|
src: '', // 选择的图片路径,用于在点击确定时,判断是否选择了图片
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onLoad(option) {
|
||||||
|
let rectInfo = uni.getSystemInfoSync();
|
||||||
|
this.width = rectInfo.windowWidth;
|
||||||
|
this.height = rectInfo.windowHeight - this.bottomNavHeight;
|
||||||
|
this.cropperOpt.width = this.width;
|
||||||
|
this.cropperOpt.height = this.height;
|
||||||
|
this.cropperOpt.pixelRatio = rectInfo.pixelRatio;
|
||||||
|
|
||||||
|
if (option.destWidth) this.destWidth = option.destWidth;
|
||||||
|
if (option.rectWidth) {
|
||||||
|
let rectWidth = Number(option.rectWidth);
|
||||||
|
this.cropperOpt.cut = {
|
||||||
|
x: (this.width - rectWidth) / 2,
|
||||||
|
y: (this.height - rectWidth) / 2,
|
||||||
|
width: rectWidth,
|
||||||
|
height: rectWidth
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.rectWidth = option.rectWidth;
|
||||||
|
if (option.fileType) this.fileType = option.fileType;
|
||||||
|
// 初始化
|
||||||
|
this.cropper = new WeCropper(this.cropperOpt)
|
||||||
|
.on('ready', ctx => {
|
||||||
|
// wecropper is ready for work!
|
||||||
|
})
|
||||||
|
.on('beforeImageLoad', ctx => {
|
||||||
|
// before picture loaded, i can do something
|
||||||
|
})
|
||||||
|
.on('imageLoad', ctx => {
|
||||||
|
// picture loaded
|
||||||
|
})
|
||||||
|
.on('beforeDraw', (ctx, instance) => {
|
||||||
|
// before canvas draw,i can do something
|
||||||
|
});
|
||||||
|
// 设置导航栏样式,以免用户在page.json中没有设置为黑色背景
|
||||||
|
uni.setNavigationBarColor({
|
||||||
|
frontColor: '#ffffff',
|
||||||
|
backgroundColor: '#000000'
|
||||||
|
});
|
||||||
|
uni.chooseImage({
|
||||||
|
count: 1, // 默认9
|
||||||
|
sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
|
||||||
|
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
|
||||||
|
success: res => {
|
||||||
|
this.src = res.tempFilePaths[0];
|
||||||
|
// 获取裁剪图片资源后,给data添加src属性及其值
|
||||||
|
this.cropper.pushOrign(this.src);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
touchStart(e) {
|
||||||
|
this.cropper.touchStart(e);
|
||||||
|
},
|
||||||
|
touchMove(e) {
|
||||||
|
this.cropper.touchMove(e);
|
||||||
|
},
|
||||||
|
touchEnd(e) {
|
||||||
|
this.cropper.touchEnd(e);
|
||||||
|
},
|
||||||
|
getCropperImage(isPre = false) {
|
||||||
|
if(!this.src) return this.$u.toast('请先选择图片再裁剪');
|
||||||
|
|
||||||
|
let cropper_opt = {
|
||||||
|
destHeight: Number(this.destWidth), // uni.canvasToTempFilePath要求这些参数为数值
|
||||||
|
destWidth: Number(this.destWidth),
|
||||||
|
fileType: this.fileType
|
||||||
|
};
|
||||||
|
this.cropper.getCropperImage(cropper_opt, (path, err) => {
|
||||||
|
if (err) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '温馨提示',
|
||||||
|
content: err.message
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (isPre) {
|
||||||
|
uni.previewImage({
|
||||||
|
current: '', // 当前显示图片的 http 链接
|
||||||
|
urls: [path] // 需要预览的图片 http 链接列表
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
uni.$emit('uAvatarCropper', path);
|
||||||
|
this.$u.route({
|
||||||
|
type: 'back'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
uploadTap() {
|
||||||
|
const self = this;
|
||||||
|
uni.chooseImage({
|
||||||
|
count: 1, // 默认9
|
||||||
|
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
|
||||||
|
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
|
||||||
|
success: (res) => {
|
||||||
|
self.src = res.tempFilePaths[0];
|
||||||
|
// 获取裁剪图片资源后,给data添加src属性及其值
|
||||||
|
|
||||||
|
self.cropper.pushOrign(this.src);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '../../libs/css/style.components.scss';
|
||||||
|
|
||||||
|
.content {
|
||||||
|
background: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-buttons {
|
||||||
|
background-color: #000000;
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-wrapper {
|
||||||
|
position: relative;
|
||||||
|
@include vue-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-buttons {
|
||||||
|
width: 100vw;
|
||||||
|
@include vue-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-buttons .upload,
|
||||||
|
.cropper-buttons .getCropperImage {
|
||||||
|
width: 50%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-buttons .upload {
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-buttons .getCropperImage {
|
||||||
|
text-align: right;
|
||||||
|
padding-right: 50rpx;
|
||||||
|
}
|
||||||
|
</style>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,52 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 头像图片组
|
||||||
|
urls: {
|
||||||
|
type: Array,
|
||||||
|
default: uni.$u.props.avatarGroup.urls
|
||||||
|
},
|
||||||
|
// 最多展示的头像数量
|
||||||
|
maxCount: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.avatarGroup.maxCount
|
||||||
|
},
|
||||||
|
// 头像形状
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.avatarGroup.shape
|
||||||
|
},
|
||||||
|
// 图片裁剪模式
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.avatarGroup.mode
|
||||||
|
},
|
||||||
|
// 超出maxCount时是否显示查看更多的提示
|
||||||
|
showMore: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.avatarGroup.showMore
|
||||||
|
},
|
||||||
|
// 头像大小
|
||||||
|
size: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.avatarGroup.size
|
||||||
|
},
|
||||||
|
// 指定从数组的对象元素中读取哪个属性作为图片地址
|
||||||
|
keyName: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.avatarGroup.keyName
|
||||||
|
},
|
||||||
|
// 头像之间的遮挡比例
|
||||||
|
gap: {
|
||||||
|
type: [String, Number],
|
||||||
|
validator(value) {
|
||||||
|
return value >= 0 && value <= 1
|
||||||
|
},
|
||||||
|
default: uni.$u.props.avatarGroup.gap
|
||||||
|
},
|
||||||
|
// 需额外显示的值
|
||||||
|
extraValue: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: uni.$u.props.avatarGroup.extraValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
<template>
|
||||||
|
<view class="u-avatar-group">
|
||||||
|
<view
|
||||||
|
class="u-avatar-group__item"
|
||||||
|
v-for="(item, index) in showUrl"
|
||||||
|
:key="index"
|
||||||
|
:style="{
|
||||||
|
marginLeft: index === 0 ? 0 : $u.addUnit(-size * gap)
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<u-avatar
|
||||||
|
:size="size"
|
||||||
|
:shape="shape"
|
||||||
|
:mode="mode"
|
||||||
|
:src="$u.test.object(item) ? keyName && item[keyName] || item.url : item"
|
||||||
|
></u-avatar>
|
||||||
|
<view
|
||||||
|
class="u-avatar-group__item__show-more"
|
||||||
|
v-if="showMore && index === showUrl.length - 1 && (urls.length > maxCount || extraValue > 0)"
|
||||||
|
@tap="clickHandler"
|
||||||
|
>
|
||||||
|
<u--text
|
||||||
|
color="#ffffff"
|
||||||
|
:size="size * 0.4"
|
||||||
|
:text="`+${extraValue || urls.length - showUrl.length}`"
|
||||||
|
align="center"
|
||||||
|
customStyle="justify-content: center"
|
||||||
|
></u--text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js';
|
||||||
|
/**
|
||||||
|
* AvatarGroup 头像组
|
||||||
|
* @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
|
||||||
|
* @tutorial https://www.uviewui.com/components/avatar.html
|
||||||
|
*
|
||||||
|
* @property {Array} urls 头像图片组 (默认 [] )
|
||||||
|
* @property {String | Number} maxCount 最多展示的头像数量 ( 默认 5 )
|
||||||
|
* @property {String} shape 头像形状( 'circle' (默认) | 'square' )
|
||||||
|
* @property {String} mode 图片裁剪模式(默认 'scaleToFill' )
|
||||||
|
* @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 (默认 true )
|
||||||
|
* @property {String | Number} size 头像大小 (默认 40 )
|
||||||
|
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
|
||||||
|
* @property {String | Number} gap 头像之间的遮挡比例(0.4代表遮挡40%) (默认 0.5 )
|
||||||
|
* @property {String | Number} extraValue 需额外显示的值
|
||||||
|
* @event {Function} showMore 头像组更多点击
|
||||||
|
* @example <u-avatar-group:urls="urls" size="35" gap="0.4" ></u-avatar-group:urls=>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-avatar-group',
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
showUrl() {
|
||||||
|
return this.urls.slice(0, this.maxCount)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clickHandler() {
|
||||||
|
this.$emit('showMore')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
|
.u-avatar-group {
|
||||||
|
@include flex;
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
margin-left: -10px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&--no-indent {
|
||||||
|
// 如果你想质疑作者不会使用:first-child,说明你太年轻,因为nvue不支持
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__show-more {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
@include flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,78 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 头像图片路径(不能为相对路径)
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.avatar.src
|
||||||
|
},
|
||||||
|
// 头像形状,circle-圆形,square-方形
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.avatar.shape
|
||||||
|
},
|
||||||
|
// 头像尺寸
|
||||||
|
size: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.avatar.size
|
||||||
|
},
|
||||||
|
// 裁剪模式
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.avatar.mode
|
||||||
|
},
|
||||||
|
// 显示的文字
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.avatar.text
|
||||||
|
},
|
||||||
|
// 背景色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.avatar.bgColor
|
||||||
|
},
|
||||||
|
// 文字颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.avatar.color
|
||||||
|
},
|
||||||
|
// 文字大小
|
||||||
|
fontSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.avatar.fontSize
|
||||||
|
},
|
||||||
|
// 显示的图标
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.avatar.icon
|
||||||
|
},
|
||||||
|
// 显示小程序头像,只对百度,微信,QQ小程序有效
|
||||||
|
mpAvatar: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.avatar.mpAvatar
|
||||||
|
},
|
||||||
|
// 是否使用随机背景色
|
||||||
|
randomBgColor: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.avatar.randomBgColor
|
||||||
|
},
|
||||||
|
// 加载失败的默认头像(组件有内置默认图片)
|
||||||
|
defaultUrl: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.avatar.defaultUrl
|
||||||
|
},
|
||||||
|
// 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间
|
||||||
|
colorIndex: {
|
||||||
|
type: [String, Number],
|
||||||
|
// 校验参数规则,索引在0-19之间
|
||||||
|
validator(n) {
|
||||||
|
return uni.$u.test.range(n, [0, 19]) || n === ''
|
||||||
|
},
|
||||||
|
default: uni.$u.props.avatar.colorIndex
|
||||||
|
},
|
||||||
|
// 组件标识符
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.avatar.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="u-avatar"
|
||||||
|
:class="[`u-avatar--${shape}`]"
|
||||||
|
:style="[{
|
||||||
|
backgroundColor: (text || icon) ? (randomBgColor ? colors[colorIndex !== '' ? colorIndex : $u.random(0, 19)] : bgColor) : 'transparent',
|
||||||
|
width: $u.addUnit(size),
|
||||||
|
height: $u.addUnit(size),
|
||||||
|
}, $u.addStyle(customStyle)]"
|
||||||
|
@tap="clickHandler"
|
||||||
|
>
|
||||||
|
<slot>
|
||||||
|
<!-- #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU -->
|
||||||
|
<open-data
|
||||||
|
v-if="mpAvatar && allowMp"
|
||||||
|
type="userAvatarUrl"
|
||||||
|
:style="[{
|
||||||
|
width: $u.addUnit(size),
|
||||||
|
height: $u.addUnit(size)
|
||||||
|
}]"
|
||||||
|
/>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU -->
|
||||||
|
<template v-if="mpAvatar && allowMp"></template>
|
||||||
|
<!-- #endif -->
|
||||||
|
<u-icon
|
||||||
|
v-else-if="icon"
|
||||||
|
:name="icon"
|
||||||
|
:size="fontSize"
|
||||||
|
:color="color"
|
||||||
|
></u-icon>
|
||||||
|
<u--text
|
||||||
|
v-else-if="text"
|
||||||
|
:text="text"
|
||||||
|
:size="fontSize"
|
||||||
|
:color="color"
|
||||||
|
align="center"
|
||||||
|
customStyle="justify-content: center"
|
||||||
|
></u--text>
|
||||||
|
<image
|
||||||
|
class="u-avatar__image"
|
||||||
|
v-else
|
||||||
|
:class="[`u-avatar__image--${shape}`]"
|
||||||
|
:src="avatarUrl || defaultUrl"
|
||||||
|
:mode="mode"
|
||||||
|
@error="errorHandler"
|
||||||
|
:style="[{
|
||||||
|
width: $u.addUnit(size),
|
||||||
|
height: $u.addUnit(size)
|
||||||
|
}]"
|
||||||
|
></image>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js';
|
||||||
|
const base64Avatar =
|
||||||
|
"data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYGCAsMCgoLCgoMEAwMDAwMDBAMDg8QDw4MExMUFBMTHBsbGxwfHx8fHx8fHx8fAQcHBw0MDRgQEBgaFREVGh8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx//wAARCADIAMgDAREAAhEBAxEB/8QAcQABAQEAAwEBAAAAAAAAAAAAAAUEAQMGAgcBAQAAAAAAAAAAAAAAAAAAAAAQAAIBAwICBgkDBQAAAAAAAAABAhEDBCEFMVFBYXGREiKBscHRMkJSEyOh4XLxYjNDFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHbHFyZ/Dam+yLA+Z2L0Pjtyj2poD4AAAAAAAAAAAAAAAAAAAAAAAAKWFs9y6lcvvwQeqj8z9wFaziY1n/HbUX9XF97A7QAGXI23EvJ1goyfzR0YEfN269jeZ+a03pNe0DIAAAAAAAAAAAAAAAAAAAACvtO3RcVkXlWutuL9YFYAAAAAOJRjKLjJVi9GmB5/csH/mu1h/in8PU+QGMAAAAAAAAAAAAAAAAAAaMDG/6MmMH8C80+xAelSSVFolwQAAAAAAAHVlWI37ErUulaPk+hgeYnCUJuElSUXRrrQHAAAAAAAAAAAAAAAAABa2Oz4bM7r4zdF2ICmAAAAAAAAAg7zZ8GX41wuJP0rRgYAAAAAAAAAAAAAAAAAD0m2R8ODaXU33tsDSAAAAAAAAAlb9HyWZcnJd9PcBHAAAAAAAAAAAAAAAAAPS7e64Vn+KA0AAAAAAAAAJm+v8Ftf3ewCKAAAAAAAAAAAAAAAAAX9muqeGo9NttP06+0DcAAAAAAAAAjb7dTu2ra+VOT9P8AQCWAAAAAAAAAAAAAAAAAUNmyPt5Ltv4bui/kuAF0AAAAAAADiUlGLlJ0SVW+oDzOXfd/Ind6JPRdS0QHSAAAAAAAAAAAAAAAAAE2nVaNcGB6Lbs6OTao9LsF51z60BrAAAAAABJ3jOVHjW3r/sa9QEgAAAAAAAAAAAAAAAAAAAPu1duWriuW34ZR4MC9hbnZyEoy8l36XwfYBsAAADaSq9EuLAlZ+7xSdrGdW9Hc5dgEdtt1erfFgAAAAAAAAAAAAAAAAADVjbblX6NR8MH80tEBRs7HYivyzlN8lovaBPzduvY0m6eK10TXtAyAarO55lpJK54orolr+4GqO/Xaea1FvqbXvA+Z77kNeW3GPbV+4DJfzcm/pcm3H6Vou5AdAFLC2ed2Pjv1txa8sV8T6wOL+yZEKu1JXFy4MDBOE4ScZxcZLinoB8gAAAAAAAAAAAB242LeyJ+C3GvN9C7QLmJtePYpKS+5c+p8F2IDYAANJqj1T4oCfk7Nj3G5Wn9qXJax7gJ93Z82D8sVNc4v30A6Xg5i42Z+iLfqARwcyT0sz9MWvWBps7LlTf5Grce9/oBTxdtxseklHxT+uWr9AGoAB138ezfj4bsFJdD6V2MCPm7RdtJzs1uW1xXzL3gTgAAAAAAAAADRhYc8q74I6RWs5ckB6GxYtWLat21SK731sDsAAAAAAAAAAAAAAAASt021NO/YjrxuQXT1oCOAAAAAAABzGLlJRSq26JAelwsWONYjbXxcZvmwO8AAAAAAAAAAAAAAAAAAef3TEWPkVivx3NY9T6UBiAAAAAABo2+VmGXblddIJ8eivRUD0oAAAAAAAAAAAAAAAAAAAYt4tKeFKVNYNSXfRgefAAAAAAAAr7VuSSWPedKaW5v1MCsAAAAAAAAAAAAAAAAAAIe6bj96Ts2n+JPzSXzP3ATgAAAAAAAAFbbt1UUrOQ9FpC4/UwK6aaqtU+DAAAAAAAAAAAAAAA4lKMIuUmoxWrb4ARNx3R3q2rLpa4Sl0y/YCcAAAAAAAAAAANmFud7G8r89r6X0dgFvGzLGRGtuWvTF6NAdwAAAAAAAAAAAy5W442PVN+K59EePp5ARMvOv5MvO6QXCC4AZwAAAAAAAAAAAAAcxlKLUotprg1owN+PvORborq+7Hnwl3gUbO74VzRydt8pKn68ANcJwmqwkpLmnUDkAAAAfNy9atqtyagut0AxXt5xIV8Fbj6lRd7Am5G65V6qUvtwfyx94GMAAAAAAAAAAAAAAAAAAAOU2nVOj5gdsc3LiqRvTpyqwOxbnnrhdfpSfrQB7pnv/AGvuS9gHXPMy5/Fem1yq0v0A6W29XqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//Z";
|
||||||
|
/**
|
||||||
|
* Avatar 头像
|
||||||
|
* @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
|
||||||
|
* @tutorial https://www.uviewui.com/components/avatar.html
|
||||||
|
*
|
||||||
|
* @property {String} src 头像路径,如加载失败,将会显示默认头像(不能为相对路径)
|
||||||
|
* @property {String} shape 头像形状 ( circle (默认) | square)
|
||||||
|
* @property {String | Number} size 头像尺寸,可以为指定字符串(large, default, mini),或者数值 (默认 40 )
|
||||||
|
* @property {String} mode 头像图片的裁剪类型,与uni的image组件的mode参数一致,如效果达不到需求,可尝试传widthFix值 (默认 'scaleToFill' )
|
||||||
|
* @property {String} text 用文字替代图片,级别优先于src
|
||||||
|
* @property {String} bgColor 背景颜色,一般显示文字时用 (默认 '#c0c4cc' )
|
||||||
|
* @property {String} color 文字颜色 (默认 '#ffffff' )
|
||||||
|
* @property {String | Number} fontSize 文字大小 (默认 18 )
|
||||||
|
* @property {String} icon 显示的图标
|
||||||
|
* @property {Boolean} mpAvatar 显示小程序头像,只对百度,微信,QQ小程序有效 (默认 false )
|
||||||
|
* @property {Boolean} randomBgColor 是否使用随机背景色 (默认 false )
|
||||||
|
* @property {String} defaultUrl 加载失败的默认头像(组件有内置默认图片)
|
||||||
|
* @property {String | Number} colorIndex 如果配置了randomBgColor为true,且配置了此值,则从默认的背景色数组中取出对应索引的颜色值,取值0-19之间
|
||||||
|
* @property {String} name 组件标识符 (默认 'level' )
|
||||||
|
* @property {Object} customStyle 定义需要用到的外部样式
|
||||||
|
*
|
||||||
|
* @event {Function} click 点击组件时触发 index: 用户传递的标识符
|
||||||
|
* @example <u-avatar :src="src" mode="square"></u-avatar>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-avatar',
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 如果配置randomBgColor参数为true,在图标或者文字的模式下,会随机从中取出一个颜色值当做背景色
|
||||||
|
colors: ['#ffb34b', '#f2bba9', '#f7a196', '#f18080', '#88a867', '#bfbf39', '#89c152', '#94d554', '#f19ec2',
|
||||||
|
'#afaae4', '#e1b0df', '#c38cc1', '#72dcdc', '#9acdcb', '#77b1cc', '#448aca', '#86cefa', '#98d1ee',
|
||||||
|
'#73d1f1',
|
||||||
|
'#80a7dc'
|
||||||
|
],
|
||||||
|
avatarUrl: this.src,
|
||||||
|
allowMp: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// 监听头像src的变化,赋值给内部的avatarUrl变量,因为图片加载失败时,需要修改图片的src为默认值
|
||||||
|
// 而组件内部不能直接修改props的值,所以需要一个中间变量
|
||||||
|
src: {
|
||||||
|
immediate: true,
|
||||||
|
handler(newVal) {
|
||||||
|
this.avatarUrl = newVal
|
||||||
|
// 如果没有传src,则主动触发error事件,用于显示默认的头像,否则src为''空字符等的时候,会无内容展示
|
||||||
|
if(!newVal) {
|
||||||
|
this.errorHandler()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
imageStyle() {
|
||||||
|
const style = {}
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
// 目前只有这几个小程序平台具有open-data标签
|
||||||
|
// 其他平台可以通过uni.getUserInfo类似接口获取信息,但是需要弹窗授权(首次),不合符组件逻辑
|
||||||
|
// 故目前自动获取小程序头像只支持这几个平台
|
||||||
|
// #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU
|
||||||
|
this.allowMp = true
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
// 判断传入的name属性,是否图片路径,只要带有"/"均认为是图片形式
|
||||||
|
isImg() {
|
||||||
|
return this.src.indexOf('/') !== -1
|
||||||
|
},
|
||||||
|
// 图片加载时失败时触发
|
||||||
|
errorHandler() {
|
||||||
|
this.avatarUrl = this.defaultUrl || base64Avatar
|
||||||
|
},
|
||||||
|
clickHandler() {
|
||||||
|
this.$emit('click', this.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
|
.u-avatar {
|
||||||
|
@include flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&--circle {
|
||||||
|
border-radius: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--square {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__image {
|
||||||
|
&--circle {
|
||||||
|
border-radius: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--square {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,54 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 返回顶部的形状,circle-圆形,square-方形
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.backtop.mode
|
||||||
|
},
|
||||||
|
// 自定义图标
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.backtop.icon
|
||||||
|
},
|
||||||
|
// 提示文字
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.backtop.text
|
||||||
|
},
|
||||||
|
// 返回顶部滚动时间
|
||||||
|
duration: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.backtop.duration
|
||||||
|
},
|
||||||
|
// 滚动距离
|
||||||
|
scrollTop: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.backtop.scrollTop
|
||||||
|
},
|
||||||
|
// 距离顶部多少距离显示,单位px
|
||||||
|
top: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.backtop.top
|
||||||
|
},
|
||||||
|
// 返回顶部按钮到底部的距离,单位px
|
||||||
|
bottom: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.backtop.bottom
|
||||||
|
},
|
||||||
|
// 返回顶部按钮到右边的距离,单位px
|
||||||
|
right: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.backtop.right
|
||||||
|
},
|
||||||
|
// 层级
|
||||||
|
zIndex: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.backtop.zIndex
|
||||||
|
},
|
||||||
|
// 图标的样式,对象形式
|
||||||
|
iconStyle: {
|
||||||
|
type: Object,
|
||||||
|
default: uni.$u.props.backtop.iconStyle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
<template>
|
||||||
|
<u-transition
|
||||||
|
mode="fade"
|
||||||
|
:customStyle="backTopStyle"
|
||||||
|
:show="show"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="u-back-top"
|
||||||
|
:style="[contentStyle]"
|
||||||
|
v-if="!$slots.default && !$slots.$default"
|
||||||
|
@click="backToTop"
|
||||||
|
>
|
||||||
|
<u-icon
|
||||||
|
:name="icon"
|
||||||
|
:custom-style="iconStyle"
|
||||||
|
></u-icon>
|
||||||
|
<text
|
||||||
|
v-if="text"
|
||||||
|
class="u-back-top__text"
|
||||||
|
>{{text}}</text>
|
||||||
|
</view>
|
||||||
|
<slot v-else />
|
||||||
|
</u-transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js';
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
const dom = weex.requireModule('dom')
|
||||||
|
// #endif
|
||||||
|
/**
|
||||||
|
* backTop 返回顶部
|
||||||
|
* @description 本组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。
|
||||||
|
* @tutorial https://uviewui.com/components/backTop.html
|
||||||
|
*
|
||||||
|
* @property {String} mode 返回顶部的形状,circle-圆形,square-方形 (默认 'circle' )
|
||||||
|
* @property {String} icon 自定义图标 (默认 'arrow-upward' ) 见官方文档示例
|
||||||
|
* @property {String} text 提示文字
|
||||||
|
* @property {String | Number} duration 返回顶部滚动时间 (默认 100)
|
||||||
|
* @property {String | Number} scrollTop 滚动距离 (默认 0 )
|
||||||
|
* @property {String | Number} top 距离顶部多少距离显示,单位px (默认 400 )
|
||||||
|
* @property {String | Number} bottom 返回顶部按钮到底部的距离,单位px (默认 100 )
|
||||||
|
* @property {String | Number} right 返回顶部按钮到右边的距离,单位px (默认 20 )
|
||||||
|
* @property {String | Number} zIndex 层级 (默认 9 )
|
||||||
|
* @property {Object<Object>} iconStyle 图标的样式,对象形式 (默认 {color: '#909399',fontSize: '19px'})
|
||||||
|
* @property {Object} customStyle 定义需要用到的外部样式
|
||||||
|
*
|
||||||
|
* @example <u-back-top :scrollTop="scrollTop"></u-back-top>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-back-top',
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
|
||||||
|
computed: {
|
||||||
|
backTopStyle() {
|
||||||
|
// 动画组件样式
|
||||||
|
const style = {
|
||||||
|
bottom: uni.$u.addUnit(this.bottom),
|
||||||
|
right: uni.$u.addUnit(this.right),
|
||||||
|
width: '40px',
|
||||||
|
height: '40px',
|
||||||
|
position: 'fixed',
|
||||||
|
zIndex: 10,
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
},
|
||||||
|
show() {
|
||||||
|
return uni.$u.getPx(this.scrollTop) > uni.$u.getPx(this.top)
|
||||||
|
},
|
||||||
|
contentStyle() {
|
||||||
|
const style = {}
|
||||||
|
let radius = 0
|
||||||
|
// 是否圆形
|
||||||
|
if(this.mode === 'circle') {
|
||||||
|
radius = '100px'
|
||||||
|
} else {
|
||||||
|
radius = '4px'
|
||||||
|
}
|
||||||
|
// 为了兼容安卓nvue,只能这么分开写
|
||||||
|
style.borderTopLeftRadius = radius
|
||||||
|
style.borderTopRightRadius = radius
|
||||||
|
style.borderBottomLeftRadius = radius
|
||||||
|
style.borderBottomRightRadius = radius
|
||||||
|
return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
backToTop() {
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
if (!this.$parent.$refs['u-back-top']) {
|
||||||
|
uni.$u.error(`nvue页面需要给页面最外层元素设置"ref='u-back-top'`)
|
||||||
|
}
|
||||||
|
dom.scrollToElement(this.$parent.$refs['u-back-top'], {
|
||||||
|
offset: 0
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
uni.pageScrollTo({
|
||||||
|
scrollTop: 0,
|
||||||
|
duration: this.duration
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
this.$emit('click')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../libs/css/components.scss';
|
||||||
|
$u-back-top-flex:1 !default;
|
||||||
|
$u-back-top-height:100% !default;
|
||||||
|
$u-back-top-background-color:#E1E1E1 !default;
|
||||||
|
$u-back-top-tips-font-size:12px !default;
|
||||||
|
.u-back-top {
|
||||||
|
@include flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
flex:$u-back-top-flex;
|
||||||
|
height: $u-back-top-height;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: $u-back-top-background-color;
|
||||||
|
|
||||||
|
&__tips {
|
||||||
|
font-size:$u-back-top-tips-font-size;
|
||||||
|
transform: scale(0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,72 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 是否显示圆点
|
||||||
|
isDot: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.badge.isDot
|
||||||
|
},
|
||||||
|
// 显示的内容
|
||||||
|
value: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: uni.$u.props.badge.value
|
||||||
|
},
|
||||||
|
// 是否显示
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.badge.show
|
||||||
|
},
|
||||||
|
// 最大值,超过最大值会显示 '{max}+'
|
||||||
|
max: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: uni.$u.props.badge.max
|
||||||
|
},
|
||||||
|
// 主题类型,error|warning|success|primary
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.badge.type
|
||||||
|
},
|
||||||
|
// 当数值为 0 时,是否展示 Badge
|
||||||
|
showZero: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.badge.showZero
|
||||||
|
},
|
||||||
|
// 背景颜色,优先级比type高,如设置,type参数会失效
|
||||||
|
bgColor: {
|
||||||
|
type: [String, null],
|
||||||
|
default: uni.$u.props.badge.bgColor
|
||||||
|
},
|
||||||
|
// 字体颜色
|
||||||
|
color: {
|
||||||
|
type: [String, null],
|
||||||
|
default: uni.$u.props.badge.color
|
||||||
|
},
|
||||||
|
// 徽标形状,circle-四角均为圆角,horn-左下角为直角
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.badge.shape
|
||||||
|
},
|
||||||
|
// 设置数字的显示方式,overflow|ellipsis|limit
|
||||||
|
// overflow会根据max字段判断,超出显示`${max}+`
|
||||||
|
// ellipsis会根据max判断,超出显示`${max}...`
|
||||||
|
// limit会依据1000作为判断条件,超出1000,显示`${value/1000}K`,比如2.2k、3.34w,最多保留2位小数
|
||||||
|
numberType: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.badge.numberType
|
||||||
|
},
|
||||||
|
// 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效
|
||||||
|
offset: {
|
||||||
|
type: Array,
|
||||||
|
default: uni.$u.props.badge.offset
|
||||||
|
},
|
||||||
|
// 是否反转背景和字体颜色
|
||||||
|
inverted: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.badge.inverted
|
||||||
|
},
|
||||||
|
// 是否绝对定位
|
||||||
|
absolute: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.badge.absolute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
<template>
|
||||||
|
<text
|
||||||
|
v-if="show && ((Number(value) === 0 ? showZero : true) || isDot)"
|
||||||
|
:class="[isDot ? 'u-badge--dot' : 'u-badge--not-dot', inverted && 'u-badge--inverted', shape === 'horn' && 'u-badge--horn', `u-badge--${type}${inverted ? '--inverted' : ''}`]"
|
||||||
|
:style="[$u.addStyle(customStyle), badgeStyle]"
|
||||||
|
class="u-badge"
|
||||||
|
>{{ isDot ? '' :showValue }}</text>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js';
|
||||||
|
/**
|
||||||
|
* badge 徽标数
|
||||||
|
* @description 该组件一般用于图标右上角显示未读的消息数量,提示用户点击,有圆点和圆包含文字两种形式。
|
||||||
|
* @tutorial https://uviewui.com/components/badge.html
|
||||||
|
*
|
||||||
|
* @property {Boolean} isDot 是否显示圆点 (默认 false )
|
||||||
|
* @property {String | Number} value 显示的内容
|
||||||
|
* @property {Boolean} show 是否显示 (默认 true )
|
||||||
|
* @property {String | Number} max 最大值,超过最大值会显示 '{max}+' (默认999)
|
||||||
|
* @property {String} type 主题类型,error|warning|success|primary (默认 'error' )
|
||||||
|
* @property {Boolean} showZero 当数值为 0 时,是否展示 Badge (默认 false )
|
||||||
|
* @property {String} bgColor 背景颜色,优先级比type高,如设置,type参数会失效
|
||||||
|
* @property {String} color 字体颜色 (默认 '#ffffff' )
|
||||||
|
* @property {String} shape 徽标形状,circle-四角均为圆角,horn-左下角为直角 (默认 'circle' )
|
||||||
|
* @property {String} numberType 设置数字的显示方式,overflow|ellipsis|limit (默认 'overflow' )
|
||||||
|
* @property {Array}} offset 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,absolute为true时有效
|
||||||
|
* @property {Boolean} inverted 是否反转背景和字体颜色(默认 false )
|
||||||
|
* @property {Boolean} absolute 是否绝对定位(默认 false )
|
||||||
|
* @property {Object} customStyle 定义需要用到的外部样式
|
||||||
|
* @example <u-badge :type="type" :count="count"></u-badge>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-badge',
|
||||||
|
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
|
||||||
|
computed: {
|
||||||
|
// 是否将badge中心与父组件右上角重合
|
||||||
|
boxStyle() {
|
||||||
|
let style = {};
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
// 整个组件的样式
|
||||||
|
badgeStyle() {
|
||||||
|
const style = {}
|
||||||
|
if(this.color) {
|
||||||
|
style.color = this.color
|
||||||
|
}
|
||||||
|
if (this.bgColor && !this.inverted) {
|
||||||
|
style.backgroundColor = this.bgColor
|
||||||
|
}
|
||||||
|
if (this.absolute) {
|
||||||
|
style.position = 'absolute'
|
||||||
|
// 如果有设置offset参数
|
||||||
|
if(this.offset.length) {
|
||||||
|
// top和right分为为offset的第一个和第二个值,如果没有第二个值,则right等于top
|
||||||
|
const top = this.offset[0]
|
||||||
|
const right = this.offset[1] || top
|
||||||
|
style.top = uni.$u.addUnit(top)
|
||||||
|
style.right = uni.$u.addUnit(right)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
},
|
||||||
|
showValue() {
|
||||||
|
switch (this.numberType) {
|
||||||
|
case "overflow":
|
||||||
|
return Number(this.value) > Number(this.max) ? this.max + "+" : this.value
|
||||||
|
break;
|
||||||
|
case "ellipsis":
|
||||||
|
return Number(this.value) > Number(this.max) ? "..." : this.value
|
||||||
|
break;
|
||||||
|
case "limit":
|
||||||
|
return Number(this.value) > 999 ? Number(this.value) >= 9999 ?
|
||||||
|
Math.floor(this.value / 1e4 * 100) / 100 + "w" : Math.floor(this.value /
|
||||||
|
1e3 * 100) / 100 + "k" : this.value
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return Number(this.value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
|
$u-badge-primary: $u-primary !default;
|
||||||
|
$u-badge-error: $u-error !default;
|
||||||
|
$u-badge-success: $u-success !default;
|
||||||
|
$u-badge-info: $u-info !default;
|
||||||
|
$u-badge-warning: $u-warning !default;
|
||||||
|
$u-badge-dot-radius: 100px !default;
|
||||||
|
$u-badge-dot-size: 8px !default;
|
||||||
|
$u-badge-dot-right: 4px !default;
|
||||||
|
$u-badge-dot-top: 0 !default;
|
||||||
|
$u-badge-text-font-size: 11px !default;
|
||||||
|
$u-badge-text-right: 10px !default;
|
||||||
|
$u-badge-text-padding: 2px 5px !default;
|
||||||
|
$u-badge-text-align: center !default;
|
||||||
|
$u-badge-text-color: #FFFFFF !default;
|
||||||
|
|
||||||
|
.u-badge {
|
||||||
|
border-top-right-radius: $u-badge-dot-radius;
|
||||||
|
border-top-left-radius: $u-badge-dot-radius;
|
||||||
|
border-bottom-left-radius: $u-badge-dot-radius;
|
||||||
|
border-bottom-right-radius: $u-badge-dot-radius;
|
||||||
|
@include flex;
|
||||||
|
line-height: $u-badge-text-font-size;
|
||||||
|
text-align: $u-badge-text-align;
|
||||||
|
font-size: $u-badge-text-font-size;
|
||||||
|
color: $u-badge-text-color;
|
||||||
|
|
||||||
|
&--dot {
|
||||||
|
height: $u-badge-dot-size;
|
||||||
|
width: $u-badge-dot-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--inverted {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--not-dot {
|
||||||
|
padding: $u-badge-text-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--horn {
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--primary {
|
||||||
|
background-color: $u-badge-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--primary--inverted {
|
||||||
|
color: $u-badge-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error {
|
||||||
|
background-color: $u-badge-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error--inverted {
|
||||||
|
color: $u-badge-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--success {
|
||||||
|
background-color: $u-badge-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--success--inverted {
|
||||||
|
color: $u-badge-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--info {
|
||||||
|
background-color: $u-badge-info;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--info--inverted {
|
||||||
|
color: $u-badge-info;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--warning {
|
||||||
|
background-color: $u-badge-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--warning--inverted {
|
||||||
|
color: $u-badge-warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,46 @@
|
||||||
|
$u-button-active-opacity:0.75 !default;
|
||||||
|
$u-button-loading-text-margin-left:4px !default;
|
||||||
|
$u-button-text-color: #FFFFFF !default;
|
||||||
|
$u-button-text-plain-error-color:$u-error !default;
|
||||||
|
$u-button-text-plain-warning-color:$u-warning !default;
|
||||||
|
$u-button-text-plain-success-color:$u-success !default;
|
||||||
|
$u-button-text-plain-info-color:$u-info !default;
|
||||||
|
$u-button-text-plain-primary-color:$u-primary !default;
|
||||||
|
.u-button {
|
||||||
|
&--active {
|
||||||
|
opacity: $u-button-active-opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--active--plain {
|
||||||
|
background-color: rgb(217, 217, 217);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__loading-text {
|
||||||
|
margin-left:$u-button-loading-text-margin-left;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text,
|
||||||
|
&__loading-text {
|
||||||
|
color:$u-button-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text--plain--error {
|
||||||
|
color:$u-button-text-plain-error-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text--plain--warning {
|
||||||
|
color:$u-button-text-plain-warning-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text--plain--success{
|
||||||
|
color:$u-button-text-plain-success-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text--plain--info {
|
||||||
|
color:$u-button-text-plain-info-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text--plain--primary {
|
||||||
|
color:$u-button-text-plain-primary-color;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
/*
|
||||||
|
* @Author : LQ
|
||||||
|
* @Description :
|
||||||
|
* @version : 1.0
|
||||||
|
* @Date : 2021-08-16 10:04:04
|
||||||
|
* @LastAuthor : LQ
|
||||||
|
* @lastTime : 2021-08-16 10:04:24
|
||||||
|
* @FilePath : /u-view2.0/uview-ui/components/u-button/props.js
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 是否细边框
|
||||||
|
hairline: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.button.hairline
|
||||||
|
},
|
||||||
|
// 按钮的预置样式,info,primary,error,warning,success
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.type
|
||||||
|
},
|
||||||
|
// 按钮尺寸,large,normal,small,mini
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.size
|
||||||
|
},
|
||||||
|
// 按钮形状,circle(两边为半圆),square(带圆角)
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.shape
|
||||||
|
},
|
||||||
|
// 按钮是否镂空
|
||||||
|
plain: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.button.plain
|
||||||
|
},
|
||||||
|
// 是否禁止状态
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.button.disabled
|
||||||
|
},
|
||||||
|
// 是否加载中
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.button.loading
|
||||||
|
},
|
||||||
|
// 加载中提示文字
|
||||||
|
loadingText: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.button.loadingText
|
||||||
|
},
|
||||||
|
// 加载状态图标类型
|
||||||
|
loadingMode: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.loadingMode
|
||||||
|
},
|
||||||
|
// 加载图标大小
|
||||||
|
loadingSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.button.loadingSize
|
||||||
|
},
|
||||||
|
// 开放能力,具体请看uniapp稳定关于button组件部分说明
|
||||||
|
// https://uniapp.dcloud.io/component/button
|
||||||
|
openType: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.openType
|
||||||
|
},
|
||||||
|
// 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
|
||||||
|
// 取值为submit(提交表单),reset(重置表单)
|
||||||
|
formType: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.formType
|
||||||
|
},
|
||||||
|
// 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效
|
||||||
|
// 只微信小程序、QQ小程序有效
|
||||||
|
appParameter: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.appParameter
|
||||||
|
},
|
||||||
|
// 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
|
||||||
|
hoverStopPropagation: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.button.hoverStopPropagation
|
||||||
|
},
|
||||||
|
// 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效
|
||||||
|
lang: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.lang
|
||||||
|
},
|
||||||
|
// 会话来源,open-type="contact"时有效。只微信小程序有效
|
||||||
|
sessionFrom: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.sessionFrom
|
||||||
|
},
|
||||||
|
// 会话内消息卡片标题,open-type="contact"时有效
|
||||||
|
// 默认当前标题,只微信小程序有效
|
||||||
|
sendMessageTitle: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.sendMessageTitle
|
||||||
|
},
|
||||||
|
// 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效
|
||||||
|
// 默认当前分享路径,只微信小程序有效
|
||||||
|
sendMessagePath: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.sendMessagePath
|
||||||
|
},
|
||||||
|
// 会话内消息卡片图片,open-type="contact"时有效
|
||||||
|
// 默认当前页面截图,只微信小程序有效
|
||||||
|
sendMessageImg: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.sendMessageImg
|
||||||
|
},
|
||||||
|
// 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
|
||||||
|
// 用户点击后可以快速发送小程序消息,open-type="contact"时有效
|
||||||
|
showMessageCard: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.button.showMessageCard
|
||||||
|
},
|
||||||
|
// 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
|
||||||
|
dataName: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.dataName
|
||||||
|
},
|
||||||
|
// 节流,一定时间内只能触发一次
|
||||||
|
throttleTime: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.button.throttleTime
|
||||||
|
},
|
||||||
|
// 按住后多久出现点击态,单位毫秒
|
||||||
|
hoverStartTime: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.button.hoverStartTime
|
||||||
|
},
|
||||||
|
// 手指松开后点击态保留时间,单位毫秒
|
||||||
|
hoverStayTime: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.button.hoverStayTime
|
||||||
|
},
|
||||||
|
// 按钮文字,之所以通过props传入,是因为slot传入的话
|
||||||
|
// nvue中无法控制文字的样式
|
||||||
|
text: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.button.text
|
||||||
|
},
|
||||||
|
// 按钮图标
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.icon
|
||||||
|
},
|
||||||
|
// 按钮图标
|
||||||
|
iconColor: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.icon
|
||||||
|
},
|
||||||
|
// 按钮颜色,支持传入linear-gradient渐变色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.button.color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,495 @@
|
||||||
|
<template>
|
||||||
|
<!-- #ifndef APP-NVUE -->
|
||||||
|
<button
|
||||||
|
:hover-start-time="Number(hoverStartTime)"
|
||||||
|
:hover-stay-time="Number(hoverStayTime)"
|
||||||
|
:form-type="formType"
|
||||||
|
:open-type="openType"
|
||||||
|
:app-parameter="appParameter"
|
||||||
|
:hover-stop-propagation="hoverStopPropagation"
|
||||||
|
:send-message-title="sendMessageTitle"
|
||||||
|
:send-message-path="sendMessagePath"
|
||||||
|
:lang="lang"
|
||||||
|
:data-name="dataName"
|
||||||
|
:session-from="sessionFrom"
|
||||||
|
:send-message-img="sendMessageImg"
|
||||||
|
:show-message-card="showMessageCard"
|
||||||
|
@getphonenumber="getphonenumber"
|
||||||
|
@getuserinfo="getuserinfo"
|
||||||
|
@error="error"
|
||||||
|
@opensetting="opensetting"
|
||||||
|
@launchapp="launchapp"
|
||||||
|
@agreeprivacyauthorization="agreeprivacyauthorization"
|
||||||
|
:hover-class="!disabled && !loading ? 'u-button--active' : ''"
|
||||||
|
class="u-button u-reset-button"
|
||||||
|
:style="[baseColor, $u.addStyle(customStyle)]"
|
||||||
|
@tap="clickHandler"
|
||||||
|
:class="bemClass"
|
||||||
|
>
|
||||||
|
<template v-if="loading">
|
||||||
|
<u-loading-icon
|
||||||
|
:mode="loadingMode"
|
||||||
|
:size="loadingSize * 1.15"
|
||||||
|
:color="loadingColor"
|
||||||
|
></u-loading-icon>
|
||||||
|
<text
|
||||||
|
class="u-button__loading-text"
|
||||||
|
:style="[{ fontSize: textSize + 'px' }]"
|
||||||
|
>{{ loadingText || text }}</text
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<u-icon
|
||||||
|
v-if="icon"
|
||||||
|
:name="icon"
|
||||||
|
:color="iconColorCom"
|
||||||
|
:size="textSize * 1.35"
|
||||||
|
:customStyle="{ marginRight: '2px' }"
|
||||||
|
></u-icon>
|
||||||
|
<slot>
|
||||||
|
<text
|
||||||
|
class="u-button__text"
|
||||||
|
:style="[{ fontSize: textSize + 'px' }]"
|
||||||
|
>{{ text }}</text
|
||||||
|
>
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
</button>
|
||||||
|
<!-- #endif -->
|
||||||
|
|
||||||
|
<!-- #ifdef APP-NVUE -->
|
||||||
|
<view
|
||||||
|
:hover-start-time="Number(hoverStartTime)"
|
||||||
|
:hover-stay-time="Number(hoverStayTime)"
|
||||||
|
class="u-button"
|
||||||
|
:hover-class="
|
||||||
|
!disabled && !loading && !color && (plain || type === 'info')
|
||||||
|
? 'u-button--active--plain'
|
||||||
|
: !disabled && !loading && !plain
|
||||||
|
? 'u-button--active'
|
||||||
|
: ''
|
||||||
|
"
|
||||||
|
@tap="clickHandler"
|
||||||
|
:class="bemClass"
|
||||||
|
:style="[baseColor, $u.addStyle(customStyle)]"
|
||||||
|
>
|
||||||
|
<template v-if="loading">
|
||||||
|
<u-loading-icon
|
||||||
|
:mode="loadingMode"
|
||||||
|
:size="loadingSize * 1.15"
|
||||||
|
:color="loadingColor"
|
||||||
|
></u-loading-icon>
|
||||||
|
<text
|
||||||
|
class="u-button__loading-text"
|
||||||
|
:style="[nvueTextStyle]"
|
||||||
|
:class="[plain && `u-button__text--plain--${type}`]"
|
||||||
|
>{{ loadingText || text }}</text
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<u-icon
|
||||||
|
v-if="icon"
|
||||||
|
:name="icon"
|
||||||
|
:color="iconColorCom"
|
||||||
|
:size="textSize * 1.35"
|
||||||
|
></u-icon>
|
||||||
|
<text
|
||||||
|
class="u-button__text"
|
||||||
|
:style="[
|
||||||
|
{
|
||||||
|
marginLeft: icon ? '2px' : 0,
|
||||||
|
},
|
||||||
|
nvueTextStyle,
|
||||||
|
]"
|
||||||
|
:class="[plain && `u-button__text--plain--${type}`]"
|
||||||
|
>{{ text }}</text
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import button from "../../libs/mixin/button.js";
|
||||||
|
import openType from "../../libs/mixin/openType.js";
|
||||||
|
import props from "./props.js";
|
||||||
|
/**
|
||||||
|
* button 按钮
|
||||||
|
* @description Button 按钮
|
||||||
|
* @tutorial https://www.uviewui.com/components/button.html
|
||||||
|
*
|
||||||
|
* @property {Boolean} hairline 是否显示按钮的细边框 (默认 true )
|
||||||
|
* @property {String} type 按钮的预置样式,info,primary,error,warning,success (默认 'info' )
|
||||||
|
* @property {String} size 按钮尺寸,large,normal,mini (默认 normal)
|
||||||
|
* @property {String} shape 按钮形状,circle(两边为半圆),square(带圆角) (默认 'square' )
|
||||||
|
* @property {Boolean} plain 按钮是否镂空,背景色透明 (默认 false)
|
||||||
|
* @property {Boolean} disabled 是否禁用 (默认 false)
|
||||||
|
* @property {Boolean} loading 按钮名称前是否带 loading 图标(App-nvue 平台,在 ios 上为雪花,Android上为圆圈) (默认 false)
|
||||||
|
* @property {String | Number} loadingText 加载中提示文字
|
||||||
|
* @property {String} loadingMode 加载状态图标类型 (默认 'spinner' )
|
||||||
|
* @property {String | Number} loadingSize 加载图标大小 (默认 15 )
|
||||||
|
* @property {String} openType 开放能力,具体请看uniapp稳定关于button组件部分说明
|
||||||
|
* @property {String} formType 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
|
||||||
|
* @property {String} appParameter 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效 (注:只微信小程序、QQ小程序有效)
|
||||||
|
* @property {Boolean} hoverStopPropagation 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效(默认 true )
|
||||||
|
* @property {String} lang 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文(默认 en )
|
||||||
|
* @property {String} sessionFrom 会话来源,openType="contact"时有效
|
||||||
|
* @property {String} sendMessageTitle 会话内消息卡片标题,openType="contact"时有效
|
||||||
|
* @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径,openType="contact"时有效
|
||||||
|
* @property {String} sendMessageImg 会话内消息卡片图片,openType="contact"时有效
|
||||||
|
* @property {Boolean} showMessageCard 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,用户点击后可以快速发送小程序消息,openType="contact"时有效(默认false)
|
||||||
|
* @property {String} dataName 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
|
||||||
|
* @property {String | Number} throttleTime 节流,一定时间内只能触发一次 (默认 0 )
|
||||||
|
* @property {String | Number} hoverStartTime 按住后多久出现点击态,单位毫秒 (默认 0 )
|
||||||
|
* @property {String | Number} hoverStayTime 手指松开后点击态保留时间,单位毫秒 (默认 200 )
|
||||||
|
* @property {String | Number} text 按钮文字,之所以通过props传入,是因为slot传入的话(注:nvue中无法控制文字的样式)
|
||||||
|
* @property {String} icon 按钮图标
|
||||||
|
* @property {String} iconColor 按钮图标颜色
|
||||||
|
* @property {String} color 按钮颜色,支持传入linear-gradient渐变色
|
||||||
|
* @property {Object} customStyle 定义需要用到的外部样式
|
||||||
|
*
|
||||||
|
* @event {Function} click 非禁止并且非加载中,才能点击
|
||||||
|
* @event {Function} getphonenumber open-type="getPhoneNumber"时有效
|
||||||
|
* @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,从返回参数的detail中获取到的值同uni.getUserInfo
|
||||||
|
* @event {Function} error 当使用开放能力时,发生错误的回调
|
||||||
|
* @event {Function} opensetting 在打开授权设置页并关闭后回调
|
||||||
|
* @event {Function} launchapp 打开 APP 成功的回调
|
||||||
|
* @event {Function} agreeprivacyauthorization 用户同意隐私协议事件回调
|
||||||
|
* @example <u-button>月落</u-button>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-button",
|
||||||
|
// #ifdef MP
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin, button, openType, props],
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
|
||||||
|
// #endif
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 生成bem风格的类名
|
||||||
|
bemClass() {
|
||||||
|
// this.bem为一个computed变量,在mixin中
|
||||||
|
if (!this.color) {
|
||||||
|
return this.bem(
|
||||||
|
"button",
|
||||||
|
["type", "shape", "size"],
|
||||||
|
["disabled", "plain", "hairline"]
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 由于nvue的原因,在有color参数时,不需要传入type,否则会生成type相关的类型,影响最终的样式
|
||||||
|
return this.bem(
|
||||||
|
"button",
|
||||||
|
["shape", "size"],
|
||||||
|
["disabled", "plain", "hairline"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loadingColor() {
|
||||||
|
if (this.plain) {
|
||||||
|
// 如果有设置color值,则用color值,否则使用type主题颜色
|
||||||
|
return this.color
|
||||||
|
? this.color
|
||||||
|
: uni.$u.config.color[`u-${this.type}`];
|
||||||
|
}
|
||||||
|
if (this.type === "info") {
|
||||||
|
return "#c9c9c9";
|
||||||
|
}
|
||||||
|
return "rgb(200, 200, 200)";
|
||||||
|
},
|
||||||
|
iconColorCom() {
|
||||||
|
// 如果是镂空状态,设置了color就用color值,否则使用主题颜色,
|
||||||
|
// u-icon的color能接受一个主题颜色的值
|
||||||
|
if (this.iconColor) return this.iconColor;
|
||||||
|
if (this.plain) {
|
||||||
|
return this.color ? this.color : this.type;
|
||||||
|
} else {
|
||||||
|
return this.type === "info" ? "#000000" : "#ffffff";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
baseColor() {
|
||||||
|
let style = {};
|
||||||
|
if (this.color) {
|
||||||
|
// 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色
|
||||||
|
style.color = this.plain ? this.color : "white";
|
||||||
|
if (!this.plain) {
|
||||||
|
// 非镂空,背景色使用自定义的颜色
|
||||||
|
style["background-color"] = this.color;
|
||||||
|
}
|
||||||
|
if (this.color.indexOf("gradient") !== -1) {
|
||||||
|
// 如果自定义的颜色为渐变色,不显示边框,以及通过backgroundImage设置渐变色
|
||||||
|
// weex文档说明可以写borderWidth的形式,为什么这里需要分开写?
|
||||||
|
// 因为weex是阿里巴巴为了部门业绩考核而做的你懂的东西,所以需要这么写才有效
|
||||||
|
style.borderTopWidth = 0;
|
||||||
|
style.borderRightWidth = 0;
|
||||||
|
style.borderBottomWidth = 0;
|
||||||
|
style.borderLeftWidth = 0;
|
||||||
|
if (!this.plain) {
|
||||||
|
style.backgroundImage = this.color;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 非渐变色,则设置边框相关的属性
|
||||||
|
style.borderColor = this.color;
|
||||||
|
style.borderWidth = "1px";
|
||||||
|
style.borderStyle = "solid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
// nvue版本按钮的字体不会继承父组件的颜色,需要对每一个text组件进行单独的设置
|
||||||
|
nvueTextStyle() {
|
||||||
|
let style = {};
|
||||||
|
// 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色
|
||||||
|
if (this.type === "info") {
|
||||||
|
style.color = "#323233";
|
||||||
|
}
|
||||||
|
if (this.color) {
|
||||||
|
style.color = this.plain ? this.color : "white";
|
||||||
|
}
|
||||||
|
style.fontSize = this.textSize + "px";
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
// 字体大小
|
||||||
|
textSize() {
|
||||||
|
let fontSize = 14,
|
||||||
|
{ size } = this;
|
||||||
|
if (size === "large") fontSize = 16;
|
||||||
|
if (size === "normal") fontSize = 14;
|
||||||
|
if (size === "small") fontSize = 12;
|
||||||
|
if (size === "mini") fontSize = 10;
|
||||||
|
return fontSize;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clickHandler() {
|
||||||
|
// 非禁止并且非加载中,才能点击
|
||||||
|
if (!this.disabled && !this.loading) {
|
||||||
|
// 进行节流控制,每this.throttle毫秒内,只在开始处执行
|
||||||
|
uni.$u.throttle(() => {
|
||||||
|
this.$emit("click");
|
||||||
|
}, this.throttleTime);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 下面为对接uniapp官方按钮开放能力事件回调的对接
|
||||||
|
getphonenumber(res) {
|
||||||
|
this.$emit("getphonenumber", res);
|
||||||
|
},
|
||||||
|
getuserinfo(res) {
|
||||||
|
this.$emit("getuserinfo", res);
|
||||||
|
},
|
||||||
|
error(res) {
|
||||||
|
this.$emit("error", res);
|
||||||
|
},
|
||||||
|
opensetting(res) {
|
||||||
|
this.$emit("opensetting", res);
|
||||||
|
},
|
||||||
|
launchapp(res) {
|
||||||
|
this.$emit("launchapp", res);
|
||||||
|
},
|
||||||
|
agreeprivacyauthorization(res) {
|
||||||
|
this.$emit("agreeprivacyauthorization", res);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
@import "./vue.scss";
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
/* #ifdef APP-NVUE */
|
||||||
|
@import "./nvue.scss";
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
$u-button-u-button-height: 40px !default;
|
||||||
|
$u-button-text-font-size: 15px !default;
|
||||||
|
$u-button-loading-text-font-size: 15px !default;
|
||||||
|
$u-button-loading-text-margin-left: 4px !default;
|
||||||
|
$u-button-large-width: 100% !default;
|
||||||
|
$u-button-large-height: 50px !default;
|
||||||
|
$u-button-normal-padding: 0 12px !default;
|
||||||
|
$u-button-large-padding: 0 15px !default;
|
||||||
|
$u-button-normal-font-size: 14px !default;
|
||||||
|
$u-button-small-min-width: 60px !default;
|
||||||
|
$u-button-small-height: 30px !default;
|
||||||
|
$u-button-small-padding: 0px 8px !default;
|
||||||
|
$u-button-mini-padding: 0px 8px !default;
|
||||||
|
$u-button-small-font-size: 12px !default;
|
||||||
|
$u-button-mini-height: 22px !default;
|
||||||
|
$u-button-mini-font-size: 10px !default;
|
||||||
|
$u-button-mini-min-width: 50px !default;
|
||||||
|
$u-button-disabled-opacity: 0.5 !default;
|
||||||
|
$u-button-info-color: #323233 !default;
|
||||||
|
$u-button-info-background-color: #fff !default;
|
||||||
|
$u-button-info-border-color: #ebedf0 !default;
|
||||||
|
$u-button-info-border-width: 1px !default;
|
||||||
|
$u-button-info-border-style: solid !default;
|
||||||
|
$u-button-success-color: #fff !default;
|
||||||
|
$u-button-success-background-color: $u-success !default;
|
||||||
|
$u-button-success-border-color: $u-button-success-background-color !default;
|
||||||
|
$u-button-success-border-width: 1px !default;
|
||||||
|
$u-button-success-border-style: solid !default;
|
||||||
|
$u-button-primary-color: #fff !default;
|
||||||
|
$u-button-primary-background-color: $u-primary !default;
|
||||||
|
$u-button-primary-border-color: $u-button-primary-background-color !default;
|
||||||
|
$u-button-primary-border-width: 1px !default;
|
||||||
|
$u-button-primary-border-style: solid !default;
|
||||||
|
$u-button-error-color: #fff !default;
|
||||||
|
$u-button-error-background-color: $u-error !default;
|
||||||
|
$u-button-error-border-color: $u-button-error-background-color !default;
|
||||||
|
$u-button-error-border-width: 1px !default;
|
||||||
|
$u-button-error-border-style: solid !default;
|
||||||
|
$u-button-warning-color: #fff !default;
|
||||||
|
$u-button-warning-background-color: $u-warning !default;
|
||||||
|
$u-button-warning-border-color: $u-button-warning-background-color !default;
|
||||||
|
$u-button-warning-border-width: 1px !default;
|
||||||
|
$u-button-warning-border-style: solid !default;
|
||||||
|
$u-button-block-width: 100% !default;
|
||||||
|
$u-button-circle-border-top-right-radius: 100px !default;
|
||||||
|
$u-button-circle-border-top-left-radius: 100px !default;
|
||||||
|
$u-button-circle-border-bottom-left-radius: 100px !default;
|
||||||
|
$u-button-circle-border-bottom-right-radius: 100px !default;
|
||||||
|
$u-button-square-border-top-right-radius: 3px !default;
|
||||||
|
$u-button-square-border-top-left-radius: 3px !default;
|
||||||
|
$u-button-square-border-bottom-left-radius: 3px !default;
|
||||||
|
$u-button-square-border-bottom-right-radius: 3px !default;
|
||||||
|
$u-button-icon-min-width: 1em !default;
|
||||||
|
$u-button-plain-background-color: #fff !default;
|
||||||
|
$u-button-hairline-border-width: 0.5px !default;
|
||||||
|
|
||||||
|
.u-button {
|
||||||
|
height: $u-button-u-button-height;
|
||||||
|
position: relative;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
@include flex;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* #endif */
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
font-size: $u-button-text-font-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__loading-text {
|
||||||
|
font-size: $u-button-loading-text-font-size;
|
||||||
|
margin-left: $u-button-loading-text-margin-left;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--large {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
width: $u-button-large-width;
|
||||||
|
/* #endif */
|
||||||
|
height: $u-button-large-height;
|
||||||
|
padding: $u-button-large-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--normal {
|
||||||
|
padding: $u-button-normal-padding;
|
||||||
|
font-size: $u-button-normal-font-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--small {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
min-width: $u-button-small-min-width;
|
||||||
|
/* #endif */
|
||||||
|
height: $u-button-small-height;
|
||||||
|
padding: $u-button-small-padding;
|
||||||
|
font-size: $u-button-small-font-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--mini {
|
||||||
|
height: $u-button-mini-height;
|
||||||
|
font-size: $u-button-mini-font-size;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
min-width: $u-button-mini-min-width;
|
||||||
|
/* #endif */
|
||||||
|
padding: $u-button-mini-padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
opacity: $u-button-disabled-opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--info {
|
||||||
|
color: $u-button-info-color;
|
||||||
|
background-color: $u-button-info-background-color;
|
||||||
|
border-color: $u-button-info-border-color;
|
||||||
|
border-width: $u-button-info-border-width;
|
||||||
|
border-style: $u-button-info-border-style;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--success {
|
||||||
|
color: $u-button-success-color;
|
||||||
|
background-color: $u-button-success-background-color;
|
||||||
|
border-color: $u-button-success-border-color;
|
||||||
|
border-width: $u-button-success-border-width;
|
||||||
|
border-style: $u-button-success-border-style;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--primary {
|
||||||
|
color: $u-button-primary-color;
|
||||||
|
background-color: $u-button-primary-background-color;
|
||||||
|
border-color: $u-button-primary-border-color;
|
||||||
|
border-width: $u-button-primary-border-width;
|
||||||
|
border-style: $u-button-primary-border-style;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error {
|
||||||
|
color: $u-button-error-color;
|
||||||
|
background-color: $u-button-error-background-color;
|
||||||
|
border-color: $u-button-error-border-color;
|
||||||
|
border-width: $u-button-error-border-width;
|
||||||
|
border-style: $u-button-error-border-style;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--warning {
|
||||||
|
color: $u-button-warning-color;
|
||||||
|
background-color: $u-button-warning-background-color;
|
||||||
|
border-color: $u-button-warning-border-color;
|
||||||
|
border-width: $u-button-warning-border-width;
|
||||||
|
border-style: $u-button-warning-border-style;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--block {
|
||||||
|
@include flex;
|
||||||
|
width: $u-button-block-width;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--circle {
|
||||||
|
border-top-right-radius: $u-button-circle-border-top-right-radius;
|
||||||
|
border-top-left-radius: $u-button-circle-border-top-left-radius;
|
||||||
|
border-bottom-left-radius: $u-button-circle-border-bottom-left-radius;
|
||||||
|
border-bottom-right-radius: $u-button-circle-border-bottom-right-radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--square {
|
||||||
|
border-bottom-left-radius: $u-button-square-border-top-right-radius;
|
||||||
|
border-bottom-right-radius: $u-button-square-border-top-left-radius;
|
||||||
|
border-top-left-radius: $u-button-square-border-bottom-left-radius;
|
||||||
|
border-top-right-radius: $u-button-square-border-bottom-right-radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
min-width: $u-button-icon-min-width;
|
||||||
|
line-height: inherit !important;
|
||||||
|
vertical-align: top;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
&--plain {
|
||||||
|
background-color: $u-button-plain-background-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--hairline {
|
||||||
|
border-width: $u-button-hairline-border-width !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,80 @@
|
||||||
|
// nvue下hover-class无效
|
||||||
|
$u-button-before-top:50% !default;
|
||||||
|
$u-button-before-left:50% !default;
|
||||||
|
$u-button-before-width:100% !default;
|
||||||
|
$u-button-before-height:100% !default;
|
||||||
|
$u-button-before-transform:translate(-50%, -50%) !default;
|
||||||
|
$u-button-before-opacity:0 !default;
|
||||||
|
$u-button-before-background-color:#000 !default;
|
||||||
|
$u-button-before-border-color:#000 !default;
|
||||||
|
$u-button-active-before-opacity:.15 !default;
|
||||||
|
$u-button-icon-margin-left:4px !default;
|
||||||
|
$u-button-plain-u-button-info-color:$u-info;
|
||||||
|
$u-button-plain-u-button-success-color:$u-success;
|
||||||
|
$u-button-plain-u-button-error-color:$u-error;
|
||||||
|
$u-button-plain-u-button-warning-color:$u-error;
|
||||||
|
|
||||||
|
.u-button {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
white-space: nowrap;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
position: absolute;
|
||||||
|
top:$u-button-before-top;
|
||||||
|
left:$u-button-before-left;
|
||||||
|
width:$u-button-before-width;
|
||||||
|
height:$u-button-before-height;
|
||||||
|
border: inherit;
|
||||||
|
border-radius: inherit;
|
||||||
|
transform:$u-button-before-transform;
|
||||||
|
opacity:$u-button-before-opacity;
|
||||||
|
content: " ";
|
||||||
|
background-color:$u-button-before-background-color;
|
||||||
|
border-color:$u-button-before-border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
&:before {
|
||||||
|
opacity: .15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon+&__text:not(:empty),
|
||||||
|
&__loading-text {
|
||||||
|
margin-left:$u-button-icon-margin-left;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--plain {
|
||||||
|
&.u-button--primary {
|
||||||
|
color: $u-primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--plain {
|
||||||
|
&.u-button--info {
|
||||||
|
color:$u-button-plain-u-button-info-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--plain {
|
||||||
|
&.u-button--success {
|
||||||
|
color:$u-button-plain-u-button-success-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--plain {
|
||||||
|
&.u-button--error {
|
||||||
|
color:$u-button-plain-u-button-error-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--plain {
|
||||||
|
&.u-button--warning {
|
||||||
|
color:$u-button-plain-u-button-warning-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
<template>
|
||||||
|
<view class="u-calendar-header u-border-bottom">
|
||||||
|
<text
|
||||||
|
class="u-calendar-header__title"
|
||||||
|
v-if="showTitle"
|
||||||
|
>{{ title }}</text>
|
||||||
|
<text
|
||||||
|
class="u-calendar-header__subtitle"
|
||||||
|
v-if="showSubtitle"
|
||||||
|
>{{ subtitle }}</text>
|
||||||
|
<view class="u-calendar-header__weekdays">
|
||||||
|
<text class="u-calendar-header__weekdays__weekday">一</text>
|
||||||
|
<text class="u-calendar-header__weekdays__weekday">二</text>
|
||||||
|
<text class="u-calendar-header__weekdays__weekday">三</text>
|
||||||
|
<text class="u-calendar-header__weekdays__weekday">四</text>
|
||||||
|
<text class="u-calendar-header__weekdays__weekday">五</text>
|
||||||
|
<text class="u-calendar-header__weekdays__weekday">六</text>
|
||||||
|
<text class="u-calendar-header__weekdays__weekday">日</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'u-calendar-header',
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin],
|
||||||
|
props: {
|
||||||
|
// 标题
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 副标题
|
||||||
|
subtitle: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否显示标题
|
||||||
|
showTitle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示副标题
|
||||||
|
showSubtitle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
name() {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
|
.u-calendar-header {
|
||||||
|
padding-bottom: 4px;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: 16px;
|
||||||
|
color: $u-main-color;
|
||||||
|
text-align: center;
|
||||||
|
height: 42px;
|
||||||
|
line-height: 42px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
color: $u-main-color;
|
||||||
|
height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 40px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__weekdays {
|
||||||
|
@include flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&__weekday {
|
||||||
|
font-size: 13px;
|
||||||
|
color: $u-main-color;
|
||||||
|
line-height: 30px;
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,579 @@
|
||||||
|
<template>
|
||||||
|
<view class="u-calendar-month-wrapper" ref="u-calendar-month-wrapper">
|
||||||
|
<view v-for="(item, index) in months" :key="index" :class="[`u-calendar-month-${index}`]"
|
||||||
|
:ref="`u-calendar-month-${index}`" :id="`month-${index}`">
|
||||||
|
<text v-if="index !== 0" class="u-calendar-month__title">{{ item.year }}年{{ item.month }}月</text>
|
||||||
|
<view class="u-calendar-month__days">
|
||||||
|
<view v-if="showMark" class="u-calendar-month__days__month-mark-wrapper">
|
||||||
|
<text class="u-calendar-month__days__month-mark-wrapper__text">{{ item.month }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="u-calendar-month__days__day" v-for="(item1, index1) in item.date" :key="index1"
|
||||||
|
:style="[dayStyle(index, index1, item1)]" @tap="clickHandler(index, index1, item1)"
|
||||||
|
:class="[item1.selected && 'u-calendar-month__days__day__select--selected']">
|
||||||
|
<view class="u-calendar-month__days__day__select" :style="[daySelectStyle(index, index1, item1)]">
|
||||||
|
<text class="u-calendar-month__days__day__select__info"
|
||||||
|
:class="[item1.disabled && 'u-calendar-month__days__day__select__info--disabled']"
|
||||||
|
:style="[textStyle(item1)]">{{ item1.day }}</text>
|
||||||
|
<text v-if="getBottomInfo(index, index1, item1)"
|
||||||
|
class="u-calendar-month__days__day__select__buttom-info"
|
||||||
|
:class="[item1.disabled && 'u-calendar-month__days__day__select__buttom-info--disabled']"
|
||||||
|
:style="[textStyle(item1)]">{{ getBottomInfo(index, index1, item1) }}</text>
|
||||||
|
<text v-if="item1.dot" class="u-calendar-month__days__day__select__dot"></text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
// 由于nvue不支持百分比单位,需要查询宽度来计算每个日期的宽度
|
||||||
|
const dom = uni.requireNativePlugin('dom')
|
||||||
|
// #endif
|
||||||
|
import dayjs from '../../libs/util/dayjs.js';
|
||||||
|
export default {
|
||||||
|
name: 'u-calendar-month',
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin],
|
||||||
|
props: {
|
||||||
|
// 是否显示月份背景色
|
||||||
|
showMark: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 主题色,对底部按钮和选中日期有效
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#3c9cff'
|
||||||
|
},
|
||||||
|
// 月份数据
|
||||||
|
months: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
// 日期选择类型
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'single'
|
||||||
|
},
|
||||||
|
// 日期行高
|
||||||
|
rowHeight: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 58
|
||||||
|
},
|
||||||
|
// mode=multiple时,最多可选多少个日期
|
||||||
|
maxCount: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: Infinity
|
||||||
|
},
|
||||||
|
// mode=range时,第一个日期底部的提示文字
|
||||||
|
startText: {
|
||||||
|
type: String,
|
||||||
|
default: '开始'
|
||||||
|
},
|
||||||
|
// mode=range时,最后一个日期底部的提示文字
|
||||||
|
endText: {
|
||||||
|
type: String,
|
||||||
|
default: '结束'
|
||||||
|
},
|
||||||
|
// 默认选中的日期,mode为multiple或range是必须为数组格式
|
||||||
|
defaultDate: {
|
||||||
|
type: [Array, String, Date],
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
// 最小的可选日期
|
||||||
|
minDate: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 最大可选日期
|
||||||
|
maxDate: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 如果没有设置maxDate,则往后推多少个月
|
||||||
|
maxMonth: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 2
|
||||||
|
},
|
||||||
|
// 是否为只读状态,只读状态下禁止选择日期
|
||||||
|
readonly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.calendar.readonly
|
||||||
|
},
|
||||||
|
// 日期区间最多可选天数,默认无限制,mode = range时有效
|
||||||
|
maxRange: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: Infinity
|
||||||
|
},
|
||||||
|
// 范围选择超过最多可选天数时的提示文案,mode = range时有效
|
||||||
|
rangePrompt: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效
|
||||||
|
showRangePrompt: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否允许日期范围的起止时间为同一天,mode = range时有效
|
||||||
|
allowSameDay: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 每个日期的宽度
|
||||||
|
width: 0,
|
||||||
|
// 当前选中的日期item
|
||||||
|
item: {},
|
||||||
|
selected: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
selectedChange: {
|
||||||
|
immediate: true,
|
||||||
|
handler(n) {
|
||||||
|
this.setDefaultDate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 多个条件的变化,会引起选中日期的变化,这里统一管理监听
|
||||||
|
selectedChange() {
|
||||||
|
return [this.minDate, this.maxDate, this.defaultDate]
|
||||||
|
},
|
||||||
|
dayStyle(index1, index2, item) {
|
||||||
|
return (index1, index2, item) => {
|
||||||
|
const style = {}
|
||||||
|
let week = item.week
|
||||||
|
// 不进行四舍五入的形式保留2位小数
|
||||||
|
const dayWidth = Number(parseFloat(this.width / 7).toFixed(3).slice(0, -1))
|
||||||
|
// 得出每个日期的宽度
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
style.width = uni.$u.addUnit(dayWidth)
|
||||||
|
// #endif
|
||||||
|
style.height = uni.$u.addUnit(this.rowHeight)
|
||||||
|
if (index2 === 0) {
|
||||||
|
// 获取当前为星期几,如果为0,则为星期天,减一为每月第一天时,需要向左偏移的item个数
|
||||||
|
week = (week === 0 ? 7 : week) - 1
|
||||||
|
style.marginLeft = uni.$u.addUnit(week * dayWidth)
|
||||||
|
}
|
||||||
|
if (this.mode === 'range') {
|
||||||
|
// 之所以需要这么写,是因为DCloud公司的iOS客户端的开发者能力有限导致的bug
|
||||||
|
style.paddingLeft = 0
|
||||||
|
style.paddingRight = 0
|
||||||
|
style.paddingBottom = 0
|
||||||
|
style.paddingTop = 0
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
},
|
||||||
|
daySelectStyle() {
|
||||||
|
return (index1, index2, item) => {
|
||||||
|
let date = dayjs(item.date).format("YYYY-MM-DD"),
|
||||||
|
style = {}
|
||||||
|
// 判断date是否在selected数组中,因为月份可能会需要补0,所以使用dateSame判断,而不用数组的includes判断
|
||||||
|
if (this.selected.some(item => this.dateSame(item, date))) {
|
||||||
|
style.backgroundColor = this.color
|
||||||
|
}
|
||||||
|
if (this.mode === 'single') {
|
||||||
|
if (date === this.selected[0]) {
|
||||||
|
// 因为需要对nvue的兼容,只能这么写,无法缩写,也无法通过类名控制等等
|
||||||
|
style.borderTopLeftRadius = '3px'
|
||||||
|
style.borderBottomLeftRadius = '3px'
|
||||||
|
style.borderTopRightRadius = '3px'
|
||||||
|
style.borderBottomRightRadius = '3px'
|
||||||
|
}
|
||||||
|
} else if (this.mode === 'range') {
|
||||||
|
if (this.selected.length >= 2) {
|
||||||
|
const len = this.selected.length - 1
|
||||||
|
// 第一个日期设置左上角和左下角的圆角
|
||||||
|
if (this.dateSame(date, this.selected[0])) {
|
||||||
|
style.borderTopLeftRadius = '3px'
|
||||||
|
style.borderBottomLeftRadius = '3px'
|
||||||
|
}
|
||||||
|
// 最后一个日期设置右上角和右下角的圆角
|
||||||
|
if (this.dateSame(date, this.selected[len])) {
|
||||||
|
style.borderTopRightRadius = '3px'
|
||||||
|
style.borderBottomRightRadius = '3px'
|
||||||
|
}
|
||||||
|
// 处于第一和最后一个之间的日期,背景色设置为浅色,通过将对应颜色进行等分,再取其尾部的颜色值
|
||||||
|
if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
|
||||||
|
.selected[len]))) {
|
||||||
|
style.backgroundColor = uni.$u.colorGradient(this.color, '#ffffff', 100)[90]
|
||||||
|
// 增加一个透明度,让范围区间的背景色也能看到底部的mark水印字符
|
||||||
|
style.opacity = 0.7
|
||||||
|
}
|
||||||
|
} else if (this.selected.length === 1) {
|
||||||
|
// 之所以需要这么写,是因为DCloud公司的iOS客户端的开发者能力有限导致的bug
|
||||||
|
// 进行还原操作,否则在nvue的iOS,uni-app有bug,会导致诡异的表现
|
||||||
|
style.borderTopLeftRadius = '3px'
|
||||||
|
style.borderBottomLeftRadius = '3px'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.selected.some(item => this.dateSame(item, date))) {
|
||||||
|
style.borderTopLeftRadius = '3px'
|
||||||
|
style.borderBottomLeftRadius = '3px'
|
||||||
|
style.borderTopRightRadius = '3px'
|
||||||
|
style.borderBottomRightRadius = '3px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 某个日期是否被选中
|
||||||
|
textStyle() {
|
||||||
|
return (item) => {
|
||||||
|
const date = dayjs(item.date).format("YYYY-MM-DD"),
|
||||||
|
style = {}
|
||||||
|
// 选中的日期,提示文字设置白色
|
||||||
|
if (this.selected.some(item => this.dateSame(item, date))) {
|
||||||
|
style.color = '#ffffff'
|
||||||
|
}
|
||||||
|
if (this.mode === 'range') {
|
||||||
|
const len = this.selected.length - 1
|
||||||
|
// 如果是范围选择模式,第一个和最后一个之间的日期,文字颜色设置为高亮的主题色
|
||||||
|
if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
|
||||||
|
.selected[len]))) {
|
||||||
|
style.color = this.color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 获取底部的提示文字
|
||||||
|
getBottomInfo() {
|
||||||
|
return (index1, index2, item) => {
|
||||||
|
const date = dayjs(item.date).format("YYYY-MM-DD")
|
||||||
|
const bottomInfo = item.bottomInfo
|
||||||
|
// 当为日期范围模式时,且选择的日期个数大于0时
|
||||||
|
if (this.mode === 'range' && this.selected.length > 0) {
|
||||||
|
if (this.selected.length === 1) {
|
||||||
|
// 选择了一个日期时,如果当前日期为数组中的第一个日期,则显示底部文字为“开始”
|
||||||
|
if (this.dateSame(date, this.selected[0])) return this.startText
|
||||||
|
else return bottomInfo
|
||||||
|
} else {
|
||||||
|
const len = this.selected.length - 1
|
||||||
|
// 如果数组中的日期大于2个时,第一个和最后一个显示为开始和结束日期
|
||||||
|
if (this.dateSame(date, this.selected[0]) && this.dateSame(date, this.selected[1]) &&
|
||||||
|
len === 1) {
|
||||||
|
// 如果长度为2,且第一个等于第二个日期,则提示语放在同一个item中
|
||||||
|
return `${this.startText}/${this.endText}`
|
||||||
|
} else if (this.dateSame(date, this.selected[0])) {
|
||||||
|
return this.startText
|
||||||
|
} else if (this.dateSame(date, this.selected[len])) {
|
||||||
|
return this.endText
|
||||||
|
} else {
|
||||||
|
return bottomInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return bottomInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
// 初始化默认选中
|
||||||
|
this.$emit('monthSelected', this.selected)
|
||||||
|
this.$nextTick(() => {
|
||||||
|
// 这里需要另一个延时,因为获取宽度后,会进行月份数据渲染,只有渲染完成之后,才有真正的高度
|
||||||
|
// 因为nvue下,$nextTick并不是100%可靠的
|
||||||
|
uni.$u.sleep(10).then(() => {
|
||||||
|
this.getWrapperWidth()
|
||||||
|
this.getMonthRect()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 判断两个日期是否相等
|
||||||
|
dateSame(date1, date2) {
|
||||||
|
return dayjs(date1).isSame(dayjs(date2))
|
||||||
|
},
|
||||||
|
// 获取月份数据区域的宽度,因为nvue不支持百分比,所以无法通过css设置每个日期item的宽度
|
||||||
|
getWrapperWidth() {
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
dom.getComponentRect(this.$refs['u-calendar-month-wrapper'], res => {
|
||||||
|
this.width = res.size.width
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
this.$uGetRect('.u-calendar-month-wrapper').then(size => {
|
||||||
|
this.width = size.width
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
getMonthRect() {
|
||||||
|
// 获取每个月份数据的尺寸,用于父组件在scroll-view滚动事件中,监听当前滚动到了第几个月份
|
||||||
|
const promiseAllArr = this.months.map((item, index) => this.getMonthRectByPromise(
|
||||||
|
`u-calendar-month-${index}`))
|
||||||
|
// 一次性返回
|
||||||
|
Promise.all(promiseAllArr).then(
|
||||||
|
sizes => {
|
||||||
|
let height = 1
|
||||||
|
const topArr = []
|
||||||
|
for (let i = 0; i < this.months.length; i++) {
|
||||||
|
// 添加到months数组中,供scroll-view滚动事件中,判断当前滚动到哪个月份
|
||||||
|
topArr[i] = height
|
||||||
|
height += sizes[i].height
|
||||||
|
}
|
||||||
|
// 由于微信下,无法通过this.months[i].top的形式(引用类型)去修改父组件的month的top值,所以使用事件形式对外发出
|
||||||
|
this.$emit('updateMonthTop', topArr)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 获取每个月份区域的尺寸
|
||||||
|
getMonthRectByPromise(el) {
|
||||||
|
// #ifndef APP-NVUE
|
||||||
|
// $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://www.uviewui.com/js/getRect.html
|
||||||
|
// 组件内部一般用this.$uGetRect,对外的为uni.$u.getRect,二者功能一致,名称不同
|
||||||
|
return new Promise(resolve => {
|
||||||
|
this.$uGetRect(`.${el}`).then(size => {
|
||||||
|
resolve(size)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
// nvue下,使用dom模块查询元素高度
|
||||||
|
// 返回一个promise,让调用此方法的主体能使用then回调
|
||||||
|
return new Promise(resolve => {
|
||||||
|
dom.getComponentRect(this.$refs[el][0], res => {
|
||||||
|
resolve(res.size)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
},
|
||||||
|
// 点击某一个日期
|
||||||
|
clickHandler(index1, index2, item) {
|
||||||
|
if (this.readonly) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.item = item
|
||||||
|
const date = dayjs(item.date).format("YYYY-MM-DD")
|
||||||
|
if (item.disabled) return
|
||||||
|
// 对上一次选择的日期数组进行深度克隆
|
||||||
|
let selected = uni.$u.deepClone(this.selected)
|
||||||
|
if (this.mode === 'single') {
|
||||||
|
// 单选情况下,让数组中的元素为当前点击的日期
|
||||||
|
selected = [date]
|
||||||
|
} else if (this.mode === 'multiple') {
|
||||||
|
if (selected.some(item => this.dateSame(item, date))) {
|
||||||
|
// 如果点击的日期已在数组中,则进行移除操作,也就是达到反选的效果
|
||||||
|
const itemIndex = selected.findIndex(item => item === date)
|
||||||
|
selected.splice(itemIndex, 1)
|
||||||
|
} else {
|
||||||
|
// 如果点击的日期不在数组中,且已有的长度小于总可选长度时,则添加到数组中去
|
||||||
|
if (selected.length < this.maxCount) selected.push(date)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 选择区间形式
|
||||||
|
if (selected.length === 0 || selected.length >= 2) {
|
||||||
|
// 如果原来就为0或者大于2的长度,则当前点击的日期,就是开始日期
|
||||||
|
selected = [date]
|
||||||
|
} else if (selected.length === 1) {
|
||||||
|
// 如果已经选择了开始日期
|
||||||
|
const existsDate = selected[0]
|
||||||
|
// 如果当前选择的日期小于上一次选择的日期,则当前的日期定为开始日期
|
||||||
|
if (dayjs(date).isBefore(existsDate)) {
|
||||||
|
selected = [date]
|
||||||
|
} else if (dayjs(date).isAfter(existsDate)) {
|
||||||
|
// 当前日期减去最大可选的日期天数,如果大于起始时间,则进行提示
|
||||||
|
if(dayjs(dayjs(date).subtract(this.maxRange, 'day')).isAfter(dayjs(selected[0])) && this.showRangePrompt) {
|
||||||
|
if(this.rangePrompt) {
|
||||||
|
uni.$u.toast(this.rangePrompt)
|
||||||
|
} else {
|
||||||
|
uni.$u.toast(`选择天数不能超过 ${this.maxRange} 天`)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 如果当前日期大于已有日期,将当前的添加到数组尾部
|
||||||
|
selected.push(date)
|
||||||
|
const startDate = selected[0]
|
||||||
|
const endDate = selected[1]
|
||||||
|
const arr = []
|
||||||
|
let i = 0
|
||||||
|
do {
|
||||||
|
// 将开始和结束日期之间的日期添加到数组中
|
||||||
|
arr.push(dayjs(startDate).add(i, 'day').format("YYYY-MM-DD"))
|
||||||
|
i++
|
||||||
|
// 累加的日期小于结束日期时,继续下一次的循环
|
||||||
|
} while (dayjs(startDate).add(i, 'day').isBefore(dayjs(endDate)))
|
||||||
|
// 为了一次性修改数组,避免computed中多次触发,这里才用arr变量一次性赋值的方式,同时将最后一个日期添加近来
|
||||||
|
arr.push(endDate)
|
||||||
|
selected = arr
|
||||||
|
} else {
|
||||||
|
// 选择区间时,只有一个日期的情况下,且不允许选择起止为同一天的话,不允许选择自己
|
||||||
|
if (selected[0] === date && !this.allowSameDay) return
|
||||||
|
selected.push(date)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setSelected(selected)
|
||||||
|
},
|
||||||
|
// 设置默认日期
|
||||||
|
setDefaultDate() {
|
||||||
|
if (!this.defaultDate) {
|
||||||
|
// 如果没有设置默认日期,则将当天日期设置为默认选中的日期
|
||||||
|
const selected = [dayjs().format("YYYY-MM-DD")]
|
||||||
|
return this.setSelected(selected, false)
|
||||||
|
}
|
||||||
|
let defaultDate = []
|
||||||
|
const minDate = this.minDate || dayjs().format("YYYY-MM-DD")
|
||||||
|
const maxDate = this.maxDate || dayjs(minDate).add(this.maxMonth - 1, 'month').format("YYYY-MM-DD")
|
||||||
|
if (this.mode === 'single') {
|
||||||
|
// 单选模式,可以是字符串或数组,Date对象等
|
||||||
|
if (!uni.$u.test.array(this.defaultDate)) {
|
||||||
|
defaultDate = [dayjs(this.defaultDate).format("YYYY-MM-DD")]
|
||||||
|
} else {
|
||||||
|
defaultDate = [this.defaultDate[0]]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果为非数组,则不执行
|
||||||
|
if (!uni.$u.test.array(this.defaultDate)) return
|
||||||
|
defaultDate = this.defaultDate
|
||||||
|
}
|
||||||
|
// 过滤用户传递的默认数组,取出只在可允许最大值与最小值之间的元素
|
||||||
|
defaultDate = defaultDate.filter(item => {
|
||||||
|
return dayjs(item).isAfter(dayjs(minDate).subtract(1, 'day')) && dayjs(item).isBefore(dayjs(
|
||||||
|
maxDate).add(1, 'day'))
|
||||||
|
})
|
||||||
|
this.setSelected(defaultDate, false)
|
||||||
|
},
|
||||||
|
setSelected(selected, event = true) {
|
||||||
|
this.selected = selected
|
||||||
|
event && this.$emit('monthSelected', this.selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
|
.u-calendar-month-wrapper {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-calendar-month {
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 42px;
|
||||||
|
height: 42px;
|
||||||
|
color: $u-main-color;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__days {
|
||||||
|
position: relative;
|
||||||
|
@include flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
&__month-mark-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
@include flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
font-size: 155px;
|
||||||
|
color: rgba(231, 232, 234, 0.83);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__day {
|
||||||
|
@include flex;
|
||||||
|
padding: 2px;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
// vue下使用css进行宽度计算,因为某些安卓机会无法进行js获取父元素宽度进行计算得出,会有偏移
|
||||||
|
width: calc(100% / 7);
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
&__select {
|
||||||
|
flex: 1;
|
||||||
|
@include flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&__dot {
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 100px;
|
||||||
|
background-color: $u-error;
|
||||||
|
position: absolute;
|
||||||
|
top: 12px;
|
||||||
|
right: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__buttom-info {
|
||||||
|
color: $u-content-color;
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 5px;
|
||||||
|
font-size: 10px;
|
||||||
|
text-align: center;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
|
||||||
|
&--selected {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
color: #cacbcd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__info {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
|
&--selected {
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
color: #cacbcd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--selected {
|
||||||
|
background-color: $u-primary;
|
||||||
|
@include flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--range-selected {
|
||||||
|
opacity: 0.3;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--range-start-selected {
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
border-bottom-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--range-end-selected {
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,144 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 日历顶部标题
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.calendar.title
|
||||||
|
},
|
||||||
|
// 是否显示标题
|
||||||
|
showTitle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.calendar.showTitle
|
||||||
|
},
|
||||||
|
// 是否显示副标题
|
||||||
|
showSubtitle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.calendar.showSubtitle
|
||||||
|
},
|
||||||
|
// 日期类型选择,single-选择单个日期,multiple-可以选择多个日期,range-选择日期范围
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.calendar.mode
|
||||||
|
},
|
||||||
|
// mode=range时,第一个日期底部的提示文字
|
||||||
|
startText: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.calendar.startText
|
||||||
|
},
|
||||||
|
// mode=range时,最后一个日期底部的提示文字
|
||||||
|
endText: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.calendar.endText
|
||||||
|
},
|
||||||
|
// 自定义列表
|
||||||
|
customList: {
|
||||||
|
type: Array,
|
||||||
|
default: uni.$u.props.calendar.customList
|
||||||
|
},
|
||||||
|
// 主题色,对底部按钮和选中日期有效
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.calendar.color
|
||||||
|
},
|
||||||
|
// 最小的可选日期
|
||||||
|
minDate: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.calendar.minDate
|
||||||
|
},
|
||||||
|
// 最大可选日期
|
||||||
|
maxDate: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.calendar.maxDate
|
||||||
|
},
|
||||||
|
// 默认选中的日期,mode为multiple或range是必须为数组格式
|
||||||
|
defaultDate: {
|
||||||
|
type: [Array, String, Date, null],
|
||||||
|
default: uni.$u.props.calendar.defaultDate
|
||||||
|
},
|
||||||
|
// mode=multiple时,最多可选多少个日期
|
||||||
|
maxCount: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.calendar.maxCount
|
||||||
|
},
|
||||||
|
// 日期行高
|
||||||
|
rowHeight: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.calendar.rowHeight
|
||||||
|
},
|
||||||
|
// 日期格式化函数
|
||||||
|
formatter: {
|
||||||
|
type: [Function, null],
|
||||||
|
default: uni.$u.props.calendar.formatter
|
||||||
|
},
|
||||||
|
// 是否显示农历
|
||||||
|
showLunar: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.calendar.showLunar
|
||||||
|
},
|
||||||
|
// 是否显示月份背景色
|
||||||
|
showMark: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.calendar.showMark
|
||||||
|
},
|
||||||
|
// 确定按钮的文字
|
||||||
|
confirmText: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.calendar.confirmText
|
||||||
|
},
|
||||||
|
// 确认按钮处于禁用状态时的文字
|
||||||
|
confirmDisabledText: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.calendar.confirmDisabledText
|
||||||
|
},
|
||||||
|
// 是否显示日历弹窗
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.calendar.show
|
||||||
|
},
|
||||||
|
// 是否允许点击遮罩关闭日历
|
||||||
|
closeOnClickOverlay: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.calendar.closeOnClickOverlay
|
||||||
|
},
|
||||||
|
// 是否为只读状态,只读状态下禁止选择日期
|
||||||
|
readonly: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.calendar.readonly
|
||||||
|
},
|
||||||
|
// 是否展示确认按钮
|
||||||
|
showConfirm: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.calendar.showConfirm
|
||||||
|
},
|
||||||
|
// 日期区间最多可选天数,默认无限制,mode = range时有效
|
||||||
|
maxRange: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: uni.$u.props.calendar.maxRange
|
||||||
|
},
|
||||||
|
// 范围选择超过最多可选天数时的提示文案,mode = range时有效
|
||||||
|
rangePrompt: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.calendar.rangePrompt
|
||||||
|
},
|
||||||
|
// 范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效
|
||||||
|
showRangePrompt: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.calendar.showRangePrompt
|
||||||
|
},
|
||||||
|
// 是否允许日期范围的起止时间为同一天,mode = range时有效
|
||||||
|
allowSameDay: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.calendar.allowSameDay
|
||||||
|
},
|
||||||
|
// 圆角值
|
||||||
|
round: {
|
||||||
|
type: [Boolean, String, Number],
|
||||||
|
default: uni.$u.props.calendar.round
|
||||||
|
},
|
||||||
|
// 最多展示月份数量
|
||||||
|
monthNum: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,384 @@
|
||||||
|
<template>
|
||||||
|
<u-popup
|
||||||
|
:show="show"
|
||||||
|
mode="bottom"
|
||||||
|
closeable
|
||||||
|
@close="close"
|
||||||
|
:round="round"
|
||||||
|
:closeOnClickOverlay="closeOnClickOverlay"
|
||||||
|
>
|
||||||
|
<view class="u-calendar">
|
||||||
|
<uHeader
|
||||||
|
:title="title"
|
||||||
|
:subtitle="subtitle"
|
||||||
|
:showSubtitle="showSubtitle"
|
||||||
|
:showTitle="showTitle"
|
||||||
|
></uHeader>
|
||||||
|
<scroll-view
|
||||||
|
:style="{
|
||||||
|
height: $u.addUnit(listHeight)
|
||||||
|
}"
|
||||||
|
scroll-y
|
||||||
|
@scroll="onScroll"
|
||||||
|
:scroll-top="scrollTop"
|
||||||
|
:scrollIntoView="scrollIntoView"
|
||||||
|
>
|
||||||
|
<uMonth
|
||||||
|
:color="color"
|
||||||
|
:rowHeight="rowHeight"
|
||||||
|
:showMark="showMark"
|
||||||
|
:months="months"
|
||||||
|
:mode="mode"
|
||||||
|
:maxCount="maxCount"
|
||||||
|
:startText="startText"
|
||||||
|
:endText="endText"
|
||||||
|
:defaultDate="defaultDate"
|
||||||
|
:minDate="innerMinDate"
|
||||||
|
:maxDate="innerMaxDate"
|
||||||
|
:maxMonth="monthNum"
|
||||||
|
:readonly="readonly"
|
||||||
|
:maxRange="maxRange"
|
||||||
|
:rangePrompt="rangePrompt"
|
||||||
|
:showRangePrompt="showRangePrompt"
|
||||||
|
:allowSameDay="allowSameDay"
|
||||||
|
ref="month"
|
||||||
|
@monthSelected="monthSelected"
|
||||||
|
@updateMonthTop="updateMonthTop"
|
||||||
|
></uMonth>
|
||||||
|
</scroll-view>
|
||||||
|
<slot name="footer" v-if="showConfirm">
|
||||||
|
<view class="u-calendar__confirm">
|
||||||
|
<u-button
|
||||||
|
shape="circle"
|
||||||
|
:text="
|
||||||
|
buttonDisabled ? confirmDisabledText : confirmText
|
||||||
|
"
|
||||||
|
:color="color"
|
||||||
|
@click="confirm"
|
||||||
|
:disabled="buttonDisabled"
|
||||||
|
></u-button>
|
||||||
|
</view>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import uHeader from './header.vue'
|
||||||
|
import uMonth from './month.vue'
|
||||||
|
import props from './props.js'
|
||||||
|
import util from './util.js'
|
||||||
|
import dayjs from '../../libs/util/dayjs.js'
|
||||||
|
import Calendar from '../../libs/util/calendar.js'
|
||||||
|
/**
|
||||||
|
* Calendar 日历
|
||||||
|
* @description 此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中.
|
||||||
|
* @tutorial https://www.uviewui.com/components/calendar.html
|
||||||
|
*
|
||||||
|
* @property {String} title 标题内容 (默认 日期选择 )
|
||||||
|
* @property {Boolean} showTitle 是否显示标题 (默认 true )
|
||||||
|
* @property {Boolean} showSubtitle 是否显示副标题 (默认 true )
|
||||||
|
* @property {String} mode 日期类型选择 single-选择单个日期,multiple-可以选择多个日期,range-选择日期范围 ( 默认 'single' )
|
||||||
|
* @property {String} startText mode=range时,第一个日期底部的提示文字 (默认 '开始' )
|
||||||
|
* @property {String} endText mode=range时,最后一个日期底部的提示文字 (默认 '结束' )
|
||||||
|
* @property {Array} customList 自定义列表
|
||||||
|
* @property {String} color 主题色,对底部按钮和选中日期有效 (默认 ‘#3c9cff' )
|
||||||
|
* @property {String | Number} minDate 最小的可选日期 (默认 0 )
|
||||||
|
* @property {String | Number} maxDate 最大可选日期 (默认 0 )
|
||||||
|
* @property {Array | String| Date} defaultDate 默认选中的日期,mode为multiple或range是必须为数组格式
|
||||||
|
* @property {String | Number} maxCount mode=multiple时,最多可选多少个日期 (默认 Number.MAX_SAFE_INTEGER )
|
||||||
|
* @property {String | Number} rowHeight 日期行高 (默认 56 )
|
||||||
|
* @property {Function} formatter 日期格式化函数
|
||||||
|
* @property {Boolean} showLunar 是否显示农历 (默认 false )
|
||||||
|
* @property {Boolean} showMark 是否显示月份背景色 (默认 true )
|
||||||
|
* @property {String} confirmText 确定按钮的文字 (默认 '确定' )
|
||||||
|
* @property {String} confirmDisabledText 确认按钮处于禁用状态时的文字 (默认 '确定' )
|
||||||
|
* @property {Boolean} show 是否显示日历弹窗 (默认 false )
|
||||||
|
* @property {Boolean} closeOnClickOverlay 是否允许点击遮罩关闭日历 (默认 false )
|
||||||
|
* @property {Boolean} readonly 是否为只读状态,只读状态下禁止选择日期 (默认 false )
|
||||||
|
* @property {String | Number} maxRange 日期区间最多可选天数,默认无限制,mode = range时有效
|
||||||
|
* @property {String} rangePrompt 范围选择超过最多可选天数时的提示文案,mode = range时有效
|
||||||
|
* @property {Boolean} showRangePrompt 范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效 (默认 true )
|
||||||
|
* @property {Boolean} allowSameDay 是否允许日期范围的起止时间为同一天,mode = range时有效 (默认 false )
|
||||||
|
* @property {Number|String} round 圆角值,默认无圆角 (默认 0 )
|
||||||
|
* @property {Number|String} monthNum 最多展示的月份数量 (默认 3 )
|
||||||
|
*
|
||||||
|
* @event {Function()} confirm 点击确定按钮时触发 选择日期相关的返回参数
|
||||||
|
* @event {Function()} close 日历关闭时触发 可定义页面关闭时的回调事件
|
||||||
|
* @example <u-calendar :defaultDate="defaultDateMultiple" :show="show" mode="multiple" @confirm="confirm">
|
||||||
|
</u-calendar>
|
||||||
|
* */
|
||||||
|
export default {
|
||||||
|
name: 'u-calendar',
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
|
||||||
|
components: {
|
||||||
|
uHeader,
|
||||||
|
uMonth
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 需要显示的月份的数组
|
||||||
|
months: [],
|
||||||
|
// 在月份滚动区域中,当前视图中月份的index索引
|
||||||
|
monthIndex: 0,
|
||||||
|
// 月份滚动区域的高度
|
||||||
|
listHeight: 0,
|
||||||
|
// month组件中选择的日期数组
|
||||||
|
selected: [],
|
||||||
|
scrollIntoView: '',
|
||||||
|
scrollTop:0,
|
||||||
|
// 过滤处理方法
|
||||||
|
innerFormatter: (value) => value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
selectedChange: {
|
||||||
|
immediate: true,
|
||||||
|
handler(n) {
|
||||||
|
this.setMonth()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 打开弹窗时,设置月份数据
|
||||||
|
show: {
|
||||||
|
immediate: true,
|
||||||
|
handler(n) {
|
||||||
|
this.setMonth()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 由于maxDate和minDate可以为字符串(2021-10-10),或者数值(时间戳),但是dayjs如果接受字符串形式的时间戳会有问题,这里进行处理
|
||||||
|
innerMaxDate() {
|
||||||
|
return uni.$u.test.number(this.maxDate)
|
||||||
|
? Number(this.maxDate)
|
||||||
|
: this.maxDate
|
||||||
|
},
|
||||||
|
innerMinDate() {
|
||||||
|
return uni.$u.test.number(this.minDate)
|
||||||
|
? Number(this.minDate)
|
||||||
|
: this.minDate
|
||||||
|
},
|
||||||
|
// 多个条件的变化,会引起选中日期的变化,这里统一管理监听
|
||||||
|
selectedChange() {
|
||||||
|
return [this.innerMinDate, this.innerMaxDate, this.defaultDate]
|
||||||
|
},
|
||||||
|
subtitle() {
|
||||||
|
// 初始化时,this.months为空数组,所以需要特别判断处理
|
||||||
|
if (this.months.length) {
|
||||||
|
return `${this.months[this.monthIndex].year}年${
|
||||||
|
this.months[this.monthIndex].month
|
||||||
|
}月`
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buttonDisabled() {
|
||||||
|
// 如果为range类型,且选择的日期个数不足1个时,让底部的按钮出于disabled状态
|
||||||
|
if (this.mode === 'range') {
|
||||||
|
if (this.selected.length <= 1) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.start = Date.now()
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用
|
||||||
|
setFormatter(e) {
|
||||||
|
this.innerFormatter = e
|
||||||
|
},
|
||||||
|
// month组件内部选择日期后,通过事件通知给父组件
|
||||||
|
monthSelected(e) {
|
||||||
|
this.selected = e
|
||||||
|
if (!this.showConfirm) {
|
||||||
|
// 在不需要确认按钮的情况下,如果为单选,或者范围多选且已选长度大于2,则直接进行返还
|
||||||
|
if (
|
||||||
|
this.mode === 'multiple' ||
|
||||||
|
this.mode === 'single' ||
|
||||||
|
(this.mode === 'range' && this.selected.length >= 2)
|
||||||
|
) {
|
||||||
|
this.$emit('confirm', this.selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
init() {
|
||||||
|
// 校验maxDate,不能小于minDate
|
||||||
|
if (
|
||||||
|
this.innerMaxDate &&
|
||||||
|
this.innerMinDate &&
|
||||||
|
new Date(this.innerMaxDate).getTime() < new Date(this.innerMinDate).getTime()
|
||||||
|
) {
|
||||||
|
return uni.$u.error('maxDate不能小于minDate')
|
||||||
|
}
|
||||||
|
// 滚动区域的高度
|
||||||
|
this.listHeight = this.rowHeight * 5 + 30
|
||||||
|
this.setMonth()
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
this.$emit('close')
|
||||||
|
},
|
||||||
|
// 点击确定按钮
|
||||||
|
confirm() {
|
||||||
|
if (!this.buttonDisabled) {
|
||||||
|
this.$emit('confirm', this.selected)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 获得两个日期之间的月份数
|
||||||
|
getMonths(minDate, maxDate) {
|
||||||
|
const minYear = dayjs(minDate).year()
|
||||||
|
const minMonth = dayjs(minDate).month() + 1
|
||||||
|
const maxYear = dayjs(maxDate).year()
|
||||||
|
const maxMonth = dayjs(maxDate).month() + 1
|
||||||
|
return (maxYear - minYear) * 12 + (maxMonth - minMonth) + 1
|
||||||
|
},
|
||||||
|
// 设置月份数据
|
||||||
|
setMonth() {
|
||||||
|
// 最小日期的毫秒数
|
||||||
|
const minDate = this.innerMinDate || dayjs().valueOf()
|
||||||
|
// 如果没有指定最大日期,则往后推3个月
|
||||||
|
const maxDate =
|
||||||
|
this.innerMaxDate ||
|
||||||
|
dayjs(minDate)
|
||||||
|
.add(this.monthNum - 1, 'month')
|
||||||
|
.valueOf()
|
||||||
|
// 最大最小月份之间的共有多少个月份,
|
||||||
|
const months = uni.$u.range(
|
||||||
|
1,
|
||||||
|
this.monthNum,
|
||||||
|
this.getMonths(minDate, maxDate)
|
||||||
|
)
|
||||||
|
// 先清空数组
|
||||||
|
this.months = []
|
||||||
|
for (let i = 0; i < months; i++) {
|
||||||
|
this.months.push({
|
||||||
|
date: new Array(
|
||||||
|
dayjs(minDate).add(i, 'month').daysInMonth()
|
||||||
|
)
|
||||||
|
.fill(1)
|
||||||
|
.map((item, index) => {
|
||||||
|
// 日期,取值1-31
|
||||||
|
let day = index + 1
|
||||||
|
// 星期,0-6,0为周日
|
||||||
|
const week = dayjs(minDate)
|
||||||
|
.add(i, 'month')
|
||||||
|
.date(day)
|
||||||
|
.day()
|
||||||
|
const date = dayjs(minDate)
|
||||||
|
.add(i, 'month')
|
||||||
|
.date(day)
|
||||||
|
.format('YYYY-MM-DD')
|
||||||
|
let bottomInfo = ''
|
||||||
|
if (this.showLunar) {
|
||||||
|
// 将日期转为农历格式
|
||||||
|
const lunar = Calendar.solar2lunar(
|
||||||
|
dayjs(date).year(),
|
||||||
|
dayjs(date).month() + 1,
|
||||||
|
dayjs(date).date()
|
||||||
|
)
|
||||||
|
bottomInfo = lunar.IDayCn
|
||||||
|
}
|
||||||
|
let config = {
|
||||||
|
day,
|
||||||
|
week,
|
||||||
|
// 小于最小允许的日期,或者大于最大的日期,则设置为disabled状态
|
||||||
|
disabled:
|
||||||
|
dayjs(date).isBefore(
|
||||||
|
dayjs(minDate).format('YYYY-MM-DD')
|
||||||
|
) ||
|
||||||
|
dayjs(date).isAfter(
|
||||||
|
dayjs(maxDate).format('YYYY-MM-DD')
|
||||||
|
),
|
||||||
|
// 返回一个日期对象,供外部的formatter获取当前日期的年月日等信息,进行加工处理
|
||||||
|
date: new Date(date),
|
||||||
|
bottomInfo,
|
||||||
|
dot: false,
|
||||||
|
month:
|
||||||
|
dayjs(minDate).add(i, 'month').month() + 1
|
||||||
|
}
|
||||||
|
const formatter =
|
||||||
|
this.formatter || this.innerFormatter
|
||||||
|
return formatter(config)
|
||||||
|
}),
|
||||||
|
// 当前所属的月份
|
||||||
|
month: dayjs(minDate).add(i, 'month').month() + 1,
|
||||||
|
// 当前年份
|
||||||
|
year: dayjs(minDate).add(i, 'month').year()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
// 滚动到默认设置的月份
|
||||||
|
scrollIntoDefaultMonth(selected) {
|
||||||
|
// 查询默认日期在可选列表的下标
|
||||||
|
const _index = this.months.findIndex(({
|
||||||
|
year,
|
||||||
|
month
|
||||||
|
}) => {
|
||||||
|
month = uni.$u.padZero(month)
|
||||||
|
return `${year}-${month}` === selected
|
||||||
|
})
|
||||||
|
if (_index !== -1) {
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.scrollIntoView = `month-${_index}`
|
||||||
|
})
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
this.scrollTop = this.months[_index].top || 0;
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// scroll-view滚动监听
|
||||||
|
onScroll(event) {
|
||||||
|
// 不允许小于0的滚动值,如果scroll-view到顶了,继续下拉,会出现负数值
|
||||||
|
const scrollTop = Math.max(0, event.detail.scrollTop)
|
||||||
|
// 将当前滚动条数值,除以滚动区域的高度,可以得出当前滚动到了哪一个月份的索引
|
||||||
|
for (let i = 0; i < this.months.length; i++) {
|
||||||
|
if (scrollTop >= (this.months[i].top || this.listHeight)) {
|
||||||
|
this.monthIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 更新月份的top值
|
||||||
|
updateMonthTop(topArr = []) {
|
||||||
|
// 设置对应月份的top值,用于onScroll方法更新月份
|
||||||
|
topArr.map((item, index) => {
|
||||||
|
this.months[index].top = item
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取默认日期的下标
|
||||||
|
if (!this.defaultDate) {
|
||||||
|
// 如果没有设置默认日期,则将当天日期设置为默认选中的日期
|
||||||
|
const selected = dayjs().format("YYYY-MM")
|
||||||
|
this.scrollIntoDefaultMonth(selected)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let selected = dayjs().format("YYYY-MM");
|
||||||
|
// 单选模式,可以是字符串或数组,Date对象等
|
||||||
|
if (!uni.$u.test.array(this.defaultDate)) {
|
||||||
|
selected = dayjs(this.defaultDate).format("YYYY-MM")
|
||||||
|
} else {
|
||||||
|
selected = dayjs(this.defaultDate[0]).format("YYYY-MM");
|
||||||
|
}
|
||||||
|
this.scrollIntoDefaultMonth(selected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import '../../libs/css/components.scss';
|
||||||
|
|
||||||
|
.u-calendar {
|
||||||
|
&__confirm {
|
||||||
|
padding: 7px 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,85 @@
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
// 设置月份数据
|
||||||
|
setMonth() {
|
||||||
|
// 月初是周几
|
||||||
|
const day = dayjs(this.date).date(1).day()
|
||||||
|
const start = day == 0 ? 6 : day - 1
|
||||||
|
|
||||||
|
// 本月天数
|
||||||
|
const days = dayjs(this.date).endOf('month').format('D')
|
||||||
|
|
||||||
|
// 上个月天数
|
||||||
|
const prevDays = dayjs(this.date).endOf('month').subtract(1, 'month').format('D')
|
||||||
|
|
||||||
|
// 日期数据
|
||||||
|
const arr = []
|
||||||
|
// 清空表格
|
||||||
|
this.month = []
|
||||||
|
|
||||||
|
// 添加上月数据
|
||||||
|
arr.push(
|
||||||
|
...new Array(start).fill(1).map((e, i) => {
|
||||||
|
const day = prevDays - start + i + 1
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: day,
|
||||||
|
disabled: true,
|
||||||
|
date: dayjs(this.date).subtract(1, 'month').date(day).format('YYYY-MM-DD')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// 添加本月数据
|
||||||
|
arr.push(
|
||||||
|
...new Array(days - 0).fill(1).map((e, i) => {
|
||||||
|
const day = i + 1
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: day,
|
||||||
|
date: dayjs(this.date).date(day).format('YYYY-MM-DD')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// 添加下个月
|
||||||
|
arr.push(
|
||||||
|
...new Array(42 - days - start).fill(1).map((e, i) => {
|
||||||
|
const day = i + 1
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: day,
|
||||||
|
disabled: true,
|
||||||
|
date: dayjs(this.date).add(1, 'month').date(day).format('YYYY-MM-DD')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// 分割数组
|
||||||
|
for (let n = 0; n < arr.length; n += 7) {
|
||||||
|
this.month.push(
|
||||||
|
arr.slice(n, n + 7).map((e, i) => {
|
||||||
|
e.index = i + n
|
||||||
|
|
||||||
|
// 自定义信息
|
||||||
|
const custom = this.customList.find((c) => c.date == e.date)
|
||||||
|
|
||||||
|
// 农历
|
||||||
|
if (this.lunar) {
|
||||||
|
const {
|
||||||
|
IDayCn,
|
||||||
|
IMonthCn
|
||||||
|
} = this.getLunar(e.date)
|
||||||
|
e.lunar = IDayCn == '初一' ? IMonthCn : IDayCn
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...e,
|
||||||
|
...custom
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 是否打乱键盘按键的顺序
|
||||||
|
random: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 输入一个中文后,是否自动切换到英文
|
||||||
|
autoChange: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,311 @@
|
||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="u-keyboard"
|
||||||
|
@touchmove.stop.prevent="noop"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
v-for="(group, i) in abc ? engKeyBoardList : areaList"
|
||||||
|
:key="i"
|
||||||
|
class="u-keyboard__button"
|
||||||
|
:index="i"
|
||||||
|
:class="[i + 1 === 4 && 'u-keyboard__button--center']"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
v-if="i === 3"
|
||||||
|
class="u-keyboard__button__inner-wrapper"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="u-keyboard__button__inner-wrapper__left"
|
||||||
|
hover-class="u-hover-class"
|
||||||
|
:hover-stay-time="200"
|
||||||
|
@tap="changeCarInputMode"
|
||||||
|
>
|
||||||
|
<text
|
||||||
|
class="u-keyboard__button__inner-wrapper__left__lang"
|
||||||
|
:class="[!abc && 'u-keyboard__button__inner-wrapper__left__lang--active']"
|
||||||
|
>中</text>
|
||||||
|
<text class="u-keyboard__button__inner-wrapper__left__line">/</text>
|
||||||
|
<text
|
||||||
|
class="u-keyboard__button__inner-wrapper__left__lang"
|
||||||
|
:class="[abc && 'u-keyboard__button__inner-wrapper__left__lang--active']"
|
||||||
|
>英</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="u-keyboard__button__inner-wrapper"
|
||||||
|
v-for="(item, j) in group"
|
||||||
|
:key="j"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="u-keyboard__button__inner-wrapper__inner"
|
||||||
|
:hover-stay-time="200"
|
||||||
|
@tap="carInputClick(i, j)"
|
||||||
|
hover-class="u-hover-class"
|
||||||
|
>
|
||||||
|
<text class="u-keyboard__button__inner-wrapper__inner__text">{{ item }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
v-if="i === 3"
|
||||||
|
@touchstart="backspaceClick"
|
||||||
|
@touchend="clearTimer"
|
||||||
|
class="u-keyboard__button__inner-wrapper"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="u-keyboard__button__inner-wrapper__right"
|
||||||
|
hover-class="u-hover-class"
|
||||||
|
:hover-stay-time="200"
|
||||||
|
>
|
||||||
|
<u-icon
|
||||||
|
size="28"
|
||||||
|
name="backspace"
|
||||||
|
color="#303133"
|
||||||
|
></u-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js';
|
||||||
|
/**
|
||||||
|
* keyboard 键盘组件
|
||||||
|
* @description 此为uView自定义的键盘面板,内含了数字键盘,车牌号键,身份证号键盘3种模式,都有可以打乱按键顺序的选项。
|
||||||
|
* @tutorial https://uviewui.com/components/keyboard.html
|
||||||
|
* @property {Boolean} random 是否打乱键盘的顺序
|
||||||
|
* @event {Function} change 点击键盘触发
|
||||||
|
* @event {Function} backspace 点击退格键触发
|
||||||
|
* @example <u-keyboard ref="uKeyboard" mode="car" v-model="show"></u-keyboard>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-keyboard",
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 车牌输入时,abc=true为输入车牌号码,bac=false为输入省份中文简称
|
||||||
|
abc: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
areaList() {
|
||||||
|
let data = [
|
||||||
|
'京',
|
||||||
|
'沪',
|
||||||
|
'粤',
|
||||||
|
'津',
|
||||||
|
'冀',
|
||||||
|
'豫',
|
||||||
|
'云',
|
||||||
|
'辽',
|
||||||
|
'黑',
|
||||||
|
'湘',
|
||||||
|
'皖',
|
||||||
|
'鲁',
|
||||||
|
'苏',
|
||||||
|
'浙',
|
||||||
|
'赣',
|
||||||
|
'鄂',
|
||||||
|
'桂',
|
||||||
|
'甘',
|
||||||
|
'晋',
|
||||||
|
'陕',
|
||||||
|
'蒙',
|
||||||
|
'吉',
|
||||||
|
'闽',
|
||||||
|
'贵',
|
||||||
|
'渝',
|
||||||
|
'川',
|
||||||
|
'青',
|
||||||
|
'琼',
|
||||||
|
'宁',
|
||||||
|
'挂',
|
||||||
|
'藏',
|
||||||
|
'港',
|
||||||
|
'澳',
|
||||||
|
'新',
|
||||||
|
'使',
|
||||||
|
'学'
|
||||||
|
];
|
||||||
|
let tmp = [];
|
||||||
|
// 打乱顺序
|
||||||
|
if (this.random) data = uni.$u.randomArray(data);
|
||||||
|
// 切割成二维数组
|
||||||
|
tmp[0] = data.slice(0, 10);
|
||||||
|
tmp[1] = data.slice(10, 20);
|
||||||
|
tmp[2] = data.slice(20, 30);
|
||||||
|
tmp[3] = data.slice(30, 36);
|
||||||
|
return tmp;
|
||||||
|
},
|
||||||
|
engKeyBoardList() {
|
||||||
|
let data = [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
8,
|
||||||
|
9,
|
||||||
|
0,
|
||||||
|
'Q',
|
||||||
|
'W',
|
||||||
|
'E',
|
||||||
|
'R',
|
||||||
|
'T',
|
||||||
|
'Y',
|
||||||
|
'U',
|
||||||
|
'I',
|
||||||
|
'O',
|
||||||
|
'P',
|
||||||
|
'A',
|
||||||
|
'S',
|
||||||
|
'D',
|
||||||
|
'F',
|
||||||
|
'G',
|
||||||
|
'H',
|
||||||
|
'J',
|
||||||
|
'K',
|
||||||
|
'L',
|
||||||
|
'Z',
|
||||||
|
'X',
|
||||||
|
'C',
|
||||||
|
'V',
|
||||||
|
'B',
|
||||||
|
'N',
|
||||||
|
'M'
|
||||||
|
];
|
||||||
|
let tmp = [];
|
||||||
|
if (this.random) data = uni.$u.randomArray(data);
|
||||||
|
tmp[0] = data.slice(0, 10);
|
||||||
|
tmp[1] = data.slice(10, 20);
|
||||||
|
tmp[2] = data.slice(20, 30);
|
||||||
|
tmp[3] = data.slice(30, 36);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 点击键盘按钮
|
||||||
|
carInputClick(i, j) {
|
||||||
|
let value = '';
|
||||||
|
// 不同模式,获取不同数组的值
|
||||||
|
if (this.abc) value = this.engKeyBoardList[i][j];
|
||||||
|
else value = this.areaList[i][j];
|
||||||
|
// 如果允许自动切换,则将中文状态切换为英文
|
||||||
|
if (!this.abc && this.autoChange) uni.$u.sleep(200).then(() => this.abc = true)
|
||||||
|
this.$emit('change', value);
|
||||||
|
},
|
||||||
|
// 修改汽车牌键盘的输入模式,中文|英文
|
||||||
|
changeCarInputMode() {
|
||||||
|
this.abc = !this.abc;
|
||||||
|
},
|
||||||
|
// 点击退格键
|
||||||
|
backspaceClick() {
|
||||||
|
this.$emit('backspace');
|
||||||
|
clearInterval(this.timer); //再次清空定时器,防止重复注册定时器
|
||||||
|
this.timer = null;
|
||||||
|
this.timer = setInterval(() => {
|
||||||
|
this.$emit('backspace');
|
||||||
|
}, 250);
|
||||||
|
},
|
||||||
|
clearTimer() {
|
||||||
|
clearInterval(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
$u-car-keyboard-background-color: rgb(224, 228, 230) !default;
|
||||||
|
$u-car-keyboard-padding:6px 0 6px !default;
|
||||||
|
$u-car-keyboard-button-inner-width:64rpx !default;
|
||||||
|
$u-car-keyboard-button-inner-background-color:#FFFFFF !default;
|
||||||
|
$u-car-keyboard-button-height:80rpx !default;
|
||||||
|
$u-car-keyboard-button-inner-box-shadow:0 1px 0px #999992 !default;
|
||||||
|
$u-car-keyboard-button-border-radius:4px !default;
|
||||||
|
$u-car-keyboard-button-inner-margin:8rpx 5rpx !default;
|
||||||
|
$u-car-keyboard-button-text-font-size:16px !default;
|
||||||
|
$u-car-keyboard-button-text-color:$u-main-color !default;
|
||||||
|
$u-car-keyboard-center-inner-margin: 0 4rpx !default;
|
||||||
|
$u-car-keyboard-special-button-width:134rpx !default;
|
||||||
|
$u-car-keyboard-lang-font-size:16px !default;
|
||||||
|
$u-car-keyboard-lang-color:$u-main-color !default;
|
||||||
|
$u-car-keyboard-active-color:$u-primary !default;
|
||||||
|
$u-car-keyboard-line-font-size:15px !default;
|
||||||
|
$u-car-keyboard-line-color:$u-main-color !default;
|
||||||
|
$u-car-keyboard-line-margin:0 1px !default;
|
||||||
|
$u-car-keyboard-u-hover-class-background-color:#BBBCC6 !default;
|
||||||
|
|
||||||
|
.u-keyboard {
|
||||||
|
@include flex(column);
|
||||||
|
justify-content: space-around;
|
||||||
|
background-color: $u-car-keyboard-background-color;
|
||||||
|
align-items: stretch;
|
||||||
|
padding: $u-car-keyboard-padding;
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
@include flex;
|
||||||
|
justify-content: center;
|
||||||
|
flex: 1;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
&__inner-wrapper {
|
||||||
|
box-shadow: $u-car-keyboard-button-inner-box-shadow;
|
||||||
|
margin: $u-car-keyboard-button-inner-margin;
|
||||||
|
border-radius: $u-car-keyboard-button-border-radius;
|
||||||
|
|
||||||
|
&__inner {
|
||||||
|
@include flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: $u-car-keyboard-button-inner-width;
|
||||||
|
background-color: $u-car-keyboard-button-inner-background-color;
|
||||||
|
height: $u-car-keyboard-button-height;
|
||||||
|
border-radius: $u-car-keyboard-button-border-radius;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
font-size: $u-car-keyboard-button-text-font-size;
|
||||||
|
color: $u-car-keyboard-button-text-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__left,
|
||||||
|
&__right {
|
||||||
|
border-radius: $u-car-keyboard-button-border-radius;
|
||||||
|
width: $u-car-keyboard-special-button-width;
|
||||||
|
height: $u-car-keyboard-button-height;
|
||||||
|
background-color: $u-car-keyboard-u-hover-class-background-color;
|
||||||
|
@include flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
box-shadow: $u-car-keyboard-button-inner-box-shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__left {
|
||||||
|
&__line {
|
||||||
|
font-size: $u-car-keyboard-line-font-size;
|
||||||
|
color: $u-car-keyboard-line-color;
|
||||||
|
margin: $u-car-keyboard-line-margin;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__lang {
|
||||||
|
font-size: $u-car-keyboard-lang-font-size;
|
||||||
|
color: $u-car-keyboard-lang-color;
|
||||||
|
|
||||||
|
&--active {
|
||||||
|
color: $u-car-keyboard-active-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-hover-class {
|
||||||
|
background-color: $u-car-keyboard-u-hover-class-background-color;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,299 @@
|
||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="u-card"
|
||||||
|
@tap.stop="click"
|
||||||
|
:class="{ 'u-border': border, 'u-card-full': full, 'u-card--border': borderRadius > 0 }"
|
||||||
|
:style="{
|
||||||
|
borderRadius: borderRadius + 'rpx',
|
||||||
|
margin: margin,
|
||||||
|
boxShadow: boxShadow
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
v-if="showHead"
|
||||||
|
class="u-card__head"
|
||||||
|
:style="[{padding: padding + 'rpx'}, headStyle]"
|
||||||
|
:class="{
|
||||||
|
'u-border-bottom': headBorderBottom
|
||||||
|
}"
|
||||||
|
@tap="headClick"
|
||||||
|
>
|
||||||
|
<view v-if="!$slots.head" class="u-flex u-row-between">
|
||||||
|
<view class="u-card__head--left u-flex u-line-1" v-if="title">
|
||||||
|
<image
|
||||||
|
:src="thumb"
|
||||||
|
class="u-card__head--left__thumb"
|
||||||
|
mode="aspectfull"
|
||||||
|
v-if="thumb"
|
||||||
|
:style="{
|
||||||
|
height: thumbWidth + 'rpx',
|
||||||
|
width: thumbWidth + 'rpx',
|
||||||
|
borderRadius: thumbCircle ? '100rpx' : '6rpx'
|
||||||
|
}"
|
||||||
|
></image>
|
||||||
|
<text
|
||||||
|
class="u-card__head--left__title u-line-1"
|
||||||
|
:style="{
|
||||||
|
fontSize: titleSize + 'rpx',
|
||||||
|
color: titleColor
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ title }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
<view class="u-card__head--right u-line-1" v-if="subTitle">
|
||||||
|
<text
|
||||||
|
class="u-card__head__title__text"
|
||||||
|
:style="{
|
||||||
|
fontSize: subTitleSize + 'rpx',
|
||||||
|
color: subTitleColor
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ subTitle }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<slot name="head" v-else />
|
||||||
|
</view>
|
||||||
|
<view @tap="bodyClick" class="u-card__body" :style="[{padding: padding + 'rpx'}, bodyStyle]"><slot name="body" /></view>
|
||||||
|
<view
|
||||||
|
v-if="showFoot"
|
||||||
|
class="u-card__foot"
|
||||||
|
@tap="footClick"
|
||||||
|
:style="[{padding: $slots.foot ? padding + 'rpx' : 0}, footStyle]"
|
||||||
|
:class="{
|
||||||
|
'u-border-top': footBorderTop
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<slot name="foot" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* card 卡片
|
||||||
|
* @description 卡片组件一般用于多个列表条目,且风格统一的场景
|
||||||
|
* @tutorial https://www.uviewui.com/components/card.html
|
||||||
|
* @property {Boolean} full 卡片与屏幕两侧是否留空隙(默认false)
|
||||||
|
* @property {String} title 头部左边的标题
|
||||||
|
* @property {String} title-color 标题颜色(默认#303133)
|
||||||
|
* @property {String | Number} title-size 标题字体大小,单位rpx(默认30)
|
||||||
|
* @property {String} sub-title 头部右边的副标题
|
||||||
|
* @property {String} sub-title-color 副标题颜色(默认#909399)
|
||||||
|
* @property {String | Number} sub-title-size 副标题字体大小(默认26)
|
||||||
|
* @property {Boolean} border 是否显示边框(默认true)
|
||||||
|
* @property {String | Number} index 用于标识点击了第几个卡片
|
||||||
|
* @property {String} box-shadow 卡片外围阴影,字符串形式(默认none)
|
||||||
|
* @property {String} margin 卡片与屏幕两边和上下元素的间距,需带单位,如"30rpx 20rpx"(默认30rpx)
|
||||||
|
* @property {String | Number} border-radius 卡片整体的圆角值,单位rpx(默认16)
|
||||||
|
* @property {Object} head-style 头部自定义样式,对象形式
|
||||||
|
* @property {Object} body-style 中部自定义样式,对象形式
|
||||||
|
* @property {Object} foot-style 底部自定义样式,对象形式
|
||||||
|
* @property {Boolean} head-border-bottom 是否显示头部的下边框(默认true)
|
||||||
|
* @property {Boolean} foot-border-top 是否显示底部的上边框(默认true)
|
||||||
|
* @property {Boolean} show-head 是否显示头部(默认true)
|
||||||
|
* @property {Boolean} show-head 是否显示尾部(默认true)
|
||||||
|
* @property {String} thumb 缩略图路径,如设置将显示在标题的左边,不建议使用相对路径
|
||||||
|
* @property {String | Number} thumb-width 缩略图的宽度,高等于宽,单位rpx(默认60)
|
||||||
|
* @property {Boolean} thumb-circle 缩略图是否为圆形(默认false)
|
||||||
|
* @event {Function} click 整个卡片任意位置被点击时触发
|
||||||
|
* @event {Function} head-click 卡片头部被点击时触发
|
||||||
|
* @event {Function} body-click 卡片主体部分被点击时触发
|
||||||
|
* @event {Function} foot-click 卡片底部部分被点击时触发
|
||||||
|
* @example <u-card padding="30" title="card"></u-card>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-card',
|
||||||
|
props: {
|
||||||
|
// 与屏幕两侧是否留空隙
|
||||||
|
full: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 标题
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 标题颜色
|
||||||
|
titleColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#303133'
|
||||||
|
},
|
||||||
|
// 标题字体大小,单位rpx
|
||||||
|
titleSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '30'
|
||||||
|
},
|
||||||
|
// 副标题
|
||||||
|
subTitle: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 副标题颜色
|
||||||
|
subTitleColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#909399'
|
||||||
|
},
|
||||||
|
// 副标题字体大小,单位rpx
|
||||||
|
subTitleSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '26'
|
||||||
|
},
|
||||||
|
// 是否显示外部边框,只对full=false时有效(卡片与边框有空隙时)
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 用于标识点击了第几个
|
||||||
|
index: {
|
||||||
|
type: [Number, String, Object],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 用于隔开上下左右的边距,带单位的写法,如:"30rpx 30rpx","20rpx 20rpx 30rpx 30rpx"
|
||||||
|
margin: {
|
||||||
|
type: String,
|
||||||
|
default: '30rpx'
|
||||||
|
},
|
||||||
|
// card卡片的圆角
|
||||||
|
borderRadius: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '16'
|
||||||
|
},
|
||||||
|
// 头部自定义样式,对象形式
|
||||||
|
headStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 主体自定义样式,对象形式
|
||||||
|
bodyStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 底部自定义样式,对象形式
|
||||||
|
footStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 头部是否下边框
|
||||||
|
headBorderBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 底部是否有上边框
|
||||||
|
footBorderTop: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 标题左边的缩略图
|
||||||
|
thumb: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 缩略图宽高,单位rpx
|
||||||
|
thumbWidth: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '60'
|
||||||
|
},
|
||||||
|
// 缩略图是否为圆形
|
||||||
|
thumbCircle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 给head,body,foot的内边距
|
||||||
|
padding: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '30'
|
||||||
|
},
|
||||||
|
// 是否显示头部
|
||||||
|
showHead: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示尾部
|
||||||
|
showFoot: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 卡片外围阴影,字符串形式
|
||||||
|
boxShadow: {
|
||||||
|
type: String,
|
||||||
|
default: 'none'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click() {
|
||||||
|
this.$emit('click', this.index);
|
||||||
|
},
|
||||||
|
headClick() {
|
||||||
|
this.$emit('head-click', this.index);
|
||||||
|
},
|
||||||
|
bodyClick() {
|
||||||
|
this.$emit('body-click', this.index);
|
||||||
|
},
|
||||||
|
footClick() {
|
||||||
|
this.$emit('foot-click', this.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-card {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 28rpx;
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&-full {
|
||||||
|
// 如果是与屏幕之间不留空隙,应该设置左右边距为0
|
||||||
|
margin-left: 0 !important;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border:after {
|
||||||
|
border-radius: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__head {
|
||||||
|
&--left {
|
||||||
|
color: $u-main-color;
|
||||||
|
|
||||||
|
&__thumb {
|
||||||
|
margin-right: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
max-width: 400rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--right {
|
||||||
|
color: $u-tips-color;
|
||||||
|
margin-left: 6rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__body {
|
||||||
|
color: $u-content-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__foot {
|
||||||
|
color: $u-tips-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,14 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 分组标题
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.cellGroup.title
|
||||||
|
},
|
||||||
|
// 是否显示外边框
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.cellGroup.border
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
<template>
|
||||||
|
<view :style="[$u.addStyle(customStyle)]" :class="[customClass]" class="u-cell-group">
|
||||||
|
<view v-if="title" class="u-cell-group__title">
|
||||||
|
<slot name="title">
|
||||||
|
<text class="u-cell-group__title__text">{{ title }}</text>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
<view class="u-cell-group__wrapper">
|
||||||
|
<u-line v-if="border"></u-line>
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js';
|
||||||
|
/**
|
||||||
|
* cellGroup 单元格
|
||||||
|
* @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。
|
||||||
|
* @tutorial https://uviewui.com/components/cell.html
|
||||||
|
*
|
||||||
|
* @property {String} title 分组标题
|
||||||
|
* @property {Boolean} border 是否显示外边框 (默认 true )
|
||||||
|
* @property {Object} customStyle 定义需要用到的外部样式
|
||||||
|
*
|
||||||
|
* @event {Function} click 点击cell列表时触发
|
||||||
|
* @example <u-cell-group title="设置喜好">
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-cell-group',
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
|
$u-cell-group-title-padding: 16px 16px 8px !default;
|
||||||
|
$u-cell-group-title-font-size: 15px !default;
|
||||||
|
$u-cell-group-title-line-height: 16px !default;
|
||||||
|
$u-cell-group-title-color: $u-main-color !default;
|
||||||
|
|
||||||
|
.u-cell-group {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
padding: $u-cell-group-title-padding;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
font-size: $u-cell-group-title-font-size;
|
||||||
|
line-height: $u-cell-group-title-line-height;
|
||||||
|
color: $u-cell-group-title-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__wrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -0,0 +1,316 @@
|
||||||
|
<template>
|
||||||
|
<view
|
||||||
|
@tap="click"
|
||||||
|
class="u-cell"
|
||||||
|
:class="{ 'u-border-bottom': borderBottom, 'u-border-top': borderTop, 'u-col-center': center, 'u-cell--required': required }"
|
||||||
|
hover-stay-time="150"
|
||||||
|
:hover-class="hoverClass"
|
||||||
|
:style="{
|
||||||
|
backgroundColor: bgColor
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<u-icon :size="iconSize" :name="icon" v-if="icon" :custom-style="iconStyle" class="u-cell__left-icon-wrap"></u-icon>
|
||||||
|
<view class="u-flex" v-else>
|
||||||
|
<slot name="icon"></slot>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="u-cell_title"
|
||||||
|
:style="[
|
||||||
|
{
|
||||||
|
width: titleWidth ? titleWidth + 'rpx' : 'auto'
|
||||||
|
},
|
||||||
|
titleStyle
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<block v-if="title !== ''">{{ title }}</block>
|
||||||
|
<slot name="title" v-else></slot>
|
||||||
|
|
||||||
|
<view class="u-cell__label" v-if="label || $slots.label" :style="[labelStyle]">
|
||||||
|
<block v-if="label !== ''">{{ label }}</block>
|
||||||
|
<slot name="label" v-else></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="u-cell__value" :style="[valueStyle]">
|
||||||
|
<block class="u-cell__value" v-if="value !== ''">{{ value }}</block>
|
||||||
|
<slot v-else></slot>
|
||||||
|
</view>
|
||||||
|
<view class="u-flex u-cell_right" v-if="$slots['right-icon']">
|
||||||
|
<slot name="right-icon"></slot>
|
||||||
|
</view>
|
||||||
|
<u-icon v-if="arrow" name="arrow-right" :style="[arrowStyle]" class="u-icon-wrap u-cell__right-icon-wrap"></u-icon>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* cellItem 单元格Item
|
||||||
|
* @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。搭配u-cell-group使用
|
||||||
|
* @tutorial https://www.uviewui.com/components/cell.html
|
||||||
|
* @property {String} title 左侧标题
|
||||||
|
* @property {String} icon 左侧图标名,只支持uView内置图标,见Icon 图标
|
||||||
|
* @property {Object} icon-style 左边图标的样式,对象形式
|
||||||
|
* @property {String} value 右侧内容
|
||||||
|
* @property {String} label 标题下方的描述信息
|
||||||
|
* @property {Boolean} border-bottom 是否显示cell的下边框(默认true)
|
||||||
|
* @property {Boolean} border-top 是否显示cell的上边框(默认false)
|
||||||
|
* @property {Boolean} center 是否使内容垂直居中(默认false)
|
||||||
|
* @property {String} hover-class 是否开启点击反馈,none为无效果(默认true)
|
||||||
|
* // @property {Boolean} border-gap border-bottom为true时,Cell列表中间的条目的下边框是否与左边有一个间隔(默认true)
|
||||||
|
* @property {Boolean} arrow 是否显示右侧箭头(默认true)
|
||||||
|
* @property {Boolean} required 箭头方向,可选值(默认right)
|
||||||
|
* @property {Boolean} arrow-direction 是否显示左边表示必填的星号(默认false)
|
||||||
|
* @property {Object} title-style 标题样式,对象形式
|
||||||
|
* @property {Object} value-style 右侧内容样式,对象形式
|
||||||
|
* @property {Object} label-style 标题下方描述信息的样式,对象形式
|
||||||
|
* @property {String} bg-color 背景颜色(默认transparent)
|
||||||
|
* @property {String Number} index 用于在click事件回调中返回,标识当前是第几个Item
|
||||||
|
* @property {String Number} title-width 标题的宽度,单位rpx
|
||||||
|
* @example <u-cell-item icon="integral-fill" title="会员等级" value="新版本"></u-cell-item>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-cell-item',
|
||||||
|
props: {
|
||||||
|
// 左侧图标名称(只能uView内置图标),或者图标src
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 左侧标题
|
||||||
|
title: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 右侧内容
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 标题下方的描述信息
|
||||||
|
label: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否显示下边框
|
||||||
|
borderBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示上边框
|
||||||
|
borderTop: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 多个cell中,中间的cell显示下划线时,下划线是否给一个到左边的距离
|
||||||
|
// 1.4.0版本废除此参数,默认边框由border-top和border-bottom提供,此参数会造成干扰
|
||||||
|
// borderGap: {
|
||||||
|
// type: Boolean,
|
||||||
|
// default: true
|
||||||
|
// },
|
||||||
|
// 是否开启点击反馈,即点击时cell背景为灰色,none为无效果
|
||||||
|
hoverClass: {
|
||||||
|
type: String,
|
||||||
|
default: 'u-cell-hover'
|
||||||
|
},
|
||||||
|
// 是否显示右侧箭头
|
||||||
|
arrow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 内容是否垂直居中
|
||||||
|
center: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否显示左边表示必填的星号
|
||||||
|
required: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 标题的宽度,单位rpx
|
||||||
|
titleWidth: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 右侧箭头方向,可选值:right|up|down,默认为right
|
||||||
|
arrowDirection: {
|
||||||
|
type: String,
|
||||||
|
default: 'right'
|
||||||
|
},
|
||||||
|
// 控制标题的样式
|
||||||
|
titleStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 右侧显示内容的样式
|
||||||
|
valueStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 描述信息的样式
|
||||||
|
labelStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 背景颜色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'transparent'
|
||||||
|
},
|
||||||
|
// 用于识别被点击的是第几个cell
|
||||||
|
index: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否使用lable插槽
|
||||||
|
useLabelSlot: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 左边图标的大小,单位rpx,只对传入icon字段时有效
|
||||||
|
iconSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 34
|
||||||
|
},
|
||||||
|
// 左边图标的样式,对象形式
|
||||||
|
iconStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
arrowStyle() {
|
||||||
|
let style = {};
|
||||||
|
if (this.arrowDirection == 'up') style.transform = 'rotate(-90deg)';
|
||||||
|
else if (this.arrowDirection == 'down') style.transform = 'rotate(90deg)';
|
||||||
|
else style.transform = 'rotate(0deg)';
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click() {
|
||||||
|
this.$emit('click', this.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
.u-cell {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* #endif */
|
||||||
|
width: 100%;
|
||||||
|
padding: 26rpx 32rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
line-height: 54rpx;
|
||||||
|
color: $u-content-color;
|
||||||
|
background-color: #fff;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell_title {
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell__left-icon-wrap {
|
||||||
|
margin-right: 10rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell__right-icon-wrap {
|
||||||
|
margin-left: 10rpx;
|
||||||
|
color: #969799;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell__left-icon-wrap,
|
||||||
|
.u-cell__right-icon-wrap {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 48rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell-border:after {
|
||||||
|
position: absolute;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
box-sizing: border-box;
|
||||||
|
content: ' ';
|
||||||
|
pointer-events: none;
|
||||||
|
border-bottom: 1px solid $u-border-color;
|
||||||
|
/* #endif */
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
transform: scaleY(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell-border {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell__label {
|
||||||
|
margin-top: 6rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
line-height: 36rpx;
|
||||||
|
color: $u-tips-color;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
word-wrap: break-word;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell__value {
|
||||||
|
overflow: hidden;
|
||||||
|
text-align: right;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
vertical-align: middle;
|
||||||
|
/* #endif */
|
||||||
|
color: $u-tips-color;
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell__title,
|
||||||
|
.u-cell__value {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell--required {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
overflow: visible;
|
||||||
|
/* #endif */
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell--required:before {
|
||||||
|
position: absolute;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
content: '*';
|
||||||
|
/* #endif */
|
||||||
|
left: 8px;
|
||||||
|
margin-top: 4rpx;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $u-type-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell_right {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,110 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 标题
|
||||||
|
title: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.cell.title
|
||||||
|
},
|
||||||
|
// 标题下方的描述信息
|
||||||
|
label: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.cell.label
|
||||||
|
},
|
||||||
|
// 右侧的内容
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.cell.value
|
||||||
|
},
|
||||||
|
// 左侧图标名称,或者图片链接(本地文件建议使用绝对地址)
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.cell.icon
|
||||||
|
},
|
||||||
|
// 是否禁用cell
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.cell.disabled
|
||||||
|
},
|
||||||
|
// 是否显示下边框
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.cell.border
|
||||||
|
},
|
||||||
|
// 内容是否垂直居中(主要是针对右侧的value部分)
|
||||||
|
center: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.cell.center
|
||||||
|
},
|
||||||
|
// 点击后跳转的URL地址
|
||||||
|
url: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.cell.url
|
||||||
|
},
|
||||||
|
// 链接跳转的方式,内部使用的是uView封装的route方法,可能会进行拦截操作
|
||||||
|
linkType: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.cell.linkType
|
||||||
|
},
|
||||||
|
// 是否开启点击反馈(表现为点击时加上灰色背景)
|
||||||
|
clickable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.cell.clickable
|
||||||
|
},
|
||||||
|
// 是否展示右侧箭头并开启点击反馈
|
||||||
|
isLink: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.cell.isLink
|
||||||
|
},
|
||||||
|
// 是否显示表单状态下的必填星号(此组件可能会内嵌入input组件)
|
||||||
|
required: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.cell.required
|
||||||
|
},
|
||||||
|
// 右侧的图标箭头
|
||||||
|
rightIcon: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.cell.rightIcon
|
||||||
|
},
|
||||||
|
// 右侧箭头的方向,可选值为:left,up,down
|
||||||
|
arrowDirection: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.cell.arrowDirection
|
||||||
|
},
|
||||||
|
// 左侧图标样式
|
||||||
|
iconStyle: {
|
||||||
|
type: [Object, String],
|
||||||
|
default: () => {
|
||||||
|
return uni.$u.props.cell.iconStyle
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 右侧箭头图标的样式
|
||||||
|
rightIconStyle: {
|
||||||
|
type: [Object, String],
|
||||||
|
default: () => {
|
||||||
|
return uni.$u.props.cell.rightIconStyle
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 标题的样式
|
||||||
|
titleStyle: {
|
||||||
|
type: [Object, String],
|
||||||
|
default: () => {
|
||||||
|
return uni.$u.props.cell.titleStyle
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 单位元的大小,可选值为large
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.cell.size
|
||||||
|
},
|
||||||
|
// 点击cell是否阻止事件传播
|
||||||
|
stop: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.cell.stop
|
||||||
|
},
|
||||||
|
// 标识符,cell被点击时返回
|
||||||
|
name: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: uni.$u.props.cell.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,229 @@
|
||||||
|
<template>
|
||||||
|
<view class="u-cell" :class="[customClass]" :style="[$u.addStyle(customStyle)]"
|
||||||
|
:hover-class="(!disabled && (clickable || isLink)) ? 'u-cell--clickable' : ''" :hover-stay-time="250"
|
||||||
|
@tap="clickHandler">
|
||||||
|
<view class="u-cell__body" :class="[ center && 'u-cell--center', size === 'large' && 'u-cell__body--large']">
|
||||||
|
<view class="u-cell__body__content">
|
||||||
|
<view class="u-cell__left-icon-wrap" v-if="$slots.icon || icon">
|
||||||
|
<slot name="icon" v-if="$slots.icon">
|
||||||
|
</slot>
|
||||||
|
<u-icon v-else :name="icon" :custom-style="iconStyle" :size="size === 'large' ? 22 : 18"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="u-cell__title">
|
||||||
|
<slot name="title">
|
||||||
|
<text v-if="title" class="u-cell__title-text" :style="[titleTextStyle]"
|
||||||
|
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__title-text--large']">{{ title }}</text>
|
||||||
|
</slot>
|
||||||
|
<slot name="label">
|
||||||
|
<text class="u-cell__label" v-if="label"
|
||||||
|
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__label--large']">{{ label }}</text>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<slot name="value">
|
||||||
|
<text class="u-cell__value"
|
||||||
|
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__value--large']"
|
||||||
|
v-if="!$u.test.empty(value)">{{ value }}</text>
|
||||||
|
</slot>
|
||||||
|
<view class="u-cell__right-icon-wrap" v-if="$slots['right-icon'] || isLink"
|
||||||
|
:class="[`u-cell__right-icon-wrap--${arrowDirection}`]">
|
||||||
|
<slot name="right-icon" v-if="$slots['right-icon']">
|
||||||
|
</slot>
|
||||||
|
<u-icon v-else :name="rightIcon" :custom-style="rightIconStyle" :color="disabled ? '#c8c9cc' : 'info'"
|
||||||
|
:size="size === 'large' ? 18 : 16"></u-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<u-line v-if="border"></u-line>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js';
|
||||||
|
/**
|
||||||
|
* cell 单元格
|
||||||
|
* @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。
|
||||||
|
* @tutorial https://uviewui.com/components/cell.html
|
||||||
|
* @property {String | Number} title 标题
|
||||||
|
* @property {String | Number} label 标题下方的描述信息
|
||||||
|
* @property {String | Number} value 右侧的内容
|
||||||
|
* @property {String} icon 左侧图标名称,或者图片链接(本地文件建议使用绝对地址)
|
||||||
|
* @property {Boolean} disabled 是否禁用cell
|
||||||
|
* @property {Boolean} border 是否显示下边框 (默认 true )
|
||||||
|
* @property {Boolean} center 内容是否垂直居中(主要是针对右侧的value部分) (默认 false )
|
||||||
|
* @property {String} url 点击后跳转的URL地址
|
||||||
|
* @property {String} linkType 链接跳转的方式,内部使用的是uView封装的route方法,可能会进行拦截操作 (默认 'navigateTo' )
|
||||||
|
* @property {Boolean} clickable 是否开启点击反馈(表现为点击时加上灰色背景) (默认 false )
|
||||||
|
* @property {Boolean} isLink 是否展示右侧箭头并开启点击反馈 (默认 false )
|
||||||
|
* @property {Boolean} required 是否显示表单状态下的必填星号(此组件可能会内嵌入input组件) (默认 false )
|
||||||
|
* @property {String} rightIcon 右侧的图标箭头 (默认 'arrow-right')
|
||||||
|
* @property {String} arrowDirection 右侧箭头的方向,可选值为:left,up,down
|
||||||
|
* @property {Object | String} rightIconStyle 右侧箭头图标的样式
|
||||||
|
* @property {Object | String} titleStyle 标题的样式
|
||||||
|
* @property {Object | String} iconStyle 左侧图标样式
|
||||||
|
* @property {String} size 单位元的大小,可选值为 large,normal,mini
|
||||||
|
* @property {Boolean} stop 点击cell是否阻止事件传播 (默认 true )
|
||||||
|
* @property {Object} customStyle 定义需要用到的外部样式
|
||||||
|
*
|
||||||
|
* @event {Function} click 点击cell列表时触发
|
||||||
|
* @example 该组件需要搭配cell-group组件使用,见官方文档示例
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-cell',
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
|
||||||
|
computed: {
|
||||||
|
titleTextStyle() {
|
||||||
|
return uni.$u.addStyle(this.titleStyle)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 点击cell
|
||||||
|
clickHandler(e) {
|
||||||
|
if (this.disabled) return
|
||||||
|
this.$emit('click', {
|
||||||
|
name: this.name
|
||||||
|
})
|
||||||
|
// 如果配置了url(此props参数通过mixin引入)参数,跳转页面
|
||||||
|
this.openPage()
|
||||||
|
// 是否阻止事件传播
|
||||||
|
this.stop && this.preventEvent(e)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
|
$u-cell-padding: 10px 15px !default;
|
||||||
|
$u-cell-font-size: 15px !default;
|
||||||
|
$u-cell-line-height: 24px !default;
|
||||||
|
$u-cell-color: $u-main-color !default;
|
||||||
|
$u-cell-icon-size: 16px !default;
|
||||||
|
$u-cell-title-font-size: 15px !default;
|
||||||
|
$u-cell-title-line-height: 22px !default;
|
||||||
|
$u-cell-title-color: $u-main-color !default;
|
||||||
|
$u-cell-label-font-size: 12px !default;
|
||||||
|
$u-cell-label-color: $u-tips-color !default;
|
||||||
|
$u-cell-label-line-height: 18px !default;
|
||||||
|
$u-cell-value-font-size: 14px !default;
|
||||||
|
$u-cell-value-color: $u-content-color !default;
|
||||||
|
$u-cell-clickable-color: $u-bg-color !default;
|
||||||
|
$u-cell-disabled-color: #c8c9cc !default;
|
||||||
|
$u-cell-padding-top-large: 13px !default;
|
||||||
|
$u-cell-padding-bottom-large: 13px !default;
|
||||||
|
$u-cell-value-font-size-large: 15px !default;
|
||||||
|
$u-cell-label-font-size-large: 14px !default;
|
||||||
|
$u-cell-title-font-size-large: 16px !default;
|
||||||
|
$u-cell-left-icon-wrap-margin-right: 4px !default;
|
||||||
|
$u-cell-right-icon-wrap-margin-left: 4px !default;
|
||||||
|
$u-cell-title-flex:1 !default;
|
||||||
|
$u-cell-label-margin-top:5px !default;
|
||||||
|
|
||||||
|
|
||||||
|
.u-cell {
|
||||||
|
&__body {
|
||||||
|
@include flex();
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* #endif */
|
||||||
|
padding: $u-cell-padding;
|
||||||
|
font-size: $u-cell-font-size;
|
||||||
|
color: $u-cell-color;
|
||||||
|
// line-height: $u-cell-line-height;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
@include flex(row);
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--large {
|
||||||
|
padding-top: $u-cell-padding-top-large;
|
||||||
|
padding-bottom: $u-cell-padding-bottom-large;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__left-icon-wrap,
|
||||||
|
&__right-icon-wrap {
|
||||||
|
@include flex();
|
||||||
|
align-items: center;
|
||||||
|
// height: $u-cell-line-height;
|
||||||
|
font-size: $u-cell-icon-size;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__left-icon-wrap {
|
||||||
|
margin-right: $u-cell-left-icon-wrap-margin-right;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__right-icon-wrap {
|
||||||
|
margin-left: $u-cell-right-icon-wrap-margin-left;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
|
||||||
|
&--up {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
&--down {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
flex: $u-cell-title-flex;
|
||||||
|
|
||||||
|
&-text {
|
||||||
|
font-size: $u-cell-title-font-size;
|
||||||
|
line-height: $u-cell-title-line-height;
|
||||||
|
color: $u-cell-title-color;
|
||||||
|
|
||||||
|
&--large {
|
||||||
|
font-size: $u-cell-title-font-size-large;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
margin-top: $u-cell-label-margin-top;
|
||||||
|
font-size: $u-cell-label-font-size;
|
||||||
|
color: $u-cell-label-color;
|
||||||
|
line-height: $u-cell-label-line-height;
|
||||||
|
|
||||||
|
&--large {
|
||||||
|
font-size: $u-cell-label-font-size-large;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__value {
|
||||||
|
text-align: right;
|
||||||
|
font-size: $u-cell-value-font-size;
|
||||||
|
line-height: $u-cell-line-height;
|
||||||
|
color: $u-cell-value-color;
|
||||||
|
|
||||||
|
&--large {
|
||||||
|
font-size: $u-cell-value-font-size-large;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--clickable {
|
||||||
|
background-color: $u-cell-clickable-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
color: $u-cell-disabled-color;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
cursor: not-allowed;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
&--center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,82 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 标识符
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.checkboxGroup.name
|
||||||
|
},
|
||||||
|
// 绑定的值
|
||||||
|
value: {
|
||||||
|
type: Array,
|
||||||
|
default: uni.$u.props.checkboxGroup.value
|
||||||
|
},
|
||||||
|
// 形状,circle-圆形,square-方形
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.checkboxGroup.shape
|
||||||
|
},
|
||||||
|
// 是否禁用全部checkbox
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.checkboxGroup.disabled
|
||||||
|
},
|
||||||
|
|
||||||
|
// 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.checkboxGroup.activeColor
|
||||||
|
},
|
||||||
|
// 未选中的颜色
|
||||||
|
inactiveColor: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.checkboxGroup.inactiveColor
|
||||||
|
},
|
||||||
|
|
||||||
|
// 整个组件的尺寸,默认px
|
||||||
|
size: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.checkboxGroup.size
|
||||||
|
},
|
||||||
|
// 布局方式,row-横向,column-纵向
|
||||||
|
placement: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.checkboxGroup.placement
|
||||||
|
},
|
||||||
|
// label的字体大小,px单位
|
||||||
|
labelSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.checkboxGroup.labelSize
|
||||||
|
},
|
||||||
|
// label的字体颜色
|
||||||
|
labelColor: {
|
||||||
|
type: [String],
|
||||||
|
default: uni.$u.props.checkboxGroup.labelColor
|
||||||
|
},
|
||||||
|
// 是否禁止点击文本操作
|
||||||
|
labelDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.checkboxGroup.labelDisabled
|
||||||
|
},
|
||||||
|
// 图标颜色
|
||||||
|
iconColor: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.checkboxGroup.iconColor
|
||||||
|
},
|
||||||
|
// 图标的大小,单位px
|
||||||
|
iconSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.checkboxGroup.iconSize
|
||||||
|
},
|
||||||
|
// 勾选图标的对齐方式,left-左边,right-右边
|
||||||
|
iconPlacement: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.checkboxGroup.iconPlacement
|
||||||
|
},
|
||||||
|
// 竖向配列时,是否显示下划线
|
||||||
|
borderBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.checkboxGroup.borderBottom
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="u-checkbox-group"
|
||||||
|
:class="bemClass"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js';
|
||||||
|
/**
|
||||||
|
* checkboxGroup 复选框组
|
||||||
|
* @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
|
||||||
|
* @tutorial https://www.uviewui.com/components/checkbox.html
|
||||||
|
* @property {String} name 标识符
|
||||||
|
* @property {Array} value 绑定的值
|
||||||
|
* @property {String} shape 形状,circle-圆形,square-方形 (默认 'square' )
|
||||||
|
* @property {Boolean} disabled 是否禁用全部checkbox (默认 false )
|
||||||
|
* @property {String} activeColor 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值 (默认 '#2979ff' )
|
||||||
|
* @property {String} inactiveColor 未选中的颜色 (默认 '#c8c9cc' )
|
||||||
|
* @property {String | Number} size 整个组件的尺寸 单位px (默认 18 )
|
||||||
|
* @property {String} placement 布局方式,row-横向,column-纵向 (默认 'row' )
|
||||||
|
* @property {String | Number} labelSize label的字体大小,px单位 (默认 14 )
|
||||||
|
* @property {String} labelColor label的字体颜色 (默认 '#303133' )
|
||||||
|
* @property {Boolean} labelDisabled 是否禁止点击文本操作 (默认 false )
|
||||||
|
* @property {String} iconColor 图标颜色 (默认 '#ffffff' )
|
||||||
|
* @property {String | Number} iconSize 图标的大小,单位px (默认 12 )
|
||||||
|
* @property {String} iconPlacement 勾选图标的对齐方式,left-左边,right-右边 (默认 'left' )
|
||||||
|
* @property {Boolean} borderBottom placement为row时,是否显示下边框 (默认 false )
|
||||||
|
* @event {Function} change 任一个checkbox状态发生变化时触发,回调为一个对象
|
||||||
|
* @event {Function} input 修改通过v-model绑定的值时触发,回调为一个对象
|
||||||
|
* @example <u-checkbox-group></u-checkbox-group>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-checkbox-group',
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
|
||||||
|
computed: {
|
||||||
|
// 这里computed的变量,都是子组件u-checkbox需要用到的,由于头条小程序的兼容性差异,子组件无法实时监听父组件参数的变化
|
||||||
|
// 所以需要手动通知子组件,这里返回一个parentData变量,供watch监听,在其中去通知每一个子组件重新从父组件(u-checkbox-group)
|
||||||
|
// 拉取父组件新的变化后的参数
|
||||||
|
parentData() {
|
||||||
|
return [this.value, this.disabled, this.inactiveColor, this.activeColor, this.size, this.labelDisabled, this.shape,
|
||||||
|
this.iconSize, this.borderBottom, this.placement
|
||||||
|
]
|
||||||
|
},
|
||||||
|
bemClass() {
|
||||||
|
// this.bem为一个computed变量,在mixin中
|
||||||
|
return this.bem('checkbox-group', ['placement'])
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件
|
||||||
|
parentData() {
|
||||||
|
if (this.children.length) {
|
||||||
|
this.children.map(child => {
|
||||||
|
// 判断子组件(u-checkbox)如果有init方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
|
||||||
|
typeof(child.init) === 'function' && child.init()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.children = []
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 将其他的checkbox设置为未选中的状态
|
||||||
|
unCheckedOther(childInstance) {
|
||||||
|
const values = []
|
||||||
|
this.children.map(child => {
|
||||||
|
// 将被选中的checkbox,放到数组中返回
|
||||||
|
if (child.isChecked) {
|
||||||
|
values.push(child.name)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 发出事件
|
||||||
|
this.$emit('change', values)
|
||||||
|
// 修改通过v-model绑定的值
|
||||||
|
this.$emit('input', values)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
|
.u-checkbox-group {
|
||||||
|
|
||||||
|
&--row {
|
||||||
|
@include flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--column {
|
||||||
|
@include flex(column);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,69 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// checkbox的名称
|
||||||
|
name: {
|
||||||
|
type: [String, Number, Boolean],
|
||||||
|
default: uni.$u.props.checkbox.name
|
||||||
|
},
|
||||||
|
// 形状,square为方形,circle为圆型
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.checkbox.shape
|
||||||
|
},
|
||||||
|
// 整体的大小
|
||||||
|
size: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.checkbox.size
|
||||||
|
},
|
||||||
|
// 是否默认选中
|
||||||
|
checked: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.checkbox.checked
|
||||||
|
},
|
||||||
|
// 是否禁用
|
||||||
|
disabled: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: uni.$u.props.checkbox.disabled
|
||||||
|
},
|
||||||
|
// 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.checkbox.activeColor
|
||||||
|
},
|
||||||
|
// 未选中的颜色
|
||||||
|
inactiveColor: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.checkbox.inactiveColor
|
||||||
|
},
|
||||||
|
// 图标的大小,单位px
|
||||||
|
iconSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.checkbox.iconSize
|
||||||
|
},
|
||||||
|
// 图标颜色
|
||||||
|
iconColor: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.checkbox.iconColor
|
||||||
|
},
|
||||||
|
// label提示文字,因为nvue下,直接slot进来的文字,由于特殊的结构,无法修改样式
|
||||||
|
label: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.checkbox.label
|
||||||
|
},
|
||||||
|
// label的字体大小,px单位
|
||||||
|
labelSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.checkbox.labelSize
|
||||||
|
},
|
||||||
|
// label的颜色
|
||||||
|
labelColor: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.checkbox.labelColor
|
||||||
|
},
|
||||||
|
// 是否禁止点击提示语选中复选框
|
||||||
|
labelDisabled: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: uni.$u.props.checkbox.labelDisabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,344 @@
|
||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="u-checkbox"
|
||||||
|
:style="[checkboxStyle]"
|
||||||
|
@tap.stop="wrapperClickHandler"
|
||||||
|
:class="[`u-checkbox-label--${parentData.iconPlacement}`, parentData.borderBottom && parentData.placement === 'column' && 'u-border-bottom']"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="u-checkbox__icon-wrap"
|
||||||
|
@tap.stop="iconClickHandler"
|
||||||
|
:class="iconClasses"
|
||||||
|
:style="[iconWrapStyle]"
|
||||||
|
>
|
||||||
|
<slot name="icon">
|
||||||
|
<u-icon
|
||||||
|
class="u-checkbox__icon-wrap__icon"
|
||||||
|
name="checkbox-mark"
|
||||||
|
:size="elIconSize"
|
||||||
|
:color="elIconColor"
|
||||||
|
/>
|
||||||
|
</slot>
|
||||||
|
</view>
|
||||||
|
<text
|
||||||
|
@tap.stop="labelClickHandler"
|
||||||
|
:style="{
|
||||||
|
color: elDisabled ? elInactiveColor : elLabelColor,
|
||||||
|
fontSize: elLabelSize,
|
||||||
|
lineHeight: elLabelSize
|
||||||
|
}"
|
||||||
|
>{{label}}</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js';
|
||||||
|
/**
|
||||||
|
* checkbox 复选框
|
||||||
|
* @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
|
||||||
|
* @tutorial https://uviewui.com/components/checkbox.html
|
||||||
|
* @property {String | Number | Boolean} name checkbox组件的标示符
|
||||||
|
* @property {String} shape 形状,square为方形,circle为圆型
|
||||||
|
* @property {String | Number} size 整体的大小
|
||||||
|
* @property {Boolean} checked 是否默认选中
|
||||||
|
* @property {String | Boolean} disabled 是否禁用
|
||||||
|
* @property {String} activeColor 选中状态下的颜色,如设置此值,将会覆盖parent的activeColor值
|
||||||
|
* @property {String} inactiveColor 未选中的颜色
|
||||||
|
* @property {String | Number} iconSize 图标的大小,单位px
|
||||||
|
* @property {String} iconColor 图标颜色
|
||||||
|
* @property {String | Number} label label提示文字,因为nvue下,直接slot进来的文字,由于特殊的结构,无法修改样式
|
||||||
|
* @property {String} labelColor label的颜色
|
||||||
|
* @property {String | Number} labelSize label的字体大小,px单位
|
||||||
|
* @property {String | Boolean} labelDisabled 是否禁止点击提示语选中复选框
|
||||||
|
* @property {Object} customStyle 定义需要用到的外部样式
|
||||||
|
*
|
||||||
|
* @event {Function} change 任一个checkbox状态发生变化时触发,回调为一个对象
|
||||||
|
* @example <u-checkbox v-model="checked" :disabled="false">天涯</u-checkbox>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-checkbox",
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isChecked: false,
|
||||||
|
// 父组件的默认值,因为头条小程序不支持在computed中使用this.parent.shape的形式
|
||||||
|
// 故只能使用如此方法
|
||||||
|
parentData: {
|
||||||
|
iconSize: 12,
|
||||||
|
labelDisabled: null,
|
||||||
|
disabled: null,
|
||||||
|
shape: 'square',
|
||||||
|
activeColor: null,
|
||||||
|
inactiveColor: null,
|
||||||
|
size: 18,
|
||||||
|
value: null,
|
||||||
|
iconColor: null,
|
||||||
|
placement: 'row',
|
||||||
|
borderBottom: false,
|
||||||
|
iconPlacement: 'left'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 是否禁用,如果父组件u-raios-group禁用的话,将会忽略子组件的配置
|
||||||
|
elDisabled() {
|
||||||
|
return this.disabled !== '' ? this.disabled : this.parentData.disabled !== null ? this.parentData.disabled : false;
|
||||||
|
},
|
||||||
|
// 是否禁用label点击
|
||||||
|
elLabelDisabled() {
|
||||||
|
return this.labelDisabled !== '' ? this.labelDisabled : this.parentData.labelDisabled !== null ? this.parentData.labelDisabled :
|
||||||
|
false;
|
||||||
|
},
|
||||||
|
// 组件尺寸,对应size的值,默认值为21px
|
||||||
|
elSize() {
|
||||||
|
return this.size ? this.size : (this.parentData.size ? this.parentData.size : 21);
|
||||||
|
},
|
||||||
|
// 组件的勾选图标的尺寸,默认12px
|
||||||
|
elIconSize() {
|
||||||
|
return this.iconSize ? this.iconSize : (this.parentData.iconSize ? this.parentData.iconSize : 12);
|
||||||
|
},
|
||||||
|
// 组件选中激活时的颜色
|
||||||
|
elActiveColor() {
|
||||||
|
return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff');
|
||||||
|
},
|
||||||
|
// 组件选未中激活时的颜色
|
||||||
|
elInactiveColor() {
|
||||||
|
return this.inactiveColor ? this.inactiveColor : (this.parentData.inactiveColor ? this.parentData.inactiveColor :
|
||||||
|
'#c8c9cc');
|
||||||
|
},
|
||||||
|
// label的颜色
|
||||||
|
elLabelColor() {
|
||||||
|
return this.labelColor ? this.labelColor : (this.parentData.labelColor ? this.parentData.labelColor : '#606266')
|
||||||
|
},
|
||||||
|
// 组件的形状
|
||||||
|
elShape() {
|
||||||
|
return this.shape ? this.shape : (this.parentData.shape ? this.parentData.shape : 'circle');
|
||||||
|
},
|
||||||
|
// label大小
|
||||||
|
elLabelSize() {
|
||||||
|
return uni.$u.addUnit(this.labelSize ? this.labelSize : (this.parentData.labelSize ? this.parentData.labelSize :
|
||||||
|
'15'))
|
||||||
|
},
|
||||||
|
elIconColor() {
|
||||||
|
const iconColor = this.iconColor ? this.iconColor : (this.parentData.iconColor ? this.parentData.iconColor :
|
||||||
|
'#ffffff');
|
||||||
|
// 图标的颜色
|
||||||
|
if (this.elDisabled) {
|
||||||
|
// disabled状态下,已勾选的checkbox图标改为elInactiveColor
|
||||||
|
return this.isChecked ? this.elInactiveColor : 'transparent'
|
||||||
|
} else {
|
||||||
|
return this.isChecked ? iconColor : 'transparent'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
iconClasses() {
|
||||||
|
let classes = []
|
||||||
|
// 组件的形状
|
||||||
|
classes.push('u-checkbox__icon-wrap--' + this.elShape)
|
||||||
|
if (this.elDisabled) {
|
||||||
|
classes.push('u-checkbox__icon-wrap--disabled')
|
||||||
|
}
|
||||||
|
if (this.isChecked && this.elDisabled) {
|
||||||
|
classes.push('u-checkbox__icon-wrap--disabled--checked')
|
||||||
|
}
|
||||||
|
// 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
|
||||||
|
// #ifdef MP-ALIPAY || MP-TOUTIAO
|
||||||
|
classes = classes.join(' ')
|
||||||
|
// #endif
|
||||||
|
return classes
|
||||||
|
},
|
||||||
|
iconWrapStyle() {
|
||||||
|
// checkbox的整体样式
|
||||||
|
const style = {}
|
||||||
|
style.backgroundColor = this.isChecked && !this.elDisabled ? this.elActiveColor : '#ffffff'
|
||||||
|
style.borderColor = this.isChecked && !this.elDisabled ? this.elActiveColor : this.elInactiveColor
|
||||||
|
style.width = uni.$u.addUnit(this.elSize)
|
||||||
|
style.height = uni.$u.addUnit(this.elSize)
|
||||||
|
// 如果是图标在右边的话,移除它的右边距
|
||||||
|
if (this.parentData.iconPlacement === 'right') {
|
||||||
|
style.marginRight = 0
|
||||||
|
}
|
||||||
|
return style
|
||||||
|
},
|
||||||
|
checkboxStyle() {
|
||||||
|
const style = {}
|
||||||
|
if (this.parentData.borderBottom && this.parentData.placement === 'row') {
|
||||||
|
uni.$u.error('检测到您将borderBottom设置为true,需要同时将u-checkbox-group的placement设置为column才有效')
|
||||||
|
}
|
||||||
|
// 当父组件设置了显示下边框并且排列形式为纵向时,给内容和边框之间加上一定间隔
|
||||||
|
if (this.parentData.borderBottom && this.parentData.placement === 'column') {
|
||||||
|
style.paddingBottom = '8px'
|
||||||
|
}
|
||||||
|
return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
// 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环引用
|
||||||
|
this.updateParentData()
|
||||||
|
if (!this.parent) {
|
||||||
|
uni.$u.error('u-checkbox必须搭配u-checkbox-group组件使用')
|
||||||
|
}
|
||||||
|
// 设置初始化时,是否默认选中的状态,父组件u-checkbox-group的value可能是array,所以额外判断
|
||||||
|
if (this.checked) {
|
||||||
|
this.isChecked = true
|
||||||
|
} else if (uni.$u.test.array(this.parentData.value)) {
|
||||||
|
// 查找数组是是否存在this.name元素值
|
||||||
|
this.isChecked = this.parentData.value.some(item => {
|
||||||
|
return item === this.name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateParentData() {
|
||||||
|
this.getParentData('u-checkbox-group')
|
||||||
|
},
|
||||||
|
// 横向两端排列时,点击组件即可触发选中事件
|
||||||
|
wrapperClickHandler(e) {
|
||||||
|
this.parentData.iconPlacement === 'right' && this.iconClickHandler(e)
|
||||||
|
},
|
||||||
|
// 点击图标
|
||||||
|
iconClickHandler(e) {
|
||||||
|
this.preventEvent(e)
|
||||||
|
// 如果整体被禁用,不允许被点击
|
||||||
|
if (!this.elDisabled) {
|
||||||
|
this.setRadioCheckedStatus()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 点击label
|
||||||
|
labelClickHandler(e) {
|
||||||
|
this.preventEvent(e)
|
||||||
|
// 如果按钮整体被禁用或者label被禁用,则不允许点击文字修改状态
|
||||||
|
if (!this.elLabelDisabled && !this.elDisabled) {
|
||||||
|
this.setRadioCheckedStatus()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emitEvent() {
|
||||||
|
this.$emit('change', this.isChecked)
|
||||||
|
// 尝试调用u-form的验证方法,进行一定延迟,否则微信小程序更新可能会不及时
|
||||||
|
this.$nextTick(() => {
|
||||||
|
uni.$u.formValidate(this, 'change')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 改变组件选中状态
|
||||||
|
// 这里的改变的依据是,更改本组件的checked值为true,同时通过父组件遍历所有u-checkbox实例
|
||||||
|
// 将本组件外的其他u-checkbox的checked都设置为false(都被取消选中状态),因而只剩下一个为选中状态
|
||||||
|
setRadioCheckedStatus() {
|
||||||
|
// 将本组件标记为与原来相反的状态
|
||||||
|
this.isChecked = !this.isChecked
|
||||||
|
this.emitEvent()
|
||||||
|
typeof this.parent.unCheckedOther === 'function' && this.parent.unCheckedOther(this)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch:{
|
||||||
|
checked(){
|
||||||
|
this.isChecked = this.checked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
$u-checkbox-icon-wrap-margin-right:6px !default;
|
||||||
|
$u-checkbox-icon-wrap-font-size:6px !default;
|
||||||
|
$u-checkbox-icon-wrap-border-width:1px !default;
|
||||||
|
$u-checkbox-icon-wrap-border-color:#c8c9cc !default;
|
||||||
|
$u-checkbox-icon-wrap-icon-line-height:0 !default;
|
||||||
|
$u-checkbox-icon-wrap-circle-border-radius:100% !default;
|
||||||
|
$u-checkbox-icon-wrap-square-border-radius:3px !default;
|
||||||
|
$u-checkbox-icon-wrap-checked-color:#fff !default;
|
||||||
|
$u-checkbox-icon-wrap-checked-background-color:red !default;
|
||||||
|
$u-checkbox-icon-wrap-checked-border-color:#2979ff !default;
|
||||||
|
$u-checkbox-icon-wrap-disabled-background-color:#ebedf0 !default;
|
||||||
|
$u-checkbox-icon-wrap-disabled-checked-color:#c8c9cc !default;
|
||||||
|
$u-checkbox-label-margin-left:5px !default;
|
||||||
|
$u-checkbox-label-margin-right:12px !default;
|
||||||
|
$u-checkbox-label-color:$u-content-color !default;
|
||||||
|
$u-checkbox-label-font-size:15px !default;
|
||||||
|
$u-checkbox-label-disabled-color:#c8c9cc !default;
|
||||||
|
|
||||||
|
.u-checkbox {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
@include flex(row);
|
||||||
|
/* #endif */
|
||||||
|
overflow: hidden;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&-label--left {
|
||||||
|
flex-direction: row
|
||||||
|
}
|
||||||
|
|
||||||
|
&-label--right {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
justify-content: space-between
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon-wrap {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
box-sizing: border-box;
|
||||||
|
// nvue下,border-color过渡有问题
|
||||||
|
transition-property: border-color, background-color, color;
|
||||||
|
transition-duration: 0.2s;
|
||||||
|
/* #endif */
|
||||||
|
color: $u-content-color;
|
||||||
|
@include flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: transparent;
|
||||||
|
text-align: center;
|
||||||
|
margin-right: $u-checkbox-icon-wrap-margin-right;
|
||||||
|
|
||||||
|
font-size: $u-checkbox-icon-wrap-font-size;
|
||||||
|
border-width: $u-checkbox-icon-wrap-border-width;
|
||||||
|
border-color: $u-checkbox-icon-wrap-border-color;
|
||||||
|
border-style: solid;
|
||||||
|
|
||||||
|
/* #ifdef MP-TOUTIAO */
|
||||||
|
// 头条小程序兼容性问题,需要设置行高为0,否则图标偏下
|
||||||
|
&__icon {
|
||||||
|
line-height: $u-checkbox-icon-wrap-icon-line-height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
&--circle {
|
||||||
|
border-radius: $u-checkbox-icon-wrap-circle-border-radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--square {
|
||||||
|
border-radius: $u-checkbox-icon-wrap-square-border-radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--checked {
|
||||||
|
color: $u-checkbox-icon-wrap-checked-color;
|
||||||
|
background-color: $u-checkbox-icon-wrap-checked-background-color;
|
||||||
|
border-color: $u-checkbox-icon-wrap-checked-border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
background-color: $u-checkbox-icon-wrap-disabled-background-color !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--disabled--checked {
|
||||||
|
color: $u-checkbox-icon-wrap-disabled-checked-color !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
word-wrap: break-word;
|
||||||
|
/* #endif */
|
||||||
|
margin-left: $u-checkbox-label-margin-left;
|
||||||
|
margin-right: $u-checkbox-label-margin-right;
|
||||||
|
color: $u-checkbox-label-color;
|
||||||
|
font-size: $u-checkbox-label-font-size;
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
color: $u-checkbox-label-disabled-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,8 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
percentage: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.circleProgress.percentage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
<template>
|
||||||
|
<view class="u-circle-progress">
|
||||||
|
<view class="u-circle-progress__left">
|
||||||
|
<view
|
||||||
|
class="u-circle-progress__left__circle"
|
||||||
|
:style="[leftSyle]"
|
||||||
|
ref="left-circle"
|
||||||
|
>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="u-circle-progress__right"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="u-circle-progress__right__circle"
|
||||||
|
ref="right-circle"
|
||||||
|
:style="[rightSyle]"
|
||||||
|
>
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-circle-progress__circle">
|
||||||
|
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js';
|
||||||
|
// #ifdef APP-NVUE
|
||||||
|
const animation = uni.requireNativePlugin('animation')
|
||||||
|
// #endif
|
||||||
|
/**
|
||||||
|
* CircleProgress 圆形进度条 TODO: 待完善
|
||||||
|
* @description 展示操作或任务的当前进度,比如上传文件,是一个圆形的进度环。
|
||||||
|
* @tutorial https://www.uviewui.com/components/circleProgress.html
|
||||||
|
* @property {String | Number} percentage 圆环进度百分比值,为数值类型,0-100 (默认 30 )
|
||||||
|
* @example
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-circle-progress',
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
leftBorderColor: 'rgb(200, 200, 200)',
|
||||||
|
rightBorderColor: 'rgb(200, 200, 200)',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
leftSyle() {
|
||||||
|
const style = {}
|
||||||
|
style.borderTopColor = this.leftBorderColor
|
||||||
|
style.borderRightColor = this.leftBorderColor
|
||||||
|
return style
|
||||||
|
},
|
||||||
|
rightSyle() {
|
||||||
|
const style = {}
|
||||||
|
style.borderLeftColor = this.rightBorderColor
|
||||||
|
style.borderBottomColor = this.rightBorderColor
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
uni.$u.sleep().then(() => {
|
||||||
|
this.rightBorderColor = 'rgb(66, 185, 131)'
|
||||||
|
// this.init()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
animation.transition(this.$refs['right-circle'].ref, {
|
||||||
|
styles: {
|
||||||
|
transform: 'rotate(45deg)',
|
||||||
|
transformOrigin: 'center center'
|
||||||
|
},
|
||||||
|
}, () => {
|
||||||
|
this.rightBorderColor = 'rgb(66, 185, 131)'
|
||||||
|
// animation.transition(this.$refs['right-circle'].ref, {
|
||||||
|
// styles: {
|
||||||
|
// transform: 'rotate(225deg)',
|
||||||
|
// transformOrigin: 'center center'
|
||||||
|
// },
|
||||||
|
// duration: 3000,
|
||||||
|
// }, () => {
|
||||||
|
// animation.transition(this.$refs['left-circle'].ref, {
|
||||||
|
// styles: {
|
||||||
|
// transform: 'rotate(45deg)',
|
||||||
|
// transformOrigin: 'center center'
|
||||||
|
// },
|
||||||
|
// }, () => {
|
||||||
|
// this.leftBorderColor = 'rgb(66, 185, 131)'
|
||||||
|
// animation.transition(this.$refs['left-circle'].ref, {
|
||||||
|
// styles: {
|
||||||
|
// transform: 'rotate(225deg)',
|
||||||
|
// transformOrigin: 'center center'
|
||||||
|
// },
|
||||||
|
// duration: 1500,
|
||||||
|
// }, () => {
|
||||||
|
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
|
.u-circle-progress {
|
||||||
|
@include flex(row);
|
||||||
|
position: relative;
|
||||||
|
border-radius: 100px;
|
||||||
|
height: 100px;
|
||||||
|
width: 100px;
|
||||||
|
// transform: rotate(0deg);
|
||||||
|
// background-color: rgb(66, 185, 131);
|
||||||
|
background-color: rgb(200, 200, 200);
|
||||||
|
overflow: hidden;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
&__circle {
|
||||||
|
border-radius: 100px;
|
||||||
|
height: 90px;
|
||||||
|
width: 90px;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background-color: rgb(255, 255, 255);
|
||||||
|
left: 50px;
|
||||||
|
top: 50px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__left {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
width: 50px;
|
||||||
|
height: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
// background-color: rgb(66, 185, 131);
|
||||||
|
// background-color: rgb(200, 200, 200);
|
||||||
|
// transform-origin: left center;
|
||||||
|
|
||||||
|
&__circle {
|
||||||
|
box-sizing: border-box;
|
||||||
|
// background-color: red;
|
||||||
|
border-left-color: transparent;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
border-top-left-radius: 50px;
|
||||||
|
border-top-right-radius: 50px;
|
||||||
|
border-bottom-right-radius: 50px;
|
||||||
|
// border-left-color: rgb(66, 185, 131);
|
||||||
|
// border-bottom-color: rgb(66, 185, 131);
|
||||||
|
border-top-color: rgb(66, 185, 131);
|
||||||
|
border-right-color: rgb(66, 185, 131);
|
||||||
|
border-width: 5px;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
transform: rotate(225deg);
|
||||||
|
// border-radius: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__right {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
width: 50px;
|
||||||
|
height: 100px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&__circle {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
// background-color: red;
|
||||||
|
border-top-color: transparent;
|
||||||
|
border-right-color: transparent;
|
||||||
|
border-top-left-radius: 50px;
|
||||||
|
border-bottom-left-radius: 50px;
|
||||||
|
border-bottom-right-radius: 50px;
|
||||||
|
// border-left-color: rgb(66, 185, 131);
|
||||||
|
// border-bottom-color: rgb(66, 185, 131);
|
||||||
|
border-left-color: rgb(200, 200, 200);
|
||||||
|
border-bottom-color: rgb(200, 200, 200);
|
||||||
|
border-width: 5px;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
transform: rotate(45deg);
|
||||||
|
transform-origin: center center;
|
||||||
|
// border-radius: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,79 @@
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 键盘弹起时,是否自动上推页面
|
||||||
|
adjustPosition: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.codeInput.adjustPosition
|
||||||
|
},
|
||||||
|
// 最大输入长度
|
||||||
|
maxlength: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.codeInput.maxlength
|
||||||
|
},
|
||||||
|
// 是否用圆点填充
|
||||||
|
dot: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.codeInput.dot
|
||||||
|
},
|
||||||
|
// 显示模式,box-盒子模式,line-底部横线模式
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.codeInput.mode
|
||||||
|
},
|
||||||
|
// 是否细边框
|
||||||
|
hairline: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.codeInput.hairline
|
||||||
|
},
|
||||||
|
// 字符间的距离
|
||||||
|
space: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.codeInput.space
|
||||||
|
},
|
||||||
|
// 预置值
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.codeInput.value
|
||||||
|
},
|
||||||
|
// 是否自动获取焦点
|
||||||
|
focus: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.codeInput.focus
|
||||||
|
},
|
||||||
|
// 字体是否加粗
|
||||||
|
bold: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.codeInput.bold
|
||||||
|
},
|
||||||
|
// 字体颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.codeInput.color
|
||||||
|
},
|
||||||
|
// 字体大小
|
||||||
|
fontSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.codeInput.fontSize
|
||||||
|
},
|
||||||
|
// 输入框的大小,宽等于高
|
||||||
|
size: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: uni.$u.props.codeInput.size
|
||||||
|
},
|
||||||
|
// 是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true
|
||||||
|
disabledKeyboard: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.codeInput.disabledKeyboard
|
||||||
|
},
|
||||||
|
// 边框和线条颜色
|
||||||
|
borderColor: {
|
||||||
|
type: String,
|
||||||
|
default: uni.$u.props.codeInput.borderColor
|
||||||
|
},
|
||||||
|
// 是否禁止输入"."符号
|
||||||
|
disabledDot: {
|
||||||
|
type: Boolean,
|
||||||
|
default: uni.$u.props.codeInput.disabledDot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,252 @@
|
||||||
|
<template>
|
||||||
|
<view class="u-code-input">
|
||||||
|
<view
|
||||||
|
class="u-code-input__item"
|
||||||
|
:style="[itemStyle(index)]"
|
||||||
|
v-for="(item, index) in codeLength"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
class="u-code-input__item__dot"
|
||||||
|
v-if="dot && codeArray.length > index"
|
||||||
|
></view>
|
||||||
|
<text
|
||||||
|
v-else
|
||||||
|
:style="{
|
||||||
|
fontSize: $u.addUnit(fontSize),
|
||||||
|
fontWeight: bold ? 'bold' : 'normal',
|
||||||
|
color: color
|
||||||
|
}"
|
||||||
|
>{{codeArray[index]}}</text>
|
||||||
|
<view
|
||||||
|
class="u-code-input__item__line"
|
||||||
|
v-if="mode === 'line'"
|
||||||
|
:style="[lineStyle]"
|
||||||
|
></view>
|
||||||
|
<!-- #ifndef APP-PLUS -->
|
||||||
|
<view v-if="isFocus && codeArray.length === index" :style="{backgroundColor: color}" class="u-code-input__item__cursor"></view>
|
||||||
|
<!-- #endif -->
|
||||||
|
</view>
|
||||||
|
<input
|
||||||
|
:disabled="disabledKeyboard"
|
||||||
|
type="number"
|
||||||
|
:focus="focus"
|
||||||
|
:value="inputValue"
|
||||||
|
:maxlength="maxlength"
|
||||||
|
:adjustPosition="adjustPosition"
|
||||||
|
class="u-code-input__input"
|
||||||
|
@input="inputHandler"
|
||||||
|
:style="{
|
||||||
|
height: $u.addUnit(size)
|
||||||
|
}"
|
||||||
|
@focus="isFocus = true"
|
||||||
|
@blur="isFocus = false"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import props from './props.js';
|
||||||
|
/**
|
||||||
|
* CodeInput 验证码输入
|
||||||
|
* @description 该组件一般用于验证用户短信验证码的场景,也可以结合uView的键盘组件使用
|
||||||
|
* @tutorial https://www.uviewui.com/components/codeInput.html
|
||||||
|
* @property {String | Number} maxlength 最大输入长度 (默认 6 )
|
||||||
|
* @property {Boolean} dot 是否用圆点填充 (默认 false )
|
||||||
|
* @property {String} mode 显示模式,box-盒子模式,line-底部横线模式 (默认 'box' )
|
||||||
|
* @property {Boolean} hairline 是否细边框 (默认 false )
|
||||||
|
* @property {String | Number} space 字符间的距离 (默认 10 )
|
||||||
|
* @property {String | Number} value 预置值
|
||||||
|
* @property {Boolean} focus 是否自动获取焦点 (默认 false )
|
||||||
|
* @property {Boolean} bold 字体和输入横线是否加粗 (默认 false )
|
||||||
|
* @property {String} color 字体颜色 (默认 '#606266' )
|
||||||
|
* @property {String | Number} fontSize 字体大小,单位px (默认 18 )
|
||||||
|
* @property {String | Number} size 输入框的大小,宽等于高 (默认 35 )
|
||||||
|
* @property {Boolean} disabledKeyboard 是否隐藏原生键盘,如果想用自定义键盘的话,需设置此参数为true (默认 false )
|
||||||
|
* @property {String} borderColor 边框和线条颜色 (默认 '#c9cacc' )
|
||||||
|
* @property {Boolean} disabledDot 是否禁止输入"."符号 (默认 true )
|
||||||
|
*
|
||||||
|
* @event {Function} change 输入内容发生改变时触发,具体见上方说明 value:当前输入的值
|
||||||
|
* @event {Function} finish 输入字符个数达maxlength值时触发,见上方说明 value:当前输入的值
|
||||||
|
* @example <u-code-input v-model="value4" :focus="true"></u-code-input>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-code-input',
|
||||||
|
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
inputValue: '',
|
||||||
|
isFocus: this.focus
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value: {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
// 转为字符串,超出部分截掉
|
||||||
|
this.inputValue = String(val).substring(0, this.maxlength)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 根据长度,循环输入框的个数,因为头条小程序数值不能用于v-for
|
||||||
|
codeLength() {
|
||||||
|
return new Array(Number(this.maxlength))
|
||||||
|
},
|
||||||
|
// 循环item的样式
|
||||||
|
itemStyle() {
|
||||||
|
return index => {
|
||||||
|
const addUnit = uni.$u.addUnit
|
||||||
|
const style = {
|
||||||
|
width: addUnit(this.size),
|
||||||
|
height: addUnit(this.size)
|
||||||
|
}
|
||||||
|
// 盒子模式下,需要额外进行处理
|
||||||
|
if (this.mode === 'box') {
|
||||||
|
// 设置盒子的边框,如果是细边框,则设置为0.5px宽度
|
||||||
|
style.border = `${this.hairline ? 0.5 : 1}px solid ${this.borderColor}`
|
||||||
|
// 如果盒子间距为0的话
|
||||||
|
if (uni.$u.getPx(this.space) === 0) {
|
||||||
|
// 给第一和最后一个盒子设置圆角
|
||||||
|
if (index === 0) {
|
||||||
|
style.borderTopLeftRadius = '3px'
|
||||||
|
style.borderBottomLeftRadius = '3px'
|
||||||
|
}
|
||||||
|
if (index === this.codeLength.length - 1) {
|
||||||
|
style.borderTopRightRadius = '3px'
|
||||||
|
style.borderBottomRightRadius = '3px'
|
||||||
|
}
|
||||||
|
// 最后一个盒子的右边框需要保留
|
||||||
|
if (index !== this.codeLength.length - 1) {
|
||||||
|
style.borderRight = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index !== this.codeLength.length - 1) {
|
||||||
|
// 设置验证码字符之间的距离,通过margin-right设置,最后一个字符,无需右边框
|
||||||
|
style.marginRight = addUnit(this.space)
|
||||||
|
} else {
|
||||||
|
// 最后一个盒子的有边框需要保留
|
||||||
|
style.marginRight = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 将输入的值,转为数组,给item历遍时,根据当前的索引显示数组的元素
|
||||||
|
codeArray() {
|
||||||
|
return String(this.inputValue).split('')
|
||||||
|
},
|
||||||
|
// 下划线模式下,横线的样式
|
||||||
|
lineStyle() {
|
||||||
|
const style = {}
|
||||||
|
style.height = this.hairline ? '2px' : '4px'
|
||||||
|
style.width = uni.$u.addUnit(this.size)
|
||||||
|
// 线条模式下,背景色即为边框颜色
|
||||||
|
style.backgroundColor = this.borderColor
|
||||||
|
return style
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 监听输入框的值发生变化
|
||||||
|
inputHandler(e) {
|
||||||
|
const value = e.detail.value
|
||||||
|
this.inputValue = value
|
||||||
|
// 是否允许输入“.”符号
|
||||||
|
if(this.disabledDot) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.inputValue = value.replace('.', '')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 未达到maxlength之前,发送change事件,达到后发送finish事件
|
||||||
|
this.$emit('change', value)
|
||||||
|
// 修改通过v-model双向绑定的值
|
||||||
|
this.$emit('input', value)
|
||||||
|
// 达到用户指定输入长度时,发出完成事件
|
||||||
|
if (String(value).length >= Number(this.maxlength)) {
|
||||||
|
this.$emit('finish', value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
$u-code-input-cursor-width: 1px;
|
||||||
|
$u-code-input-cursor-height: 40%;
|
||||||
|
$u-code-input-cursor-animation-duration: 1s;
|
||||||
|
$u-code-input-cursor-animation-name: u-cursor-flicker;
|
||||||
|
|
||||||
|
.u-code-input {
|
||||||
|
@include flex;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
@include flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
font-size: 15px;
|
||||||
|
color: $u-content-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__dot {
|
||||||
|
width: 7px;
|
||||||
|
height: 7px;
|
||||||
|
border-radius: 100px;
|
||||||
|
background-color: $u-content-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__line {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
height: 4px;
|
||||||
|
border-radius: 100px;
|
||||||
|
width: 40px;
|
||||||
|
background-color: $u-content-color;
|
||||||
|
}
|
||||||
|
/* #ifndef APP-PLUS */
|
||||||
|
&__cursor {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%,-50%);
|
||||||
|
width: $u-code-input-cursor-width;
|
||||||
|
height: $u-code-input-cursor-height;
|
||||||
|
animation: $u-code-input-cursor-animation-duration u-cursor-flicker infinite;
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
&__input {
|
||||||
|
// 之所以需要input输入框,是因为有它才能唤起键盘
|
||||||
|
// 这里将它设置为两倍的屏幕宽度,再将左边的一半移出屏幕,为了不让用户看到输入的内容
|
||||||
|
position: absolute;
|
||||||
|
left: -750rpx;
|
||||||
|
width: 1500rpx;
|
||||||
|
top: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* #ifndef APP-PLUS */
|
||||||
|
@keyframes u-cursor-flicker {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
</style>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue