Commit fff13263 by 李嘉林

五粮液-打包

parent 5a6e236b
...@@ -8,30 +8,36 @@ ...@@ -8,30 +8,36 @@
<i class="iconfont icon-tubiao_jiyao-xiangyou"></i> <i class="iconfont icon-tubiao_jiyao-xiangyou"></i>
</div> </div>
</div> </div>
<div v-if="isLoading && showList">
<image class="picture" :src="sourceData.restaurantLogo" mode="aspectFill" alt="" /> <image class="picture" :src="sourceData.restaurantLogo" mode="aspectFill" alt="" />
<div class="title_box"> <div class="title_box">
<div class="title_text">{{sourceData.restaurantName}}</div> <div class="title_text">{{ sourceData.restaurantName }}</div>
<div class="title_tag">{{sourceData.restaurantLabel}}</div> <div class="title_tag">{{ sourceData.restaurantLabel }}</div>
</div> </div>
<div class="price_box flex"> <div class="price_box flex">
<div class="count"> <div class="count">
<span>承接次数</span> <span>承接次数</span>
<span class="price_text">{{sourceData.receiveCount}}</span> <span class="price_text">{{ sourceData.receiveCount }}</span>
</div> </div>
<div class="average"> <div class="average">
<span>人均</span> <span>人均</span>
<span class="price_text">{{sourceData.perCapitaConsumption}}</span> <span class="price_text">{{ sourceData.perCapitaConsumption }}</span>
</div> </div>
</div> </div>
<div class="address"> <div class="address">
<div><i class="iconfont icon-dingwei2"></i></div> <div><i class="iconfont icon-dingwei2"></i></div>
<div class="address_text">{{merchantAddress}}</div> <div class="address_text">{{ merchantAddress }}</div>
</div> </div>
<div class="btn_box"> <div class="btn_box">
<div class="left_btn" @click="linkMerchant">联系商家</div> <div class="left_btn" @click="linkMerchant">联系商家</div>
<div class="right_btn" @click="orderNow">立即预订</div> <div class="right_btn" @click="orderNow">立即预订</div>
</div> </div>
</div> </div>
<div class="noList" v-else>
<image src="http://cdn.mayi888.com/public/jpg/0aac085c-aa79-4ef2-94c8-7bce73f94943.jpg" mode="widthFix" />
<p class="info">当前城市暂无入驻商家,敬请期待</p>
</div>
</div>
</div> </div>
</template> </template>
...@@ -44,37 +50,16 @@ export default { ...@@ -44,37 +50,16 @@ export default {
datas: { datas: {
type: Object, type: Object,
default: () => { default: () => {
return { return {};
// id: "",
// pageCode: 0,
// pageType: 0,
// queueNumber: 0,
// componentName: "图文",
// componentCode: "img-text",
// code: 1,
// componentData: {
// titles: "这是标题",
// abstract:
// "摘要文字 这是一个图文组件,可以上传图片和编辑文字,并且对图片大小、文字大小以及位置进行自定义编辑,快使用它!",
// imageUrl:
// "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2546973851,4267148231&fm=26&gp=0.jpg",
// link: {
// name: "",
// link: ""
// },
// initimgSize: "80%", //图片默认尺寸
// initcharSize: 1,
// initcharAlign: "left",
// initcharSite: "left"
// }
};
} }
} }
}, },
data() { data() {
return { return {
sourceData:{ showList: false,
address:"", isLoading: true,
sourceData: {
address: "",
restaurantLabel: "", restaurantLabel: "",
restaurantLogo: "", restaurantLogo: "",
restaurantName: "", restaurantName: "",
...@@ -85,38 +70,49 @@ export default { ...@@ -85,38 +70,49 @@ export default {
computed: { computed: {
merchantAddress() { merchantAddress() {
const { const {
provinceName="", provinceName = "",
cityName="", cityName = "",
areaName="", areaName = "",
address="" address = ""
} = this.sourceData } = this.sourceData
return provinceName + cityName + areaName + address return provinceName + cityName + areaName + address
} }
}, },
created() {}, created() { },
onLoad(options){ onLoad(options) {
// console.log(options,'商家推荐options') // console.log(options,'商家推荐options')
console.log("当前的地址",wx.getStorageSync('location')); console.log("当前的地址", wx.getStorageSync('location'));
let _this = this let _this = this
wx.getLocation({ wx.getLocation({
type: 'wgs84', type: 'wgs84',
success:function(res){ success: function (res) {
const query = { const query = {
longitude:res.longitude, // 经度 longitude: res.longitude, // 经度
latitude:res.latitude // 纬度 latitude: res.latitude // 纬度
} }
console.log('定位数据',res) console.log('定位数据', res)
goods.getWlyList(query).then(({data:{data}})=>{ goods.getWlyList(query).then((res) => {
_this.isLoading = false;
if (res.code == 200 && res.data) {
_this.showList = true;
_this.sourceData = data; _this.sourceData = data;
console.log(_this.sourceData,"商家数据"); console.log(_this.sourceData, "商家数据");
} else {
_this.showList = false;
// wx.showToast({
// title: '附近暂无餐厅',
// icon: 'none',
// })
}
}) })
}, },
fail:function(err){ fail: function (err) {
console.log('定位失败',err) _this.isLoading = false;
console.log('定位失败', err)
wx.showModal({ wx.showModal({
title: '提示', title: '提示',
content: '定位失败,请检查是否开启了定位服务', content: '定位失败,请检查是否开启了定位服务',
success (res) { success(res) {
if (res.confirm) { if (res.confirm) {
console.log('用户点击确定') console.log('用户点击确定')
} else if (res.cancel) { } else if (res.cancel) {
...@@ -128,25 +124,25 @@ export default { ...@@ -128,25 +124,25 @@ export default {
}) })
}, },
methods: { methods: {
viewMore(){ viewMore() {
let url = "/pages/wxArticle/main?link=" + encodeURIComponent("https://uat-zanmall-m.cipmp.com/#/pages/restaurantList/index"); let url = "/pages/wxArticle/main?link=" + encodeURIComponent("https://uat-zanmall-m.cipmp.com/#/pages/restaurantList/index");
app.$themeToLink({ app.$themeToLink({
type :1.2, type: 1.2,
link : url link: url
}); });
}, },
linkMerchant(){ linkMerchant() {
wx.makePhoneCall({ wx.makePhoneCall({
phoneNumber: this.sourceData.linkPhone phoneNumber: this.sourceData.linkPhone
}) })
}, },
orderNow(){ orderNow() {
let url = 'https://uat-zanmall-m.cipmp.com/#/pages/restaurantInfo/index?restaurantId=' + this.sourceData.id + `${wx.getStorageSync("sessionid")?`&sessionid=${wx.getStorageSync("sessionid")}`:''}` let url = 'https://uat-zanmall-m.cipmp.com/#/pages/restaurantInfo/index?restaurantId=' + this.sourceData.id + `${wx.getStorageSync("sessionid") ? `&sessionid=${wx.getStorageSync("sessionid")}` : ''}`
console.log(url,"立即预订的接口地址"); console.log(url, "立即预订的接口地址");
let link = "/pages/wxArticle/main?link=" + encodeURIComponent(url); let link = "/pages/wxArticle/main?link=" + encodeURIComponent(url);
app.$themeToLink({ app.$themeToLink({
type :1.2, type: 1.2,
link : link link: link
}); });
}, },
} }
...@@ -158,17 +154,31 @@ export default { ...@@ -158,17 +154,31 @@ export default {
overflow: hidden; overflow: hidden;
box-sizing: border-box !important; box-sizing: border-box !important;
} }
.restaurant-list { .restaurant-list {
// height: 320px; // height: 320px;
padding: 12px; padding: 12px;
background: #ffffff; background: #ffffff;
border-radius: 4px; border-radius: 4px;
margin: 10px; margin: 10px;
.header_box { .header_box {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.noList{
image{
width: 40%;
margin: 20px auto 0;
}
.info{
text-align: center;
color: #999;
font-size: 13px;
margin-bottom: 20px;
}
}
.card_title { .card_title {
text-align: center; text-align: center;
text-transform: uppercase; text-transform: uppercase;
...@@ -176,11 +186,13 @@ export default { ...@@ -176,11 +186,13 @@ export default {
color: #0a0a0a; color: #0a0a0a;
font-weight: 600; font-weight: 600;
} }
.see_more { .see_more {
height: 30px; height: 30px;
color: #999999; color: #999999;
display: flex; display: flex;
align-items: center; align-items: center;
// margin-bottom: 12px; // margin-bottom: 12px;
.jt { .jt {
display: inline-block; display: inline-block;
...@@ -193,11 +205,13 @@ export default { ...@@ -193,11 +205,13 @@ export default {
margin-left: 0; margin-left: 0;
} }
} }
.picture { .picture {
width: 100%; width: 100%;
height: 180px; height: 180px;
margin-top: 12px; margin-top: 12px;
} }
.title_box { .title_box {
display: flex; display: flex;
// font-weight: 500; // font-weight: 500;
...@@ -205,9 +219,11 @@ export default { ...@@ -205,9 +219,11 @@ export default {
color: #333333; color: #333333;
align-items: center; align-items: center;
margin-top: 12px; margin-top: 12px;
.title_text { .title_text {
font-weight: 600; font-weight: 600;
} }
.title_tag { .title_tag {
margin-left: 8px; margin-left: 8px;
height: 18px; height: 18px;
...@@ -220,32 +236,39 @@ export default { ...@@ -220,32 +236,39 @@ export default {
padding: 0 6px; padding: 0 6px;
} }
} }
.price_box { .price_box {
margin-top: 6px; margin-top: 6px;
font-size: 12px; font-size: 12px;
color: #666666; color: #666666;
.count { .count {
margin-right: 12px; margin-right: 12px;
} }
.price_text { .price_text {
margin-left: 6px; margin-left: 6px;
color: #e1000f; color: #e1000f;
} }
} }
.address { .address {
margin-top: 12px; margin-top: 12px;
font-size: 14px; font-size: 14px;
display: flex; display: flex;
align-items: center; align-items: center;
.address_text { .address_text {
margin-left: 8px; margin-left: 8px;
} }
} }
.btn_box { .btn_box {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
font-size: 16px; font-size: 16px;
margin-top: 12px; margin-top: 12px;
.left_btn { .left_btn {
padding: 4px 16px; padding: 4px 16px;
background: #ffffff; background: #ffffff;
...@@ -254,6 +277,7 @@ export default { ...@@ -254,6 +277,7 @@ export default {
border: 1px solid #e1000f; border: 1px solid #e1000f;
margin-right: 12px; margin-right: 12px;
} }
.right_btn { .right_btn {
padding: 4px 16px; padding: 4px 16px;
background: #e1000f; background: #e1000f;
......
<template>
<div class="container" :style="{'padding-top':navHeight +'px'}">
<div class="navbar" :style="{'height' : navHeight + 'px','padding-top':navTop+'px'}">
<div @click="toLiveList" class="history-btn">
<span class="iconfont iconzuo"></span>
</div>
<div class="navbar-title">直播计划</div>
</div>
<div class="uprefresh" v-if="isUprefresh">正在刷新...</div>
<div class="no-history" v-if="!list.length">无历史直播</div>
<div class="history-list">
<div class="list-item" v-for="(item,index) in list" :key="index" @click="liveDetail(item)">
<div class="item-top">
<div class="top-img">
<img :src="item.logoUrl" alt="">
</div>
<div class="top-name">{{item.shopName}}</div>
</div>
<div class="item-info">
<div class="info-poster">
<image :src="item.coverUrl" mode="aspectFill" alt=""></image>
</div>
<div class="info-detail">
<div class="detail-name">{{item.title}}</div>
<div class="detail-time">开播时间:{{item.startTime}}</div>
<div class="detail-data">
<div class="look data-icon">
<span class="iconfont iconyanjing"></span>
{{item.watchNum}}
</div>
<div class="thumbs data-icon">
<span class="iconfont iconicon_huabanfuben"></span>
{{item.likeNum}}
</div>
<div class="comment data-icon">
<span class="iconfont iconpinglun"></span>
{{item.guestBookNum}}
</div>
</div>
</div>
</div>
</div>
</div>
<van-divider
class="no-more"
v-if="isNoMore"
contentPosition="center"
customStyle="border-color: #ccc;"
>
已经到底了
</van-divider>
</div>
</template>
<script>
import liveApi from '@/api/liveing'
import { DFSImg,getNavbarInfo } from '../../utils/common.js'
export default {
data(){
return{
list:[],
currentPage : 1,
pageSize : 5,
pages : 0,
navTop : '',
navHeight : '',
isUprefresh :false,
isNoMore : false,
}
},
methods:{
getLiveHandler(type){
if(type == 'init'){
wx.showLoading({
title : '加载中'
})
}
liveApi.queryCompleteLive({
pageSize : this.pageSize,
currentPage : this.currentPage
}).then(res => {
if(res.data.code == '200'){
wx.hideLoading()
this.pages = res.data.pages;
if(type == 'refresh'){
wx.hideNavigationBarLoading();
this.isUprefresh = false;
// 停止下拉动作
wx.stopPullDownRefresh();
res.data.data.forEach(item => {
item.coverUrl = DFSImg(item.coverUrl)
item.logoUrl = DFSImg(item.logoUrl)
item.startTime = `${item.startTime.split(' ')[0]} ${item.startTimeByWeek} ${item.startTime.split(' ')[1].substr(0,5)}`
})
this.list = res.data.data;
}else if(type == 'more'){
res.data.data.forEach(item => {
item.coverUrl = DFSImg(item.coverUrl)
item.logoUrl = DFSImg(item.logoUrl)
item.startTime = `${item.startTime.split(' ')[0]} ${item.startTimeByWeek} ${item.startTime.split(' ')[1].substr(0,5)}`
this.list.push(item)
})
if(res.data.current == res.data.pages){
this.isNoMore = true;
}
}else{
res.data.data.forEach(item => {
item.coverUrl = DFSImg(item.coverUrl)
item.logoUrl = DFSImg(item.logoUrl)
item.startTime = `${item.startTime.split(' ')[0]} ${item.startTimeByWeek} ${item.startTime.split(' ')[1].substr(0,5)}`
})
this.list = res.data.data;
}
}
}).catch(error => {
wx.showToast({ title: error, icon: "none" });
wx.hideLoading()
})
},
liveDetail(item){
wx.navigateTo({url:`../liveOver/main?id=${item.id}&type=3&liveInfo=${JSON.stringify(item)}`})
},
toLiveList(){
wx.reLaunch({url:`../liveList/main`})
}
},
onShow(){
this.isUprefresh = false;
this.isNoMore = false;
this.currentPage = 1;
this.getLiveHandler('init')
},
created(){
//获取导航栏信息
getNavbarInfo((res) => {
this.navTop = res.navTop
this.navHeight = res.navHeight
})
},
onPullDownRefresh(){
this.isUprefresh = true;
this.currentPage = 1;
this.getLiveHandler('refresh');
wx.showNavigationBarLoading();
},
onReachBottom(){
if(this.currentPage < this.pages){
++this.currentPage;
this.getLiveHandler('more');
}
},
}
</script>
<style scoped lang="scss">
img{
width: 100%;
height: 100%;
}
.container{
min-height: 100vh;
background-color: #efefef;
padding-bottom: 24px;
}
.navbar{
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
position: relative;
background-color: white;
width: 100%;
position: fixed;
left: 0;
top: 0;
z-index: 10;
.history-btn{
width: 24px;
height: 24px;
position: absolute;
left: 16px;
.iconfont{
font-size: 15px;
color: #323232;
}
}
.navbar-title{
font-size: 14px;
color: #000;
text-align: center;
}
}
.uprefresh{
line-height: 30px;
font-size: 16px;
color: #999;
text-align: center;
}
.no-history{
text-align: center;
padding-top: 20vh;
font-size: 30px;
color: #999999;
}
.history-list{
width: 100%;
box-sizing: border-box;
padding: 12px 12px 0 12px;
.list-item{
width: 100%;
background-color: white;
border-radius: 4px;
padding: 0 12px 16px;
margin-bottom: 12px;
box-sizing: border-box;
.item-top{
display: flex;
justify-content: flex-start;
align-items: center;
height: 42px;
margin-bottom: 4px;
.top-img{
width: 27px;
height: 27px;
border-radius: 50%;
overflow: hidden;
background-color: #B5B5B5;
margin-right: 6px;
}
.top-name{
font-size: 15px;
color: #333333;
}
}
.item-info{
width: 100%;
display: flex;
justify-content: flex-start;
justify-items: center;
.info-poster{
width: 90px;
height: 90px;
border-radius: 3px;
background-color: #B5B5B5;
margin-right: 16px;
overflow: hidden;
image{
width: 100%;
height: 100%;
}
}
.info-detail{
.detail-name{
font-size: 15px;
color: #333333;
}
.detail-time{
font-size: 13px;
color: #999999;
line-height: 34px;
}
}
.detail-data{
color: #999;
font-size: 13px;
display: flex;
justify-content: flex-start;
align-items: center;
margin-top: 14px;
.data-icon{
margin-right: 16px;
font-size: 13px;
}
}
}
}
}
.no-more{
width: 90%;
line-height: 30px;
font-size: 16px;
color: #999;
text-align: center;
}
</style>
\ No newline at end of file
import Vue from 'vue'
import App from './index'
const app = new Vue(App)
app.$mount()
{
"navigationBarTitleText":"直播计划",
"enablePullDownRefresh":true,
"navigationStyle":"custom",
"usingComponents": {
"van-divider": "/static/vant/divider/index"
}
}
\ No newline at end of file
...@@ -208,6 +208,7 @@ export default { ...@@ -208,6 +208,7 @@ export default {
this.backPath = options.back; this.backPath = options.back;
} }
} }
console.log(this.backPath,'-----backPath')
this.hideBack = options.hideBack == 1?1:0 this.hideBack = options.hideBack == 1?1:0
if (options.params) { if (options.params) {
options.params = decodeURIComponent(options.params); options.params = decodeURIComponent(options.params);
...@@ -592,8 +593,8 @@ export default { ...@@ -592,8 +593,8 @@ export default {
let parseLink=decodeURIComponent(this.backPath); let parseLink=decodeURIComponent(this.backPath);
log.info(this.backPath,parseLink,'---------------------------325') log.info(this.backPath,parseLink,'---------------------------325')
console.log(this.backPath,parseLink,'---------------------------595') console.log(this.backPath,parseLink,this.ossLink, '---------------------------595')
if(parseLink.includes('/pages/')){ if(parseLink.includes('/pages/') && !parseLink.startsWith("http")){
wx.reLaunch({ wx.reLaunch({
url: parseLink url: parseLink
}); });
...@@ -621,7 +622,8 @@ export default { ...@@ -621,7 +622,8 @@ export default {
}); });
}else{ }else{
let parseLink=decodeURIComponent(this.backPath); let parseLink=decodeURIComponent(this.backPath);
let isTabbarIndex =checkTabbarPage(parseLink) let isTabbarIndex = checkTabbarPage(parseLink)
console.log(parseLink,isTabbarIndex,'----isTabbarIndex')
if(isTabbarIndex>-1){ if(isTabbarIndex>-1){
wx.reLaunch({ wx.reLaunch({
url: parseLink == '/' ? '/pages/home/main' : `/pages/tabBar${isTabbarIndex}/main`, url: parseLink == '/' ? '/pages/home/main' : `/pages/tabBar${isTabbarIndex}/main`,
......
<wxs src="./index.wxs" module="computed"></wxs>
<template name="calendar">
<view class="van-calendar">
<header
title="{{ title }}"
showTitle="{{ showTitle }}"
subtitle="{{ subtitle }}"
showSubtitle="{{ showSubtitle }}"
>
<slot name="title" slot="title"></slot>
</header>
<scroll-view class="van-calendar__body" scroll-y scroll-into-view="{{ scrollIntoView }}">
<month
wx:for="{{ computed.getMonths(minDate, maxDate) }}"
wx:key="index"
id="month{{ index }}"
class="month"
data-date="{{ item }}"
date="{{ item }}"
type="{{ type }}"
color="{{ color }}"
minDate="{{ minDate }}"
maxDate="{{ maxDate }}"
showMark="{{ showMark }}"
formatter="{{ formatter }}"
rowHeight="{{ rowHeight }}"
currentDate="{{ currentDate }}"
showSubtitle="{{ showSubtitle }}"
allowSameDay="{{ allowSameDay }}"
showMonthTitle="{{ index !== 0 || !showSubtitle }}"
bind:click="onClickDay"
/>
</scroll-view>
<view class="van-calendar__footer {{ safeAreaInsetBottom ? 'van-calendar__footer--safe-area-inset-bottom' : '' }}">
<slot name="footer"></slot>
</view>
<view class="van-calendar__footer {{ safeAreaInsetBottom ? 'van-calendar__footer--safe-area-inset-bottom' : '' }}">
<van-button
wx:if="{{ showConfirm }}"
round
block
type="danger"
color="{{ color }}"
custom-class="van-calendar__confirm"
disabled="{{ computed.getButtonDisabled(type, currentDate) }}"
nativeType="text"
bind:click="onConfirm"
>
{{ computed.getButtonDisabled(type, currentDate) ? confirmDisabledText : confirmText }}
</van-button>
</view>
</view>
</template>
import { VantComponent } from '../../../common/component';
VantComponent({
props: {
title: {
type: String,
value: '日期选择',
},
subtitle: String,
showTitle: Boolean,
showSubtitle: Boolean,
},
data: {
weekdays: ['日', '一', '二', '三', '四', '五', '六'],
},
methods: {},
});
<view class="van-calendar__header">
<block wx:if="{{ showTitle }}">
<view class="van-calendar__header-title"><slot name="title"></slot></view>
<view class="van-calendar__header-title">{{ title }}</view>
</block>
<view wx:if="{{ showSubtitle }}" class="van-calendar__header-subtitle">
{{ subtitle }}
</view>
<view class="van-calendar__weekdays">
<view wx:for="{{ weekdays }}" wx:key="index" class="van-calendar__weekday">
{{ item }}
</view>
</view>
</view>
@import '../../../common/index.wxss';.van-calendar__header{-webkit-flex-shrink:0;flex-shrink:0;box-shadow:0 2px 10px rgba(125,126,128,.16);box-shadow:var(--calendar-header-box-shadow,0 2px 10px rgba(125,126,128,.16))}.van-calendar__header-subtitle,.van-calendar__header-title{text-align:center;height:44px;height:var(--calendar-header-title-height,44px);font-weight:500;font-weight:var(--font-weight-bold,500);line-height:44px;line-height:var(--calendar-header-title-height,44px)}.van-calendar__header-title+.van-calendar__header-title,.van-calendar__header-title:empty{display:none}.van-calendar__header-title:empty+.van-calendar__header-title{display:block!important}.van-calendar__weekdays{display:-webkit-flex;display:flex}.van-calendar__weekday{-webkit-flex:1;flex:1;text-align:center;font-size:12px;font-size:var(--calendar-weekdays-font-size,12px);line-height:30px;line-height:var(--calendar-weekdays-height,30px)}
\ No newline at end of file
import { VantComponent } from '../../../common/component';
import {
getMonthEndDay,
compareDay,
getPrevDay,
getNextDay,
} from '../../utils';
VantComponent({
props: {
date: {
type: null,
observer: 'setDays',
},
type: {
type: String,
observer: 'setDays',
},
color: String,
minDate: {
type: null,
observer: 'setDays',
},
maxDate: {
type: null,
observer: 'setDays',
},
showMark: Boolean,
rowHeight: [Number, String],
formatter: {
type: null,
observer: 'setDays',
},
currentDate: {
type: [null, Array],
observer: 'setDays',
},
allowSameDay: Boolean,
showSubtitle: Boolean,
showMonthTitle: Boolean,
},
data: {
visible: true,
days: [],
},
methods: {
onClick(event) {
const { index } = event.currentTarget.dataset;
const item = this.data.days[index];
if (item.type !== 'disabled') {
this.$emit('click', item);
}
},
setDays() {
const days = [];
const startDate = new Date(this.data.date);
const year = startDate.getFullYear();
const month = startDate.getMonth();
const totalDay = getMonthEndDay(
startDate.getFullYear(),
startDate.getMonth() + 1
);
for (let day = 1; day <= totalDay; day++) {
const date = new Date(year, month, day);
const type = this.getDayType(date);
let config = {
date,
type,
text: day,
bottomInfo: this.getBottomInfo(type),
};
if (this.data.formatter) {
config = this.data.formatter(config);
}
days.push(config);
}
this.setData({ days });
},
getMultipleDayType(day) {
const { currentDate } = this.data;
if (!Array.isArray(currentDate)) {
return '';
}
const isSelected = (date) =>
currentDate.some((item) => compareDay(item, date) === 0);
if (isSelected(day)) {
const prevDay = getPrevDay(day);
const nextDay = getNextDay(day);
const prevSelected = isSelected(prevDay);
const nextSelected = isSelected(nextDay);
if (prevSelected && nextSelected) {
return 'multiple-middle';
}
if (prevSelected) {
return 'end';
}
return nextSelected ? 'start' : 'multiple-selected';
}
return '';
},
getRangeDayType(day) {
const { currentDate, allowSameDay } = this.data;
if (!Array.isArray(currentDate)) {
return;
}
const [startDay, endDay] = currentDate;
if (!startDay) {
return;
}
const compareToStart = compareDay(day, startDay);
if (!endDay) {
return compareToStart === 0 ? 'start' : '';
}
const compareToEnd = compareDay(day, endDay);
if (compareToStart === 0 && compareToEnd === 0 && allowSameDay) {
return 'start-end';
}
if (compareToStart === 0) {
return 'start';
}
if (compareToEnd === 0) {
return 'end';
}
if (compareToStart > 0 && compareToEnd < 0) {
return 'middle';
}
},
getDayType(day) {
const { type, minDate, maxDate, currentDate } = this.data;
if (compareDay(day, minDate) < 0 || compareDay(day, maxDate) > 0) {
return 'disabled';
}
if (type === 'single') {
return compareDay(day, currentDate) === 0 ? 'selected' : '';
}
if (type === 'multiple') {
return this.getMultipleDayType(day);
}
/* istanbul ignore else */
if (type === 'range') {
return this.getRangeDayType(day);
}
},
getBottomInfo(type) {
if (this.data.type === 'range') {
if (type === 'start') {
return '开始';
}
if (type === 'end') {
return '结束';
}
if (type === 'start-end') {
return '开始/结束';
}
}
},
},
});
<wxs src="./index.wxs" module="computed"></wxs>
<wxs src="../../../wxs/utils.wxs" module="utils" />
<view class="van-calendar__month" style="{{ computed.getMonthStyle(visible, date, rowHeight) }}">
<view wx:if="{{ showMonthTitle }}" class="van-calendar__month-title">
{{ computed.formatMonthTitle(date) }}
</view>
<view wx:if="{{ visible }}" class="van-calendar__days">
<view wx:if="{{ showMark }}" class="van-calendar__month-mark">
{{ computed.getMark(date) }}
</view>
<view
wx:for="{{ days }}"
wx:key="index"
style="{{ computed.getDayStyle(item.type, index, date, rowHeight, color) }}"
class="{{ utils.bem('calendar__day', [item.type]) }} {{ item.className }}"
data-index="{{ index }}"
bindtap="onClick"
>
<view wx:if="{{ item.type === 'selected' }}" class="van-calendar__selected-day" style="background: {{ color }}">
<view wx:if="{{ item.topInfo }}" class="van-calendar__top-info">{{ item.topInfo }}</view>
{{ item.text }}
<view wx:if="{{ item.bottomInfo }}" class="van-calendar__bottom-info">
{{ item.bottomInfo }}
</view>
</view>
<view wx:else>
<view wx:if="{{ item.topInfo }}" class="van-calendar__top-info">{{ item.topInfo }}</view>
{{ item.text }}
<view wx:if="{{ item.bottomInfo }}" class="van-calendar__bottom-info">
{{ item.bottomInfo }}
</view>
</view>
</view>
</view>
</view>
/* eslint-disable */
var utils = require('../../utils.wxs');
function getMark(date) {
return getDate(date).getMonth() + 1;
}
var ROW_HEIGHT = 64;
function getDayStyle(type, index, date, rowHeight, color) {
var style = [];
var offset = getDate(date).getDay();
if (index === 0) {
style.push(['margin-left', (100 * offset) / 7 + '%']);
}
if (rowHeight !== ROW_HEIGHT) {
style.push(['height', rowHeight + 'px']);
}
if (color) {
if (
type === 'start' ||
type === 'end' ||
type === 'multiple-selected' ||
type === 'multiple-middle'
) {
style.push(['background', color]);
} else if (type === 'middle') {
style.push(['color', color]);
}
}
return style
.map(function(item) {
return item.join(':');
})
.join(';');
}
function formatMonthTitle(date) {
date = getDate(date);
return date.getFullYear() + '年' + (date.getMonth() + 1) + '月';
}
function getMonthStyle(visible, date, rowHeight) {
if (!visible) {
date = getDate(date);
var totalDay = utils.getMonthEndDay(
date.getFullYear(),
date.getMonth() + 1
);
var offset = getDate(date).getDay();
var padding = Math.ceil((totalDay + offset) / 7) * rowHeight;
return 'padding-bottom:' + padding + 'px';
}
}
module.exports = {
getMark: getMark,
getDayStyle: getDayStyle,
formatMonthTitle: formatMonthTitle,
getMonthStyle: getMonthStyle
};
@import '../../../common/index.wxss';.van-calendar{display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;height:100%;background-color:#fff;background-color:var(--calendar-background-color,#fff)}.van-calendar__month-title{text-align:center;height:44px;height:var(--calendar-header-title-height,44px);font-weight:500;font-weight:var(--font-weight-bold,500);font-size:14px;font-size:var(--calendar-month-title-font-size,14px);line-height:44px;line-height:var(--calendar-header-title-height,44px)}.van-calendar__days{position:relative;display:-webkit-flex;display:flex;-webkit-flex-wrap:wrap;flex-wrap:wrap;-webkit-user-select:none;user-select:none}.van-calendar__month-mark{position:absolute;top:50%;left:50%;z-index:0;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);pointer-events:none;color:rgba(242,243,245,.8);color:var(--calendar-month-mark-color,rgba(242,243,245,.8));font-size:160px;font-size:var(--calendar-month-mark-font-size,160px)}.van-calendar__day,.van-calendar__selected-day{display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;text-align:center}.van-calendar__day{position:relative;width:14.285%;height:64px;height:var(--calendar-day-height,64px);font-size:16px;font-size:var(--calendar-day-font-size,16px)}.van-calendar__day--end,.van-calendar__day--multiple-middle,.van-calendar__day--multiple-selected,.van-calendar__day--start,.van-calendar__day--start-end{color:#fff;color:var(--calendar-range-edge-color,#fff);background-color:#ee0a24;background-color:var(--calendar-range-edge-background-color,#ee0a24)}.van-calendar__day--start{border-radius:4px 0 0 4px;border-radius:var(--border-radius-md,4px) 0 0 var(--border-radius-md,4px)}.van-calendar__day--end{border-radius:0 4px 4px 0;border-radius:0 var(--border-radius-md,4px) var(--border-radius-md,4px) 0}.van-calendar__day--multiple-selected,.van-calendar__day--start-end{border-radius:4px;border-radius:var(--border-radius-md,4px)}.van-calendar__day--middle{color:#ee0a24;color:var(--calendar-range-middle-color,#ee0a24)}.van-calendar__day--middle:after{position:absolute;top:0;right:0;bottom:0;left:0;background-color:currentColor;content:"";opacity:.1;opacity:var(--calendar-range-middle-background-opacity,.1)}.van-calendar__day--disabled{cursor:default;color:#c8c9cc;color:var(--calendar-day-disabled-color,#c8c9cc)}.van-calendar__bottom-info,.van-calendar__top-info{position:absolute;right:0;left:0;font-size:10px;font-size:var(--calendar-info-font-size,10px);line-height:14px;line-height:var(--calendar-info-line-height,14px)}@media (max-width:350px){.van-calendar__bottom-info,.van-calendar__top-info{font-size:9px}}.van-calendar__top-info{top:6px}.van-calendar__bottom-info{bottom:6px}.van-calendar__selected-day{width:54px;width:var(--calendar-selected-day-size,54px);height:54px;height:var(--calendar-selected-day-size,54px);color:#fff;color:var(--calendar-selected-day-color,#fff);background-color:#ee0a24;background-color:var(--calendar-selected-day-background-color,#ee0a24);border-radius:4px;border-radius:var(--border-radius-md,4px)}
\ No newline at end of file
import { VantComponent } from '../common/component';
import {
ROW_HEIGHT,
getNextDay,
compareDay,
copyDates,
calcDateNum,
formatMonthTitle,
compareMonth,
getMonths,
getDayByOffset,
} from './utils';
import Toast from '../toast/toast';
import { requestAnimationFrame } from '../common/utils';
VantComponent({
props: {
title: {
type: String,
value: '日期选择',
},
color: String,
show: {
type: Boolean,
observer(val) {
if (val) {
this.initRect();
this.scrollIntoView();
}
},
},
formatter: null,
confirmText: {
type: String,
value: '确定',
},
rangePrompt: String,
defaultDate: {
type: [Number, Array],
observer(val) {
this.setData({ currentDate: val });
this.scrollIntoView();
},
},
allowSameDay: Boolean,
confirmDisabledText: String,
type: {
type: String,
value: 'single',
observer: 'reset',
},
minDate: {
type: null,
value: Date.now(),
},
maxDate: {
type: null,
value: new Date(
new Date().getFullYear(),
new Date().getMonth() + 6,
new Date().getDate()
).getTime(),
},
position: {
type: String,
value: 'bottom',
},
rowHeight: {
type: [Number, String],
value: ROW_HEIGHT,
},
round: {
type: Boolean,
value: true,
},
poppable: {
type: Boolean,
value: true,
},
showMark: {
type: Boolean,
value: true,
},
showTitle: {
type: Boolean,
value: true,
},
showConfirm: {
type: Boolean,
value: true,
},
showSubtitle: {
type: Boolean,
value: true,
},
safeAreaInsetBottom: {
type: Boolean,
value: true,
},
closeOnClickOverlay: {
type: Boolean,
value: true,
},
maxRange: {
type: [Number, String],
value: null,
},
},
data: {
subtitle: '',
currentDate: null,
scrollIntoView: '',
},
created() {
this.setData({
currentDate: this.getInitialDate(),
});
},
mounted() {
if (this.data.show || !this.data.poppable) {
this.initRect();
this.scrollIntoView();
}
},
methods: {
reset() {
this.setData({ currentDate: this.getInitialDate() });
this.scrollIntoView();
},
initRect() {
if (this.contentObserver != null) {
this.contentObserver.disconnect();
}
const contentObserver = this.createIntersectionObserver({
thresholds: [0, 0.1, 0.9, 1],
observeAll: true,
});
this.contentObserver = contentObserver;
contentObserver.relativeTo('.van-calendar__body');
contentObserver.observe('.month', (res) => {
if (res.boundingClientRect.top <= res.relativeRect.top) {
// @ts-ignore
this.setData({ subtitle: formatMonthTitle(res.dataset.date) });
}
});
},
getInitialDate() {
const { type, defaultDate, minDate } = this.data;
if (type === 'range') {
const [startDay, endDay] = defaultDate || [];
return [
startDay || minDate,
endDay || getNextDay(new Date(minDate)).getTime(),
];
}
if (type === 'multiple') {
return defaultDate || [minDate];
}
return defaultDate || minDate;
},
scrollIntoView() {
requestAnimationFrame(() => {
const {
currentDate,
type,
show,
poppable,
minDate,
maxDate,
} = this.data;
// @ts-ignore
const targetDate = type === 'single' ? currentDate : currentDate[0];
const displayed = show || !poppable;
if (!targetDate || !displayed) {
return;
}
const months = getMonths(minDate, maxDate);
months.some((month, index) => {
if (compareMonth(month, targetDate) === 0) {
this.setData({ scrollIntoView: `month${index}` });
return true;
}
return false;
});
});
},
onOpen() {
this.$emit('open');
},
onOpened() {
this.$emit('opened');
},
onClose() {
this.$emit('close');
},
onClosed() {
this.$emit('closed');
},
onClickDay(event) {
const { date } = event.detail;
const { type, currentDate, allowSameDay } = this.data;
if (type === 'range') {
// @ts-ignore
const [startDay, endDay] = currentDate;
if (startDay && !endDay) {
const compareToStart = compareDay(date, startDay);
if (compareToStart === 1) {
this.select([startDay, date], true);
} else if (compareToStart === -1) {
this.select([date, null]);
} else if (allowSameDay) {
this.select([date, date]);
}
} else {
this.select([date, null]);
}
} else if (type === 'multiple') {
let selectedIndex;
// @ts-ignore
const selected = currentDate.some((dateItem, index) => {
const equal = compareDay(dateItem, date) === 0;
if (equal) {
selectedIndex = index;
}
return equal;
});
if (selected) {
// @ts-ignore
const cancelDate = currentDate.splice(selectedIndex, 1);
this.setData({ currentDate });
this.unselect(cancelDate);
} else {
// @ts-ignore
this.select([...currentDate, date]);
}
} else {
this.select(date, true);
}
},
unselect(dateArray) {
const date = dateArray[0];
if (date) {
this.$emit('unselect', copyDates(date));
}
},
select(date, complete) {
if (complete && this.data.type === 'range') {
const valid = this.checkRange(date);
if (!valid) {
// auto selected to max range if showConfirm
if (this.data.showConfirm) {
this.emit([
date[0],
getDayByOffset(date[0], this.data.maxRange - 1),
]);
} else {
this.emit(date);
}
return;
}
}
this.emit(date);
if (complete && !this.data.showConfirm) {
this.onConfirm();
}
},
emit(date) {
const getTime = (date) => (date instanceof Date ? date.getTime() : date);
this.setData({
currentDate: Array.isArray(date) ? date.map(getTime) : getTime(date),
});
this.$emit('select', copyDates(date));
},
checkRange(date) {
const { maxRange, rangePrompt } = this.data;
if (maxRange && calcDateNum(date) > maxRange) {
Toast({
context: this,
message: rangePrompt || `选择天数不能超过 ${maxRange} 天`,
});
return false;
}
return true;
},
onConfirm() {
if (
this.data.type === 'range' &&
!this.checkRange(this.data.currentDate)
) {
return;
}
wx.nextTick(() => {
// @ts-ignore
this.$emit('confirm', copyDates(this.data.currentDate));
});
},
},
});
{
"component": true,
"usingComponents": {
"header": "./components/header/index",
"month": "./components/month/index",
"van-button": "../button/index",
"van-popup": "../popup/index",
"van-toast": "../toast/index"
}
}
<wxs src="./index.wxs" module="computed" />
<import src="./calendar.wxml" />
<van-popup
wx:if="{{ poppable }}"
custom-class="van-calendar__popup--{{ position }}"
close-icon-class="van-calendar__close-icon"
show="{{ show }}"
round="{{ round }}"
position="{{ position }}"
closeable="{{ showTitle || showSubtitle }}"
close-on-click-overlay="{{ closeOnClickOverlay }}"
bind:enter="onOpen"
bind:close="onClose"
bind:after-enter="onOpened"
bind:after-leave="onClosed"
>
<template
is="calendar"
data="{{ title, subtitle, showTitle, showSubtitle, minDate, maxDate, type, color, showMark, formatter, rowHeight, currentDate, safeAreaInsetBottom, showConfirm, confirmDisabledText, confirmText, scrollIntoView, allowSameDay }}"
/>
</van-popup>
<template
wx:else
is="calendar"
data="{{ title, subtitle, showTitle, showSubtitle, minDate, maxDate, type, color, showMark, formatter, rowHeight, currentDate, safeAreaInsetBottom, showConfirm, confirmDisabledText, confirmText, scrollIntoView, allowSameDay }}"
/>
<van-toast id="van-toast" />
/* eslint-disable */
var utils = require('./utils.wxs');
function getMonths(minDate, maxDate) {
var months = [];
var cursor = getDate(minDate);
cursor.setDate(1);
do {
months.push(cursor.getTime());
cursor.setMonth(cursor.getMonth() + 1);
} while (utils.compareMonth(cursor, getDate(maxDate)) !== 1);
return months;
}
function getButtonDisabled(type, currentDate) {
if (currentDate == null) {
return true;
}
if (type === 'range') {
return !currentDate[0] || !currentDate[1];
}
if (type === 'multiple') {
return !currentDate.length;
}
return !currentDate;
}
module.exports = {
getMonths: getMonths,
getButtonDisabled: getButtonDisabled
};
@import '../common/index.wxss';.van-calendar{display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;height:100%;height:var(--calendar-height,100%);background-color:#fff;background-color:var(--calendar-background-color,#fff)}.van-calendar__close-icon{top:11px}.van-calendar__popup--bottom,.van-calendar__popup--top{height:80%;height:var(--calendar-popup-height,80%)}.van-calendar__popup--left,.van-calendar__popup--right{height:100%}.van-calendar__body{-webkit-flex:1;flex:1;overflow:auto;-webkit-overflow-scrolling:touch}.van-calendar__footer{-webkit-flex-shrink:0;flex-shrink:0;padding:0 16px;padding:0 var(--padding-md,16px)}.van-calendar__footer--safe-area-inset-bottom{padding-bottom:env(safe-area-inset-bottom)}.van-calendar__footer+.van-calendar__footer,.van-calendar__footer:empty{display:none}.van-calendar__footer:empty+.van-calendar__footer{display:block!important}.van-calendar__confirm{height:36px!important;height:var(--calendar-confirm-button-height,36px)!important;margin:7px 0!important;margin:var(--calendar-confirm-button-margin,7px 0)!important;line-height:34px!important;line-height:var(--calendar-confirm-button-line-height,34px)!important}
\ No newline at end of file
export declare const ROW_HEIGHT = 64;
export declare function formatMonthTitle(date: Date): string;
export declare function compareMonth(
date1: Date | number,
date2: Date | number
): 0 | 1 | -1;
export declare function compareDay(
day1: Date | number,
day2: Date | number
): 0 | 1 | -1;
export declare function getDayByOffset(date: Date, offset: number): Date;
export declare function getPrevDay(date: Date): Date;
export declare function getNextDay(date: Date): Date;
export declare function calcDateNum(date: [Date, Date]): number;
export declare function copyDates(dates: Date | Date[]): Date | Date[];
export declare function getMonthEndDay(year: number, month: number): number;
export declare function getMonths(minDate: number, maxDate: number): number[];
export const ROW_HEIGHT = 64;
export function formatMonthTitle(date) {
if (!(date instanceof Date)) {
date = new Date(date);
}
return `${date.getFullYear()}${date.getMonth() + 1}月`;
}
export function compareMonth(date1, date2) {
if (!(date1 instanceof Date)) {
date1 = new Date(date1);
}
if (!(date2 instanceof Date)) {
date2 = new Date(date2);
}
const year1 = date1.getFullYear();
const year2 = date2.getFullYear();
const month1 = date1.getMonth();
const month2 = date2.getMonth();
if (year1 === year2) {
return month1 === month2 ? 0 : month1 > month2 ? 1 : -1;
}
return year1 > year2 ? 1 : -1;
}
export function compareDay(day1, day2) {
if (!(day1 instanceof Date)) {
day1 = new Date(day1);
}
if (!(day2 instanceof Date)) {
day2 = new Date(day2);
}
const compareMonthResult = compareMonth(day1, day2);
if (compareMonthResult === 0) {
const date1 = day1.getDate();
const date2 = day2.getDate();
return date1 === date2 ? 0 : date1 > date2 ? 1 : -1;
}
return compareMonthResult;
}
export function getDayByOffset(date, offset) {
date = new Date(date);
date.setDate(date.getDate() + offset);
return date;
}
export function getPrevDay(date) {
return getDayByOffset(date, -1);
}
export function getNextDay(date) {
return getDayByOffset(date, 1);
}
export function calcDateNum(date) {
const day1 = new Date(date[0]).getTime();
const day2 = new Date(date[1]).getTime();
return (day2 - day1) / (1000 * 60 * 60 * 24) + 1;
}
export function copyDates(dates) {
if (Array.isArray(dates)) {
return dates.map((date) => {
if (date === null) {
return date;
}
return new Date(date);
});
}
return new Date(dates);
}
export function getMonthEndDay(year, month) {
return 32 - new Date(year, month - 1, 32).getDate();
}
export function getMonths(minDate, maxDate) {
const months = [];
const cursor = new Date(minDate);
cursor.setDate(1);
do {
months.push(cursor.getTime());
cursor.setMonth(cursor.getMonth() + 1);
} while (compareMonth(cursor, maxDate) !== 1);
return months;
}
/* eslint-disable */
function getMonthEndDay(year, month) {
return 32 - getDate(year, month - 1, 32).getDate();
}
function compareMonth(date1, date2) {
date1 = getDate(date1);
date2 = getDate(date2);
var year1 = date1.getFullYear();
var year2 = date2.getFullYear();
var month1 = date1.getMonth();
var month2 = date2.getMonth();
if (year1 === year2) {
return month1 === month2 ? 0 : month1 > month2 ? 1 : -1;
}
return year1 > year2 ? 1 : -1;
}
module.exports = {
getMonthEndDay: getMonthEndDay,
compareMonth: compareMonth
};
/// <reference types="miniprogram-api-typings" />
declare type CanvasContext = WechatMiniprogram.CanvasContext;
export declare function adaptor(
ctx: CanvasContext & Record<string, unknown>
): CanvasContext;
export {};
export function adaptor(ctx) {
// @ts-ignore
return Object.assign(ctx, {
setStrokeStyle(val) {
ctx.strokeStyle = val;
},
setLineWidth(val) {
ctx.lineWidth = val;
},
setLineCap(val) {
ctx.lineCap = val;
},
setFillStyle(val) {
ctx.fillStyle = val;
},
setFontSize(val) {
ctx.font = String(val);
},
setGlobalAlpha(val) {
ctx.globalAlpha = val;
},
setLineJoin(val) {
ctx.lineJoin = val;
},
setTextAlign(val) {
ctx.textAlign = val;
},
setMiterLimit(val) {
ctx.miterLimit = val;
},
setShadow(offsetX, offsetY, blur, color) {
ctx.shadowOffsetX = offsetX;
ctx.shadowOffsetY = offsetY;
ctx.shadowBlur = blur;
ctx.shadowColor = color;
},
setTextBaseline(val) {
ctx.textBaseline = val;
},
createCircularGradient() {},
draw() {},
});
}
import { VantComponent } from '../common/component';
import { BLUE, WHITE } from '../common/color';
import { adaptor } from './canvas';
import { isObj } from '../common/validator';
import { getSystemInfoSync } from '../common/utils';
function format(rate) {
return Math.min(Math.max(rate, 0), 100);
}
const PERIMETER = 2 * Math.PI;
const BEGIN_ANGLE = -Math.PI / 2;
const STEP = 1;
VantComponent({
props: {
text: String,
lineCap: {
type: String,
value: 'round',
},
value: {
type: Number,
value: 0,
observer: 'reRender',
},
speed: {
type: Number,
value: 50,
},
size: {
type: Number,
value: 100,
observer() {
this.drawCircle(this.currentValue);
},
},
fill: String,
layerColor: {
type: String,
value: WHITE,
},
color: {
type: [String, Object],
value: BLUE,
observer() {
this.setHoverColor().then(() => {
this.drawCircle(this.currentValue);
});
},
},
type: {
type: String,
value: '',
},
strokeWidth: {
type: Number,
value: 4,
},
clockwise: {
type: Boolean,
value: true,
},
},
data: {
hoverColor: BLUE,
},
methods: {
getContext() {
const { type, size } = this.data;
if (type === '') {
const ctx = wx.createCanvasContext('van-circle', this);
return Promise.resolve(ctx);
}
const dpr = getSystemInfoSync().pixelRatio;
return new Promise((resolve) => {
wx.createSelectorQuery()
.in(this)
.select('#van-circle')
.node()
.exec((res) => {
const canvas = res[0].node;
const ctx = canvas.getContext(type);
if (!this.inited) {
this.inited = true;
canvas.width = size * dpr;
canvas.height = size * dpr;
ctx.scale(dpr, dpr);
}
resolve(adaptor(ctx));
});
});
},
setHoverColor() {
const { color, size } = this.data;
if (isObj(color)) {
return this.getContext().then((context) => {
const LinearColor = context.createLinearGradient(size, 0, 0, 0);
Object.keys(color)
.sort((a, b) => parseFloat(a) - parseFloat(b))
.map((key) =>
LinearColor.addColorStop(parseFloat(key) / 100, color[key])
);
this.hoverColor = LinearColor;
});
}
this.hoverColor = color;
return Promise.resolve();
},
presetCanvas(context, strokeStyle, beginAngle, endAngle, fill) {
const { strokeWidth, lineCap, clockwise, size } = this.data;
const position = size / 2;
const radius = position - strokeWidth / 2;
context.setStrokeStyle(strokeStyle);
context.setLineWidth(strokeWidth);
context.setLineCap(lineCap);
context.beginPath();
context.arc(position, position, radius, beginAngle, endAngle, !clockwise);
context.stroke();
if (fill) {
context.setFillStyle(fill);
context.fill();
}
},
renderLayerCircle(context) {
const { layerColor, fill } = this.data;
this.presetCanvas(context, layerColor, 0, PERIMETER, fill);
},
renderHoverCircle(context, formatValue) {
const { clockwise } = this.data;
// 结束角度
const progress = PERIMETER * (formatValue / 100);
const endAngle = clockwise
? BEGIN_ANGLE + progress
: 3 * Math.PI - (BEGIN_ANGLE + progress);
this.presetCanvas(context, this.hoverColor, BEGIN_ANGLE, endAngle);
},
drawCircle(currentValue) {
const { size } = this.data;
this.getContext().then((context) => {
context.clearRect(0, 0, size, size);
this.renderLayerCircle(context);
const formatValue = format(currentValue);
if (formatValue !== 0) {
this.renderHoverCircle(context, formatValue);
}
context.draw();
});
},
reRender() {
// tofector 动画暂时没有想到好的解决方案
const { value, speed } = this.data;
if (speed <= 0 || speed > 1000) {
this.drawCircle(value);
return;
}
this.clearInterval();
this.currentValue = this.currentValue || 0;
this.interval = setInterval(() => {
if (this.currentValue !== value) {
if (this.currentValue < value) {
this.currentValue += STEP;
} else {
this.currentValue -= STEP;
}
this.drawCircle(this.currentValue);
} else {
this.clearInterval();
}
}, 1000 / speed);
},
clearInterval() {
if (this.interval) {
clearInterval(this.interval);
this.interval = null;
}
},
},
mounted() {
this.currentValue = this.data.value;
this.setHoverColor().then(() => {
this.drawCircle(this.currentValue);
});
},
destroyed() {
this.clearInterval();
},
});
<wxs src="../wxs/utils.wxs" module="utils" />
<view class="van-circle">
<canvas class="van-circle__canvas" type="{{ type }}" style="width: {{ utils.addUnit(size) }};height:{{ utils.addUnit(size) }}" id="van-circle" canvas-id="van-circle"></canvas>
<view wx:if="{{ !text }}" class="van-circle__text">
<slot></slot>
</view>
<cover-view wx:else class="van-circle__text">{{ text }}</cover-view>
</view>
@import '../common/index.wxss';.van-circle{position:relative;display:inline-block;text-align:center}.van-circle__text{position:absolute;top:50%;left:0;width:100%;-webkit-transform:translateY(-50%);transform:translateY(-50%);color:#323233;color:var(--circle-text-color,#323233)}
\ No newline at end of file
import { GREEN } from '../common/color';
import { VantComponent } from '../common/component';
import { getRect } from '../common/utils';
import { pageScrollMixin } from '../mixins/page-scroll';
const indexList = () => {
const indexList = [];
const charCodeOfA = 'A'.charCodeAt(0);
for (let i = 0; i < 26; i++) {
indexList.push(String.fromCharCode(charCodeOfA + i));
}
return indexList;
};
VantComponent({
relation: {
name: 'index-anchor',
type: 'descendant',
current: 'index-bar',
linked() {
this.updateData();
},
unlinked() {
this.updateData();
},
},
props: {
sticky: {
type: Boolean,
value: true,
},
zIndex: {
type: Number,
value: 1,
},
highlightColor: {
type: String,
value: GREEN,
},
stickyOffsetTop: {
type: Number,
value: 0,
},
indexList: {
type: Array,
value: indexList(),
},
},
mixins: [
pageScrollMixin(function (event) {
this.scrollTop =
(event === null || event === void 0 ? void 0 : event.scrollTop) || 0;
this.onScroll();
}),
],
data: {
activeAnchorIndex: null,
showSidebar: false,
},
created() {
this.scrollTop = 0;
},
methods: {
updateData() {
wx.nextTick(() => {
if (this.timer != null) {
clearTimeout(this.timer);
}
this.timer = setTimeout(() => {
this.setData({
showSidebar: !!this.children.length,
});
this.setRect().then(() => {
this.onScroll();
});
}, 0);
});
},
setRect() {
return Promise.all([
this.setAnchorsRect(),
this.setListRect(),
this.setSiderbarRect(),
]);
},
setAnchorsRect() {
return Promise.all(
this.children.map((anchor) =>
getRect(anchor, '.van-index-anchor-wrapper').then((rect) => {
Object.assign(anchor, {
height: rect.height,
top: rect.top + this.scrollTop,
});
})
)
);
},
setListRect() {
return getRect(this, '.van-index-bar').then((rect) => {
Object.assign(this, {
height: rect.height,
top: rect.top + this.scrollTop,
});
});
},
setSiderbarRect() {
return getRect(this, '.van-index-bar__sidebar').then((res) => {
this.sidebar = {
height: res.height,
top: res.top,
};
});
},
setDiffData({ target, data }) {
const diffData = {};
Object.keys(data).forEach((key) => {
if (target.data[key] !== data[key]) {
diffData[key] = data[key];
}
});
if (Object.keys(diffData).length) {
target.setData(diffData);
}
},
getAnchorRect(anchor) {
return getRect(anchor, '.van-index-anchor-wrapper').then((rect) => ({
height: rect.height,
top: rect.top,
}));
},
getActiveAnchorIndex() {
const { children, scrollTop } = this;
const { sticky, stickyOffsetTop } = this.data;
for (let i = this.children.length - 1; i >= 0; i--) {
const preAnchorHeight = i > 0 ? children[i - 1].height : 0;
const reachTop = sticky ? preAnchorHeight + stickyOffsetTop : 0;
if (reachTop + scrollTop >= children[i].top) {
return i;
}
}
return -1;
},
onScroll() {
const { children = [], scrollTop } = this;
if (!children.length) {
return;
}
const { sticky, stickyOffsetTop, zIndex, highlightColor } = this.data;
const active = this.getActiveAnchorIndex();
this.setDiffData({
target: this,
data: {
activeAnchorIndex: active,
},
});
if (sticky) {
let isActiveAnchorSticky = false;
if (active !== -1) {
isActiveAnchorSticky =
children[active].top <= stickyOffsetTop + scrollTop;
}
children.forEach((item, index) => {
if (index === active) {
let wrapperStyle = '';
let anchorStyle = `
color: ${highlightColor};
`;
if (isActiveAnchorSticky) {
wrapperStyle = `
height: ${children[index].height}px;
`;
anchorStyle = `
position: fixed;
top: ${stickyOffsetTop}px;
z-index: ${zIndex};
color: ${highlightColor};
`;
}
this.setDiffData({
target: item,
data: {
active: true,
anchorStyle,
wrapperStyle,
},
});
} else if (index === active - 1) {
const currentAnchor = children[index];
const currentOffsetTop = currentAnchor.top;
const targetOffsetTop =
index === children.length - 1
? this.top
: children[index + 1].top;
const parentOffsetHeight = targetOffsetTop - currentOffsetTop;
const translateY = parentOffsetHeight - currentAnchor.height;
const anchorStyle = `
position: relative;
transform: translate3d(0, ${translateY}px, 0);
z-index: ${zIndex};
color: ${highlightColor};
`;
this.setDiffData({
target: item,
data: {
active: true,
anchorStyle,
},
});
} else {
this.setDiffData({
target: item,
data: {
active: false,
anchorStyle: '',
wrapperStyle: '',
},
});
}
});
}
},
onClick(event) {
this.scrollToAnchor(event.target.dataset.index);
},
onTouchMove(event) {
const sidebarLength = this.children.length;
const touch = event.touches[0];
const itemHeight = this.sidebar.height / sidebarLength;
let index = Math.floor((touch.clientY - this.sidebar.top) / itemHeight);
if (index < 0) {
index = 0;
} else if (index > sidebarLength - 1) {
index = sidebarLength - 1;
}
this.scrollToAnchor(index);
},
onTouchStop() {
this.scrollToAnchorIndex = null;
},
scrollToAnchor(index) {
if (typeof index !== 'number' || this.scrollToAnchorIndex === index) {
return;
}
this.scrollToAnchorIndex = index;
const anchor = this.children.find(
(item) => item.data.index === this.data.indexList[index]
);
if (anchor) {
anchor.scrollIntoView(this.scrollTop);
this.$emit('select', anchor.data.index);
}
},
},
});
<view class="van-index-bar">
<slot />
<view
wx:if="{{ showSidebar }}"
class="van-index-bar__sidebar"
catch:tap="onClick"
catch:touchmove="onTouchMove"
catch:touchend="onTouchStop"
catch:touchcancel="onTouchStop"
>
<view
wx:for="{{ indexList }}"
wx:key="index"
class="van-index-bar__index"
style="z-index: {{ zIndex + 1 }}; color: {{ activeAnchorIndex === index ? highlightColor : '' }}"
data-index="{{ index }}"
>
{{ item }}
</view>
</view>
</view>
@import '../common/index.wxss';.van-index-bar{position:relative}.van-index-bar__sidebar{position:fixed;top:50%;right:0;display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;text-align:center;-webkit-transform:translateY(-50%);transform:translateY(-50%);-webkit-user-select:none;user-select:none}.van-index-bar__index{font-weight:500;padding:0 4px 0 16px;padding:0 var(--padding-base,4px) 0 var(--padding-md,16px);font-size:10px;font-size:var(--index-bar-index-font-size,10px);line-height:14px;line-height:var(--index-bar-index-line-height,14px)}
\ No newline at end of file
import { VantComponent } from '../common/component';
import { touch } from '../mixins/touch';
import { range } from '../common/utils';
const THRESHOLD = 0.3;
let ARRAY = [];
VantComponent({
props: {
disabled: Boolean,
leftWidth: {
type: Number,
value: 0,
observer(leftWidth = 0) {
if (this.offset > 0) {
this.swipeMove(leftWidth);
}
},
},
rightWidth: {
type: Number,
value: 0,
observer(rightWidth = 0) {
if (this.offset < 0) {
this.swipeMove(-rightWidth);
}
},
},
asyncClose: Boolean,
name: {
type: [Number, String],
value: '',
},
},
mixins: [touch],
data: {
catchMove: false,
wrapperStyle: '',
},
created() {
this.offset = 0;
ARRAY.push(this);
},
destroyed() {
ARRAY = ARRAY.filter((item) => item !== this);
},
methods: {
open(position) {
const { leftWidth, rightWidth } = this.data;
const offset = position === 'left' ? leftWidth : -rightWidth;
this.swipeMove(offset);
this.$emit('open', {
position,
name: this.data.name,
});
},
close() {
this.swipeMove(0);
},
swipeMove(offset = 0) {
this.offset = range(offset, -this.data.rightWidth, this.data.leftWidth);
const transform = `translate3d(${this.offset}px, 0, 0)`;
const transition = this.dragging
? 'none'
: 'transform .6s cubic-bezier(0.18, 0.89, 0.32, 1)';
this.setData({
wrapperStyle: `
-webkit-transform: ${transform};
-webkit-transition: ${transition};
transform: ${transform};
transition: ${transition};
`,
});
},
swipeLeaveTransition() {
const { leftWidth, rightWidth } = this.data;
const { offset } = this;
if (rightWidth > 0 && -offset > rightWidth * THRESHOLD) {
this.open('right');
} else if (leftWidth > 0 && offset > leftWidth * THRESHOLD) {
this.open('left');
} else {
this.swipeMove(0);
}
this.setData({ catchMove: false });
},
startDrag(event) {
if (this.data.disabled) {
return;
}
this.startOffset = this.offset;
this.touchStart(event);
},
noop() {},
onDrag(event) {
if (this.data.disabled) {
return;
}
this.touchMove(event);
if (this.direction !== 'horizontal') {
return;
}
this.dragging = true;
ARRAY.filter((item) => item !== this).forEach((item) => item.close());
this.setData({ catchMove: true });
this.swipeMove(this.startOffset + this.deltaX);
},
endDrag() {
if (this.data.disabled) {
return;
}
this.dragging = false;
this.swipeLeaveTransition();
},
onClick(event) {
const { key: position = 'outside' } = event.currentTarget.dataset;
this.$emit('click', position);
if (!this.offset) {
return;
}
if (this.data.asyncClose) {
this.$emit('close', {
position,
instance: this,
name: this.data.name,
});
} else {
this.swipeMove(0);
}
},
},
});
<view
class="van-swipe-cell custom-class"
data-key="cell"
catchtap="onClick"
bindtouchstart="startDrag"
catchtouchmove="{{ catchMove ? 'noop' : '' }}"
capture-bind:touchmove="onDrag"
bindtouchend="endDrag"
bindtouchcancel="endDrag"
>
<view style="{{ wrapperStyle }}">
<view wx:if="{{ leftWidth }}" class="van-swipe-cell__left" data-key="left" catch:tap="onClick">
<slot name="left" />
</view>
<slot />
<view wx:if="{{ rightWidth }}" class="van-swipe-cell__right" data-key="right" catch:tap="onClick">
<slot name="right" />
</view>
</view>
</view>
@import '../common/index.wxss';.van-swipe-cell{position:relative;overflow:hidden}.van-swipe-cell__left,.van-swipe-cell__right{position:absolute;top:0;height:100%}.van-swipe-cell__left{left:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.van-swipe-cell__right{right:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment