作者 倪静楠

1

正在显示 100 个修改的文件 包含 3830 行增加0 行删除

要显示太多修改。

为保证性能只显示 100 of 100+ 个文件。

{ // 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": [{
"type": "uniCloud",
"default": {
"launchtype": "local"
}
}
]
}
... ...
<script>
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style lang="scss">
/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
@import "uview-ui/index.scss";
</style>
\ No newline at end of file
... ...
.conetnt {}
.inputBox {
height: 104rpx;
opacity: 1;
background: #ffffff;
border-bottom: 2rpx solid #EBEDF0;
display: flex;
align-items: center;
}
input {
width: 80%;
background: #f7f8fa;
margin: 0 auto;
padding: 16rpx;
border-radius: 48rpx;
font-size: 28rpx;
color: #C8C9CC;
}
.selectBox {
height: 100rpx;
opacity: 1;
background: #ffffff;
display: flex;
justify-content: space-around;
align-items: center;
font-size: 28rpx;
color: #969799;
}
.active {
color: #FF2F2F;
}
.selectItem image {
width: 24rpx;
height: 24rpx;
}
.selectItemActive {
color: #FF2F2F;
}
/* 分类 */
.classBox {
display: flex;
}
.leftBox {
width: 200rpx;
background-color: #f7f8fa;
}
.rightBox {
flex: 1;
}
.leftItem {
font-size: 28rpx;
color: #969799;
height: 40rpx;
line-height: 40rpx;
text-align: center;
height: 100rpx;
line-height: 100rpx;
}
.leftActive {
background-color: #fff;
}
.itemImg {
margin-right: 32rpx;
}
.itemImg image {
width: 152rpx;
height: 152rpx;
}
.rightItem {
display: flex;
padding: 30rpx;
box-sizing: border-box;
border-bottom: 2rpx solid #ebedf0;
}
.lastItem {
border-bottom-color: #fff;
}
.goodName {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
font-size: 28rpx;
color: #323233;
}
.goodDeatil {
font-size: 24rpx;
font-weight: 400;
text-align: LEFT;
color: #c8c9cc;
margin-top: 8rpx;
}
.cartImg image {
width: 40rpx;
height: 40rpx;
}
.goodPrice {
display: flex;
justify-content: space-between;
margin-top: 30rpx;
}
.price {
font-size: 28rpx;
color: #323233;
}
/* 购物车 */
.cartBox {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
padding: 32rpx;
box-sizing: border-box;
background-color: #fff;
border-radius: 32rpx 32rpx 0px 0px;
z-index: 4;
}
.cartGoodInner {
display: flex;
}
.cartImg {
margin-right: 24rpx;
}
.cartImage {
width: 120rpx !important;
height: 120rpx !important;
}
.cartName {
width: 406rpx;
overflow: hidden;
text-overflow: ellipsis;
font-size: 32rpx;
color: #323233;
white-space: nowrap;
}
.cartPrice {
font-size: 28rpx;
color: #FE0E1F;
margin-top: 40rpx;
}
.countBox {
display: flex;
justify-content: space-between;
margin-top: 40rpx;
}
.reduceImg {
width: 60rpx;
height: 60rpx;
background-color: #f2f3f5;
line-height: 60rpx;
margin-left: 10rpx;
text-align: center;
border-radius: 4rpx;
}
.countNum {
width: 60rpx;
height: 60rpx;
background-color: #f2f3f5;
line-height: 60rpx;
margin-left: 10rpx;
text-align: center;
border-radius: 4rpx;
}
.addImg {
width: 60rpx;
height: 60rpx;
background-color: #f2f3f5;
line-height: 60rpx;
margin-left: 10rpx;
text-align: center;
border-radius: 4rpx;
}
/* 购物车规格 */
.specificationBox {}
.specificalItem {
margin-top: 28rpx;
font-size: 26rpx;
background: aliceblue;
color: #323233;
background: #f7f8fa;
border-radius: 48px;
width: auto;
padding: 10rpx 24rpx;
margin-right: 16rpx;
}
/* 遮罩层 */
.masks {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
background-color: #323233;
opacity: 0.6;
}
.addCartBtn {
margin-top: 26rpx;
width: 100%;
height: 80rpx;
background-color: #FF2F2F;
color: #fff;
font-size: 28rpx;
line-height: 80rpx;
text-align: center;
border-radius:8rpx;
}
... ...
.content {
min-height: 100vh;
background-color: #f7f8fa;
padding-bottom: 150rpx;
}
.swiper {
height: 100%;
}
.swiperImg {
width: 100%;
height: 100%;
}
.goodNameOuter {
background-color: #fff;
padding: 32rpx;
box-sizing: border-box;
}
.goodNameOuter {
font-size: 40rpx;
color: #F85317;
}
.goodName {
font-size: 28rpx;
color: #000;
}
.num {
width: 100%;
text-align: right;
color: #C8C9CC;
font-size: 24rpx;
}
.guigeBox {
background-color: #fff;
margin-top: 24rpx;
height: 108rpx;
line-height: 108rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24rpx;
box-sizing: border-box;
font-size: 28rpx;
}
/* 评价 */
.evaluateBox {
background-color: #fff;
padding: 24rpx;
box-sizing: border-box;
}
.evaluateBoxTop {
display: flex;
padding-bottom: 24rpx;
border-bottom: 2rpx solid #ebedf0;
justify-content: space-between;
align-items: center;
}
.evaImg {
width: 8rpx;
height: 36rpx;
}
.pingjiaText {
padding-left: 16rpx;
font-size: 32rpx;
color: #323233;
font-weight: 500;
}
.moreBox {
font-size: 28rpx;
color: #969799;
display: flex;
align-items: cneter;
}
.moerImg {
width: 32rpx;
height: 32rpx;
margin-top: 4rpx;
}
.evaluateContent {
padding: 24rpx 0;
box-sizing: border-box;
}
.userBox {
display: flex;
justify-content: space-between;
}
.userLeftBox {
display: flex;
font-size: 28rpx;
}
.userImg {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
}
.userName {
margin-left: 26rpx;
}
.xing {
width: 20rpx;
height: 20rpx;
}
.time {
font-size: 24rpx;
color: #c8c9cc;
}
.evaluateTEXT {
font-size: 26rpx;
color: #323233;
margin-top: 26rpx;
}
/* 商品详情 */
.goodDetail {
background-color: #fff;
padding: 32rpx;
box-sizing: border-box;
margin-top: 26rpx;
}
.detailImgBox {
margin-top: 24rpx;
}
/* 底部 */
.bottomBox {
width: 100%;
position: fixed;
bottom: 0;
left: 0;
background-color: #fff;
display: flex;
justify-content: space-between;
align-items: center;
left: 0;
bottom: 0;
padding: 32rpx;
box-sizing: border-box;
font-size: 26rpx;
}
.bottomIcon {
width: 40rpx;
height: 40rpx;
font-size: 24rpx;
color: #646566;
}
.botttomleft {
display: flex;
}
.leftItem {
padding: 0 20rpx;
text-align: center;
}
.bottomRight {
width: 236rpx;
height: 80rpx;
opacity: 1;
background: #ff2f2f;
border-radius: 8rpx;
line-height: 80rpx;
color: #fff;
text-align: center;
}
/* 购物车 */
.cartBox {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
padding: 32rpx;
box-sizing: border-box;
background-color: #fff;
border-radius: 32rpx 32rpx 0px 0px;
z-index: 4;
}
.cartGoodInner {
display: flex;
}
.cartImg {
margin-right: 24rpx;
}
.cartImage {
width: 120rpx !important;
height: 120rpx !important;
}
.cartName {
width: 406rpx;
overflow: hidden;
text-overflow: ellipsis;
font-size: 32rpx;
color: #323233;
white-space: nowrap;
}
.cartPrice {
font-size: 28rpx;
color: #FE0E1F;
margin-top: 40rpx;
}
.countBox {
display: flex;
justify-content: space-between;
margin-top: 40rpx;
}
.reduceImg {
width: 60rpx;
height: 60rpx;
background-color: #f2f3f5;
line-height: 60rpx;
margin-left: 10rpx;
text-align: center;
border-radius: 4rpx;
}
.countNum {
width: 60rpx;
height: 60rpx;
background-color: #f2f3f5;
line-height: 60rpx;
margin-left: 10rpx;
text-align: center;
border-radius: 4rpx;
}
.addImg {
width: 60rpx;
height: 60rpx;
background-color: #f2f3f5;
line-height: 60rpx;
margin-left: 10rpx;
text-align: center;
border-radius: 4rpx;
}
/* 购物车规格 */
.specificationBox {}
.specificalItem {
margin-top: 28rpx;
font-size: 26rpx;
background: aliceblue;
color: #323233;
background: #f7f8fa;
border-radius: 48px;
width: auto;
padding: 10rpx 24rpx;
margin-right: 16rpx;
}
.activespecificalItem{
background-color:#FF2F2F;
color: #fff;
}
/* 遮罩层 */
.masks {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
background-color: #323233;
opacity: 0.6;
}
.addCartBtn {
margin-top: 26rpx;
width: 100%;
height: 80rpx;
background-color: #FF2F2F;
color: #fff;
font-size: 28rpx;
line-height: 80rpx;
text-align: center;
border-radius: 8rpx;
}
/* 分享弹框 */
.shareBox {
background-color: #fff;
position: fixed;
bottom: 0;
left: 0;
padding:48rpx 0 0 0;
box-sizing: border-box;
width: 100%;
text-align: center;
border-radius: 48rpx 48rpx 0 0;
z-index: 9;
}
.share{
width:96rpx;
height: 96rpx;
}
.weixinFriend{
font-size: 24rpx;
color: #d0d0d0;
padding: 10rpx 0;
}
.concelBtn{
padding:26rpx 0;
box-sizing: border-box;
width: 100%;
text-align: center;
font-size: 28rpx;
color:#646566;
border-top:16rpx solid #f7f8fa;
}
... ...
.pinBox {
background: #ffffff;
border-radius: 10px;
margin-bottom: 18rpx;
width: 48%;
}
.spin {
background: #F8F8F8;
padding: 0 32rpx;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.fu {
color: #FE0E1F;
font-size: 24rpx;
}
.money {
color: #FE0E1F;
font-size: 32rpx;
}
.unTitle {
color: #06121F;
font-size: 28rpx;
font-weight: bold;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.reTui {
color: #323233;
font-size: 36rpx;
font-weight: bold;
}
.tbt {
padding: 32rpx;
background: #F8F8F8;
}
.content {}
.topTab {
display: flex;
flex-direction: column;
align-items: center;
min-width: 25%;
margin-bottom: 24rpx;
}
.title {
color: #323233;
font-size: 28rpx;
}
.showBac {
background: #FF2F2F;
height: 110px;
border-radius: 0 0 75rpx 75rpx;
}
.seave {
padding: 18rpx 32rpx;
position: fixed;
top: 0;
left: 0;
width: 100%;
background: #FF2F2F;
z-index: 2;
}
.van-search__content {
border-radius: 28rpx !important;
}
... ...
.topBj {
width: 100%;
height: 520rpx;
background-color: #FF2F2F;
position: fixed;
top: 0;
left: 0;
}
.content {
padding: 0 32rpx;
box-sizing: border-box;
min-height: 100vh;
background-color: #f7f8fa;
}
.noToken {
display: flex;
/* align-items: center; */
margin-top: 220rpx;
justify-content: space-between;
place-items: center;
padding: 0 32rpx ;
box-sizing: border-box;
/* position: absolute; */
}
.headInfo{
display: flex;
place-items: center;
}
.changeToShop{
display: flex;
flex-direction: column;
place-items: center;
}
.changeInfo{
margin-top: 8rpx;
font-size: 26rpx;
font-weight: 400;
color: #ffffff;
}
.noTokenImg {
width: 116rpx;
border-radius: 50%;
height: 116rpx;
}
.loginText {
padding-left: 24rpx;
font-size: 36rpx;
color: #fff;
flex: 1;
}
.orderBox {
background-color: #fff;
border-radius: 24rpx;
position: absolute;
top: 370rpx;
left: 4%;
width: 92%;
}
.topBox {
padding: 32rpx;
box-sizing: border-box;
border-bottom: 2rpx solid #F2F3F5;
display: flex;
justify-content: space-between;
align-items: center;
}
.allText {
font-size: 28rpx;
color: #323233;
}
.lookALL {
font-size: 28rpx;
color: #C8C9CC;
display: flex;
align-items: center;
}
.lookALL image{
width: 32rpx;
height: 32rpx;
}
.orderListBpox{
display: flex;
justify-content: space-between;
padding: 32rpx;
box-sizing: border-box;
}
.orderItem{
font-size: 24rpx;
color: #323233;
position: relative;
}
.orderItem image{
width: 64rpx;
height: 64rpx;
}
.orderItem>view{
margin-top:32rpx;
}
.myFuwu{
width: 100%;
opacity: 1;
background: #ffffff;
border-radius: 16px;
}
.fuwutext{
font-size:28rpx;
font-weight: 600;
color: #323233;
padding: 34rpx;
box-sizing: border-box;
border-bottom: 2rpx solid #ebedf0;
}
.fuwuItem{
padding: 34rpx ;
box-sizing: border-box;
font-size: 28rpx;
color: #323233;
display: flex;
align-items: center;
}
.fuwuItem>text{
padding-left: 34rpx;
}
.fuwuItem image{
width: 36rpx;
height: 36rpx;
}
.orderNum{
padding: 4rpx;
box-sizing: border-box;
color: #ffffff;
font-size: 16rpx;
border-radius: 50%;
background: #FF2F2F;
position: absolute;
right: 0;
tpo: -20rpx;
}
... ...
.content {
min-height: 100vh;
background-color: #f7f8fa;
}
.topList {
display: flex;
justify-content: space-around;
align-items: center;
}
.tabItem {
font-size: 28rpx;
color: #323233;
padding: 24rpx 0;
}
.active {
border-bottom: 4rpx solid #FF2F2F;
color: #FF2F2F;
}
/* 订单 */
.orderItem {
margin-top: 18rpx;
padding: 32rpx;
box-sizing: border-box;
background-color: #fff;
}
.itemTop {
display: flex;
justify-content: space-between;
}
..itemTops {
display: flex;
}
.imageBox {
margin-right: 32rpx;
}
.imageBox image {
width: 120rpx;
height: 120rpx;
border-radius: 8rpx;
}
.titleBox {
width: 354rpx;
font-size: 26rpx;
color: #000;
}
.status {
font-size: 26rpx;
color: #FF2F2F;
text-align: right;
}
.price {
font-size: 24rpx;
margin-top: 10rpx;
margin-right:-4rpx;
text-align: right;
}
.num {
font-size: 26rpx;
color: #969799;
text-align: right;
}
.btnBox {
display: flex;
justify-content: flex-end;
margin-top: 10rpx;
}
.btnBox>view {
padding: 12rpx 26rpx;
box-sizing: border-box;
border: 2rpx solid #c8c9cc;
border-radius: 8rpx;
font-size: 26rpx;
color: #323233;
margin-left: 30rpx;
text-align: center;
line-height: 40rpx;
}
.moreImg{
width: 120rpx;
height: 120rpx;
margin-right: 10rpx;
border-radius: 8rpx;
}
.noDataBox{
padding-top: 50rpx;
box-sizing: border-box;
text-align: center;
}
.noDataImg{
width: 200rpx;
height: 200rpx;
}
.noData{
font-size: 28rpx;
color: #c6c7c9;
width: 100%;
text-align: center;
margin-top: 40rpx;
}
\ No newline at end of file
... ...
.li {
padding: 9px 32rpx 0 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.lishi {
color: #323233;
font-size: 32rpx;
font-weight: bold;
}
.close {
color: #323233;
font-size: 32rpx;
}
.seave {
margin: 16rpx 32rpx;
display: flex;
align-items: center;
}
.van-search__content {
border-radius: 28rpx !important;
}
.huiBox {
background-color: #F2F3F5;
padding: 10rpx 32rpx;
border-radius: 58rpx;
margin-right: 16rpx;
margin-bottom: 16rpx;
}
.huiText {
color: #969799;
font-size: 26rpx;
}
.jiList {
display: flex;
margin: 24rpx 32rpx;
flex-wrap: wrap;
}
.zhezhao {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.3);
display: flex;
justify-content: center;
align-items: center;
z-index: 999;
}
.boxs {
height: 240rpx;
background-color: #FFFFFF;
margin: 0 64rpx;
border-radius: 28rpx;
}
.okDel {
color: #323233;
font-size: 32rpx;
}
.qren {
color: #FF2F2F;
font-size: 32rpx;
}
.kbox {
width: 50%;
display: flex;
align-items: center;
justify-content: center;
border-right: 1px solid #EBEDF0;
}
.kbo {
width: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.kuangBox {
display: flex;
height: 96rpx;
border-top: 1px solid #EBEDF0;
}
.resultBox {
width: 100%;
padding: 110rpx 24rpx 0rpx;
box-sizing: border-box;
}
.item {
display: flex;
justify-content: space-between;
width: 100%;
border-bottom: 1rpx solid #dfdfdf;
font-size: 28rpx;
padding: 0 0 28rpx 0;
align-items: center;
}
... ...
.LeftTop {
color: #646566;
font-size: 26rpx;
}
.content {
background-color: #F7F8FA;
min-height: 100vh;
position: relative;
}
.Toptt {
padding: 26rpx 32rpx 0 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.LeftTopgl {
color: #323233;
font-size: 32rpx;
font-weight: bold;
}
.LeftTopwc {
color: #323233;
font-size: 32rpx;
font-weight: bold;
}
.jian {
color: #323233;
margin: 27rpx 16rpx;
}
.jia {
color: #323233;
margin: 16rpx;
}
.shuliang {
color: #333333;
font-size: 28rpx;
margin: 10rpx 16rpx;
}
.moneyBiao {
color: #F85317;
font-size: 24rpx;
margin-right: -4rpx;
}
.money {
color: #F85317;
font-size: 34rpx;
}
.bianOne {
height: 56rpx;
background: #f2f3f5;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
width: 56rpx;
}
.bianTwo {
height: 56rpx;
background: #f2f3f5;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
margin: 0 4rpx;
width: 56rpx;
}
.bianThree {
height: 56rpx;
background: #f2f3f5;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
width: 56rpx;
}
.goodNum{
padding: 4rpx 10rpx;
box-sizing: border-box;
border: 2rpx solid #c8c9cc;
border-radius: 8rpx;
color: #323233;
font-size: 28rpx;
}
.onList {
display: flex;
align-items: center;
background-color: #FFFFFF;
margin: 24rpx 32rpx;
border-radius: 24rpx;
height: 236rpx;
}
.guige {
color: #969799;
font-size: 26rpx;
}
.TitText {
max-width: 288rpx;
overflow: hidden;
text-overflow: ellipsis;
}
.title {
color: #323233;
font-size: 28rpx;
white-space: nowrap;
}
.TitMoney {
display: flex;
align-items: center;
justify-content: space-between;
}
.onAll {
display: flex;
align-items: center;
}
.onSel {
margin: 0 26rpx;
}
.select {
color: #646566;
font-size: 26rpx;
margin-left: 10rpx;
}
.BtnMoney {
color: #F85317;
font-size: 26rpx;
margin: 0 16rpx;
}
.jiesuan {
color: #FFFFFF;
font-size: 26rpx;
}
.JieBox {
width: 160rpx;
height: 68rpx;
background: linear-gradient(135deg, #ff4427, #ff793f);
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
}
.heji {
color: #323233;
font-size: 26rpx;
}
.BtnJie {
height: 96rpx;
background: #ffffff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 32rpx;
}
.BtnDw {
position: fixed;
width: 100%;
bottom: 0;
}
.selBox {
display: flex;
align-items: center;
}
.selBox image {
width: 32rpx;
height: 32rpx;
}
.del {
color: #FA4936;
font-size: 26rpx;
margin: 12rpx 48rpx;
}
.DelBox {
border: 1px solid #fa4936;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
}
... ...
import Vue from 'vue'
import App from './App'
import uView from "uview-ui";
Vue.use(uView);
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
... ...
{
"name" : "Dragon",
"appid" : "",
"description" : "",
"versionName" : "1.0.0",
"versionCode" : "100",
"transformPx" : false,
/* 5+App特有相关 */
"app-plus" : {
"usingComponents" : true,
"nvueStyleCompiler" : "uni-app",
"compilerVersion" : 3,
"splashscreen" : {
"alwaysShowBeforeRender" : true,
"waiting" : true,
"autoclose" : true,
"delay" : 0
},
/* 模块配置 */
"modules" : {},
/* 应用发布信息 */
"distribute" : {
/* android打包配置 */
"android" : {
"permissions" : [
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
"<uses-feature android:name=\"android.hardware.camera\"/>",
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
]
},
/* ios打包配置 */
"ios" : {},
/* SDK配置 */
"sdkConfigs" : {}
}
},
/* 快应用特有相关 */
"quickapp" : {},
/* 小程序特有相关 */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true,
"permission" : {
"scope.userLocation" : {
"desc" : "科技商城请求位置信息"
}
}
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
}
}
... ...
{
"name": "Dragon",
"lockfileVersion": 2,
"requires": true,
"packages": {
"node_modules/@vant/weapp": {
"version": "1.6.8",
"resolved": "https://registry.npmjs.org/@vant/weapp/-/weapp-1.6.8.tgz",
"integrity": "sha512-CvRgAZdGUtJKEnd2wmjw3oaRYXBq/YqerFTmf19cTd3G9+vRR67nSXPMUNQEoPPSm7LZo6gF6Xk/5pYx4Q4C0Q=="
}
}
}
... ...
Copyright 2016-present Youzan
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
... ...
<p align="center">
<img alt="logo" src="https://img.yzcdn.cn/vant/logo.png" width="120" style="margin-bottom: 10px;">
</p>
<h3 align="center">轻量、可靠的小程序 UI 组件库</h3>
<p align="center">
<img src="https://img.shields.io/npm/v/@vant/weapp.svg?style=for-the-badge" alt="npm version" />
<img src="https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge&color=#4fc08d" />
<img src="https://img.shields.io/npm/dt/@vant/weapp.svg?style=for-the-badge&color=#4fc08d" alt="downloads" />
<img src="https://img.shields.io/npm/dm/@vant/weapp.svg?style=for-the-badge&color=#4fc08d" alt="downloads" />
</p>
<p align="center">
🔥 <a href="https://vant-contrib.gitee.io/vant-weapp">文档网站(国内)</a>
&nbsp;
🌈 <a href="https://youzan.github.io/vant-weapp">文档网站(GitHub)</a>
&nbsp;
🚀 <a href="https://github.com/youzan/vant" target="_blank">Vue 版</a>
</p>
---
### 介绍
Vant 是**有赞前端团队**开源的移动端组件库,于 2017 年开源,已持续维护 4 年时间。Vant 对内承载了有赞所有核心业务,对外服务十多万开发者,是业界主流的移动端组件库之一。
目前 Vant 官方提供了 [Vue 2 版本](https://vant-contrib.gitee.io/vant)[Vue 3 版本](https://vant-contrib.gitee.io/vant/v3)[微信小程序版本](http://vant-contrib.gitee.io/vant-weapp),并由社区团队维护 [React 版本](https://github.com/mxdi9i7/vant-react)[支付宝小程序版本](https://github.com/ant-move/Vant-Aliapp)
## 预览
扫描下方小程序二维码,体验组件库示例:
<img src="https://img.yzcdn.cn/vant-weapp/qrcode-201808101114.jpg" width="200" height="200" style="margin-top: 10px;" >
## 使用之前
使用 Vant Weapp 前,请确保你已经学习过微信官方的 [小程序简易教程](https://developers.weixin.qq.com/miniprogram/dev/framework/)[自定义组件介绍](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/)
## 安装
### 方式一. 通过 npm 安装 (推荐)
小程序已经支持使用 npm 安装第三方包,详见 [npm 支持](https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.html?search-key=npm)
```bash
# 通过 npm 安装
npm i @vant/weapp -S --production
# 通过 yarn 安装
yarn add @vant/weapp --production
# 安装 0.x 版本
npm i vant-weapp -S --production
```
### 方式二. 下载代码
直接通过 git 下载 Vant Weapp 源代码,并将`dist`目录拷贝到自己的项目中
```bash
git clone https://github.com/youzan/vant-weapp.git
```
## 使用组件
以按钮组件为例,只需要在 json 文件中引入按钮对应的自定义组件即可
```json
{
"usingComponents": {
"van-button": "/path/to/vant-weapp/dist/button/index"
}
}
```
接着就可以在 wxml 中直接使用组件
```html
<van-button type="primary">按钮</van-button>
```
## 在开发者工具中预览
```bash
# 安装项目依赖
npm install
# 执行组件编译
npm run dev
```
打开[微信开发者工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html),把`vant-weapp/example`目录添加进去就可以预览示例了。
PS:关于 `van-area` Area 省市区选择组件,地区数据初始化可以直接在云开发环境中导入`vant-weapp/example/database_area.JSON`文件使用
## 基础库版本
Vant Weapp 最低支持到小程序基础库 2.2.3 版本
## 微信讨论群
欢迎大家在微信上联系我们,添加下方微信并注明『交流 vant-weapp』即可
<img src="https://img.yzcdn.cn/vant/wechat_20180606.png" width="220" height="292" >
## 加入我们
**有赞前端团队**是由一群年轻、皮实、对技术饱含热情的小伙伴组成的,目前共有 100 多名前端工程师,分布在业务中台、电商、零售、美业、资产、有赞云、赋能平台、增长中心等业务线。
我们热爱分享和开源,崇尚用工程师的方式解决问题,因此造了很多工具来解决我们遇到的问题,目前我们维护的开源产品有:
<img src="https://img.yzcdn.cn/public_files/2019/07/22/f4b70763c55c8710c52c667ecf192c05.jpeg" width="320" height="303">
我们正在寻找更多优秀的小伙伴,一起拓展前端技术的边界,期待你的加入!
- <a target="_blank" href="https://app.mokahr.com/apply/youzan/3750#/jobs/?keyword=%E5%89%8D%E7%AB%AF&_k=tueqds">职位详情</a>(Base: 杭州/深圳)
- <a target="_blank" href="https://tech.youzan.com/tag/front-end/">团队博客</a>
- <a target="_blank" href="https://github.com/youzan">开源项目</a>
## 链接
* [更新日志](https://github.com/youzan/vant-weapp/blob/dev/docs/markdown/changelog.md)
* [意见反馈](https://github.com/youzan/vant-weapp/issues)
* [加入我们](https://job.youzan.com)
* [Vant Vue 版](https://github.com/youzan/vant)
## 开源协议
本项目基于 [MIT](https://zh.wikipedia.org/wiki/MIT%E8%A8%B1%E5%8F%AF%E8%AD%89)协议,请自由地享受和参与开源。
[vant-weapp]: https://github.com/youzan/vant-weapp
[issue]: https://github.com/youzan/vant-weapp/issues/new
[PR]: https://github.com/youzan/vant-weapp/compare
[MIT]: http://opensource.org/licenses/MIT
[小程序简易教程]: https://developers.weixin.qq.com/miniprogram/dev/framework/
[小程序框架介绍]: https://developers.weixin.qq.com/miniprogram/dev/framework/MINA.html
[微信开发者工具]: https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html
... ...
import { VantComponent } from '../common/component';
import { button } from '../mixins/button';
import { openType } from '../mixins/open-type';
VantComponent({
mixins: [button, openType],
props: {
show: Boolean,
title: String,
cancelText: String,
description: String,
round: {
type: Boolean,
value: true,
},
zIndex: {
type: Number,
value: 100,
},
actions: {
type: Array,
value: [],
},
overlay: {
type: Boolean,
value: true,
},
closeOnClickOverlay: {
type: Boolean,
value: true,
},
closeOnClickAction: {
type: Boolean,
value: true,
},
safeAreaInsetBottom: {
type: Boolean,
value: true,
},
},
methods: {
onSelect(event) {
const { index } = event.currentTarget.dataset;
const item = this.data.actions[index];
if (item && !item.disabled && !item.loading) {
this.$emit('select', item);
if (this.data.closeOnClickAction) {
this.onClose();
}
}
},
onCancel() {
this.$emit('cancel');
},
onClose() {
this.$emit('close');
},
onClickOverlay() {
this.$emit('click-overlay');
this.onClose();
},
},
});
... ...
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index",
"van-popup": "../popup/index",
"van-loading": "../loading/index"
}
}
... ...
<wxs src="../wxs/utils.wxs" module="utils" />
<van-popup
show="{{ show }}"
position="bottom"
round="{{ round }}"
z-index="{{ zIndex }}"
overlay="{{ overlay }}"
custom-class="van-action-sheet"
safe-area-inset-bottom="{{ safeAreaInsetBottom }}"
close-on-click-overlay="{{ closeOnClickOverlay }}"
bind:close="onClickOverlay"
>
<view wx:if="{{ title }}" class="van-action-sheet__header">
{{ title }}
<van-icon
name="cross"
custom-class="van-action-sheet__close"
bind:click="onClose"
/>
</view>
<view wx:if="{{ description }}" class="van-action-sheet__description van-hairline--bottom">
{{ description }}
</view>
<view wx:if="{{ actions && actions.length }}">
<!-- button外包一层view,防止actions动态变化,导致渲染时button被打散 -->
<button
wx:for="{{ actions }}"
wx:key="index"
open-type="{{ item.openType }}"
style="{{ item.color ? 'color: ' + item.color : '' }}"
class="{{ utils.bem('action-sheet__item', { disabled: item.disabled || item.loading }) }} {{ item.className || '' }}"
hover-class="van-action-sheet__item--hover"
data-index="{{ index }}"
bind:tap="onSelect"
bindgetuserinfo="bindGetUserInfo"
bindcontact="bindContact"
bindgetphonenumber="bindGetPhoneNumber"
binderror="bindError"
bindlaunchapp="bindLaunchApp"
bindopensetting="bindOpenSetting"
lang="{{ lang }}"
session-from="{{ sessionFrom }}"
send-message-title="{{ sendMessageTitle }}"
send-message-path="{{ sendMessagePath }}"
send-message-img="{{ sendMessageImg }}"
show-message-card="{{ showMessageCard }}"
app-parameter="{{ appParameter }}"
>
<block wx:if="{{ !item.loading }}">
{{ item.name }}
<view wx:if="{{ item.subname }}" class="van-action-sheet__subname" >{{ item.subname }}</view>
</block>
<van-loading wx:else custom-class="van-action-sheet__loading" size="22px" />
</button>
</view>
<slot />
<block wx:if="{{ cancelText }}">
<view class="van-action-sheet__gap" />
<view
class="van-action-sheet__cancel"
hover-class="van-action-sheet__cancel--hover"
hover-stay-time="70"
bind:tap="onCancel"
>
{{ cancelText }}
</view>
</block>
</van-popup>
... ...
@import '../common/index.wxss';.van-action-sheet{max-height:90%!important;max-height:var(--action-sheet-max-height,90%)!important;color:#323233;color:var(--action-sheet-item-text-color,#323233)}.van-action-sheet__cancel,.van-action-sheet__item{padding:14px 16px;text-align:center;font-size:16px;font-size:var(--action-sheet-item-font-size,16px);line-height:22px;line-height:var(--action-sheet-item-line-height,22px);background-color:#fff;background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__cancel--hover,.van-action-sheet__item--hover{background-color:#f2f3f5;background-color:var(--active-color,#f2f3f5)}.van-action-sheet__cancel:after,.van-action-sheet__item:after{border-width:0}.van-action-sheet__cancel{color:#646566;color:var(--action-sheet-cancel-text-color,#646566)}.van-action-sheet__gap{display:block;height:8px;height:var(--action-sheet-cancel-padding-top,8px);background-color:#f7f8fa;background-color:var(--action-sheet-cancel-padding-color,#f7f8fa)}.van-action-sheet__item--disabled{color:#c8c9cc;color:var(--action-sheet-item-disabled-text-color,#c8c9cc)}.van-action-sheet__item--disabled.van-action-sheet__item--hover{background-color:#fff;background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__subname{margin-top:8px;margin-top:var(--padding-xs,8px);font-size:12px;font-size:var(--action-sheet-subname-font-size,12px);color:#969799;color:var(--action-sheet-subname-color,#969799);line-height:20px;line-height:var(--action-sheet-subname-line-height,20px)}.van-action-sheet__header{text-align:center;font-weight:500;font-weight:var(--font-weight-bold,500);font-size:16px;font-size:var(--action-sheet-header-font-size,16px);line-height:48px;line-height:var(--action-sheet-header-height,48px)}.van-action-sheet__description{text-align:center;padding:20px 16px;padding:20px var(--padding-md,16px);color:#969799;color:var(--action-sheet-description-color,#969799);font-size:14px;font-size:var(--action-sheet-description-font-size,14px);line-height:20px;line-height:var(--action-sheet-description-line-height,20px)}.van-action-sheet__close{position:absolute!important;top:0;right:0;line-height:inherit!important;padding:0 16px;padding:var(--action-sheet-close-icon-padding,0 16px);font-size:22px!important;font-size:var(--action-sheet-close-icon-size,22px)!important;color:#c8c9cc;color:var(--action-sheet-close-icon-color,#c8c9cc)}.van-action-sheet__loading{display:-webkit-flex!important;display:flex!important}
\ No newline at end of file
... ...
import { VantComponent } from '../common/component';
import { pickerProps } from '../picker/shared';
import { requestAnimationFrame } from '../common/utils';
const EMPTY_CODE = '000000';
VantComponent({
classes: ['active-class', 'toolbar-class', 'column-class'],
props: Object.assign(Object.assign({}, pickerProps), {
value: {
type: String,
observer(value) {
this.code = value;
this.setValues();
},
},
areaList: {
type: Object,
value: {},
observer: 'setValues',
},
columnsNum: {
type: null,
value: 3,
},
columnsPlaceholder: {
type: Array,
observer(val) {
this.setData({
typeToColumnsPlaceholder: {
province: val[0] || '',
city: val[1] || '',
county: val[2] || '',
},
});
},
},
}),
data: {
columns: [{ values: [] }, { values: [] }, { values: [] }],
typeToColumnsPlaceholder: {},
},
mounted() {
requestAnimationFrame(() => {
this.setValues();
});
},
methods: {
getPicker() {
if (this.picker == null) {
this.picker = this.selectComponent('.van-area__picker');
}
return this.picker;
},
onCancel(event) {
this.emit('cancel', event.detail);
},
onConfirm(event) {
const { index } = event.detail;
let { value } = event.detail;
value = this.parseValues(value);
this.emit('confirm', { value, index });
},
emit(type, detail) {
detail.values = detail.value;
delete detail.value;
this.$emit(type, detail);
},
parseValues(values) {
const { columnsPlaceholder } = this.data;
return values.map((value, index) => {
if (
value &&
(!value.code || value.name === columnsPlaceholder[index])
) {
return Object.assign(Object.assign({}, value), {
code: '',
name: '',
});
}
return value;
});
},
onChange(event) {
const { index, picker, value } = event.detail;
this.code = value[index].code;
this.setValues().then(() => {
this.$emit('change', {
picker,
values: this.parseValues(picker.getValues()),
index,
});
});
},
getConfig(type) {
const { areaList } = this.data;
return (areaList && areaList[`${type}_list`]) || {};
},
getList(type, code) {
if (type !== 'province' && !code) {
return [];
}
const { typeToColumnsPlaceholder } = this.data;
const list = this.getConfig(type);
let result = Object.keys(list).map((code) => ({
code,
name: list[code],
}));
if (code != null) {
// oversea code
if (code[0] === '9' && type === 'city') {
code = '9';
}
result = result.filter((item) => item.code.indexOf(code) === 0);
}
if (typeToColumnsPlaceholder[type] && result.length) {
// set columns placeholder
const codeFill =
type === 'province'
? ''
: type === 'city'
? EMPTY_CODE.slice(2, 4)
: EMPTY_CODE.slice(4, 6);
result.unshift({
code: `${code}${codeFill}`,
name: typeToColumnsPlaceholder[type],
});
}
return result;
},
getIndex(type, code) {
let compareNum = type === 'province' ? 2 : type === 'city' ? 4 : 6;
const list = this.getList(type, code.slice(0, compareNum - 2));
// oversea code
if (code[0] === '9' && type === 'province') {
compareNum = 1;
}
code = code.slice(0, compareNum);
for (let i = 0; i < list.length; i++) {
if (list[i].code.slice(0, compareNum) === code) {
return i;
}
}
return 0;
},
setValues() {
const picker = this.getPicker();
if (!picker) {
return;
}
let code = this.code || this.getDefaultCode();
const provinceList = this.getList('province');
const cityList = this.getList('city', code.slice(0, 2));
const stack = [];
const indexes = [];
const { columnsNum } = this.data;
if (columnsNum >= 1) {
stack.push(picker.setColumnValues(0, provinceList, false));
indexes.push(this.getIndex('province', code));
}
if (columnsNum >= 2) {
stack.push(picker.setColumnValues(1, cityList, false));
indexes.push(this.getIndex('city', code));
if (cityList.length && code.slice(2, 4) === '00') {
[{ code }] = cityList;
}
}
if (columnsNum === 3) {
stack.push(
picker.setColumnValues(
2,
this.getList('county', code.slice(0, 4)),
false
)
);
indexes.push(this.getIndex('county', code));
}
return Promise.all(stack)
.catch(() => {})
.then(() => picker.setIndexes(indexes))
.catch(() => {});
},
getDefaultCode() {
const { columnsPlaceholder } = this.data;
if (columnsPlaceholder.length) {
return EMPTY_CODE;
}
const countyCodes = Object.keys(this.getConfig('county'));
if (countyCodes[0]) {
return countyCodes[0];
}
const cityCodes = Object.keys(this.getConfig('city'));
if (cityCodes[0]) {
return cityCodes[0];
}
return '';
},
getValues() {
const picker = this.getPicker();
if (!picker) {
return [];
}
return this.parseValues(picker.getValues().filter((value) => !!value));
},
getDetail() {
const values = this.getValues();
const area = {
code: '',
country: '',
province: '',
city: '',
county: '',
};
if (!values.length) {
return area;
}
const names = values.map((item) => item.name);
area.code = values[values.length - 1].code;
if (area.code[0] === '9') {
area.country = names[1] || '';
area.province = names[2] || '';
} else {
area.province = names[0] || '';
area.city = names[1] || '';
area.county = names[2] || '';
}
return area;
},
reset(code) {
this.code = code || '';
return this.setValues();
},
},
});
... ...
{
"component": true,
"usingComponents": {
"van-picker": "../picker/index"
}
}
... ...
<wxs src="./index.wxs" module="computed" />
<van-picker
class="van-area__picker"
active-class="active-class"
toolbar-class="toolbar-class"
column-class="column-class"
show-toolbar
value-key="name"
title="{{ title }}"
loading="{{ loading }}"
columns="{{ computed.displayColumns(columns, columnsNum) }}"
item-height="{{ itemHeight }}"
visible-item-count="{{ visibleItemCount }}"
cancel-button-text="{{ cancelButtonText }}"
confirm-button-text="{{ confirmButtonText }}"
bind:change="onChange"
bind:confirm="onConfirm"
bind:cancel="onCancel"
/>
... ...
/* eslint-disable */
function displayColumns(columns, columnsNum) {
return columns.slice(0, +columnsNum);
}
module.exports = {
displayColumns: displayColumns,
};
... ...
@import '../common/index.wxss';
\ No newline at end of file
... ...
import { VantComponent } from '../common/component';
import { button } from '../mixins/button';
import { openType } from '../mixins/open-type';
import { canIUseFormFieldButton } from '../common/version';
const mixins = [button, openType];
if (canIUseFormFieldButton()) {
mixins.push('wx://form-field-button');
}
VantComponent({
mixins,
classes: ['hover-class', 'loading-class'],
data: {
baseStyle: '',
},
props: {
formType: String,
icon: String,
classPrefix: {
type: String,
value: 'van-icon',
},
plain: Boolean,
block: Boolean,
round: Boolean,
square: Boolean,
loading: Boolean,
hairline: Boolean,
disabled: Boolean,
loadingText: String,
customStyle: String,
loadingType: {
type: String,
value: 'circular',
},
type: {
type: String,
value: 'default',
},
dataset: null,
size: {
type: String,
value: 'normal',
},
loadingSize: {
type: String,
value: '20px',
},
color: String,
},
methods: {
onClick() {
if (!this.data.loading) {
this.$emit('click');
}
},
noop() {},
},
});
... ...
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index",
"van-loading": "../loading/index"
}
}
... ...
<wxs src="../wxs/utils.wxs" module="utils" />
<wxs src="./index.wxs" module="computed" />
<button
id="{{ id }}"
data-detail="{{ dataset }}"
class="custom-class {{ utils.bem('button', [type, size, { block, round, plain, square, loading, disabled, hairline, unclickable: disabled || loading }]) }} {{ hairline ? 'van-hairline--surround' : '' }}"
hover-class="van-button--active hover-class"
lang="{{ lang }}"
form-type="{{ formType }}"
style="{{ computed.rootStyle({ plain, color, customStyle }) }}"
open-type="{{ disabled ? '' : openType }}"
business-id="{{ businessId }}"
session-from="{{ sessionFrom }}"
send-message-title="{{ sendMessageTitle }}"
send-message-path="{{ sendMessagePath }}"
send-message-img="{{ sendMessageImg }}"
show-message-card="{{ showMessageCard }}"
app-parameter="{{ appParameter }}"
aria-label="{{ ariaLabel }}"
bindtap="{{ !disabled ? 'onClick' : 'noop' }}"
bindgetuserinfo="bindGetUserInfo"
bindcontact="bindContact"
bindgetphonenumber="bindGetPhoneNumber"
binderror="bindError"
bindlaunchapp="bindLaunchApp"
bindopensetting="bindOpenSetting"
>
<block wx:if="{{ loading }}">
<van-loading
custom-class="loading-class"
size="{{ loadingSize }}"
type="{{ loadingType }}"
color="{{ computed.loadingColor({ type, color, plain }) }}"
/>
<view wx:if="{{ loadingText }}" class="van-button__loading-text">
{{ loadingText }}
</view>
</block>
<block wx:else>
<van-icon
wx:if="{{ icon }}"
size="1.2em"
name="{{ icon }}"
class-prefix="{{ classPrefix }}"
class="van-button__icon"
custom-style="line-height: inherit;"
/>
<view class="van-button__text">
<slot />
</view>
</block>
</button>
... ...
/* eslint-disable */
var style = require('../wxs/style.wxs');
function rootStyle(data) {
if (!data.color) {
return data.customStyle;
}
var properties = {
color: data.plain ? data.color : '#fff',
background: data.plain ? null : data.color,
};
// hide border when color is linear-gradient
if (data.color.indexOf('gradient') !== -1) {
properties.border = 0;
} else {
properties['border-color'] = data.color;
}
return style([properties, data.customStyle]);
}
function loadingColor(data) {
if (data.plain) {
return data.color ? data.color : '#c9c9c9';
}
if (data.type === 'default') {
return '#c9c9c9';
}
return '#fff';
}
module.exports = {
rootStyle: rootStyle,
loadingColor: loadingColor,
};
... ...
@import '../common/index.wxss';.van-button{position:relative;display:-webkit-inline-flex;display:inline-flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;box-sizing:border-box;padding:0;text-align:center;vertical-align:middle;-webkit-appearance:none;-webkit-text-size-adjust:100%;height:44px;height:var(--button-default-height,44px);line-height:20px;line-height:var(--button-line-height,20px);font-size:16px;font-size:var(--button-default-font-size,16px);transition:opacity .2s;transition:opacity var(--animation-duration-fast,.2s);border-radius:2px;border-radius:var(--button-border-radius,2px)}.van-button:before{position:absolute;top:50%;left:50%;width:100%;height:100%;border:inherit;border-radius:inherit;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);opacity:0;content:" ";background-color:#000;background-color:var(--black,#000);border-color:#000;border-color:var(--black,#000)}.van-button:after{border-width:0}.van-button--active:before{opacity:.15}.van-button--unclickable:after{display:none}.van-button--default{color:#323233;color:var(--button-default-color,#323233);background:#fff;background:var(--button-default-background-color,#fff);border:1px solid #ebedf0;border:var(--button-border-width,1px) solid var(--button-default-border-color,#ebedf0)}.van-button--primary{color:#fff;color:var(--button-primary-color,#fff);background:#07c160;background:var(--button-primary-background-color,#07c160);border:1px solid #07c160;border:var(--button-border-width,1px) solid var(--button-primary-border-color,#07c160)}.van-button--info{color:#fff;color:var(--button-info-color,#fff);background:#1989fa;background:var(--button-info-background-color,#1989fa);border:1px solid #1989fa;border:var(--button-border-width,1px) solid var(--button-info-border-color,#1989fa)}.van-button--danger{color:#fff;color:var(--button-danger-color,#fff);background:#ee0a24;background:var(--button-danger-background-color,#ee0a24);border:1px solid #ee0a24;border:var(--button-border-width,1px) solid var(--button-danger-border-color,#ee0a24)}.van-button--warning{color:#fff;color:var(--button-warning-color,#fff);background:#ff976a;background:var(--button-warning-background-color,#ff976a);border:1px solid #ff976a;border:var(--button-border-width,1px) solid var(--button-warning-border-color,#ff976a)}.van-button--plain{background:#fff;background:var(--button-plain-background-color,#fff)}.van-button--plain.van-button--primary{color:#07c160;color:var(--button-primary-background-color,#07c160)}.van-button--plain.van-button--info{color:#1989fa;color:var(--button-info-background-color,#1989fa)}.van-button--plain.van-button--danger{color:#ee0a24;color:var(--button-danger-background-color,#ee0a24)}.van-button--plain.van-button--warning{color:#ff976a;color:var(--button-warning-background-color,#ff976a)}.van-button--large{width:100%;height:50px;height:var(--button-large-height,50px)}.van-button--normal{padding:0 15px;font-size:14px;font-size:var(--button-normal-font-size,14px)}.van-button--small{min-width:60px;min-width:var(--button-small-min-width,60px);height:30px;height:var(--button-small-height,30px);padding:0 8px;padding:0 var(--padding-xs,8px);font-size:12px;font-size:var(--button-small-font-size,12px)}.van-button--mini{display:inline-block;min-width:50px;min-width:var(--button-mini-min-width,50px);height:22px;height:var(--button-mini-height,22px);font-size:10px;font-size:var(--button-mini-font-size,10px)}.van-button--mini+.van-button--mini{margin-left:5px}.van-button--block{display:-webkit-flex;display:flex;width:100%}.van-button--round{border-radius:999px;border-radius:var(--button-round-border-radius,999px)}.van-button--square{border-radius:0}.van-button--disabled{opacity:.5;opacity:var(--button-disabled-opacity,.5)}.van-button__text{display:inline}.van-button__icon+.van-button__text:not(:empty),.van-button__loading-text{margin-left:4px}.van-button__icon{min-width:1em;line-height:inherit!important;vertical-align:top}.van-button--hairline{padding-top:1px;border-width:0}.van-button--hairline:after{border-color:inherit;border-width:1px;border-radius:4px;border-radius:calc(var(--button-border-radius, 2px)*2)}.van-button--hairline.van-button--round:after{border-radius:999px;border-radius:var(--button-round-border-radius,999px)}.van-button--hairline.van-button--square:after{border-radius:0}
\ No newline at end of file
... ...
<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="{{ utils.bem('calendar__footer', { safeAreaInsetBottom }) }}"
>
<slot name="footer"></slot>
</view>
<view
class="{{ utils.bem('calendar__footer', { safeAreaInsetBottom }) }}"
>
<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>
... ...
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: null,
formatter: {
type: null,
observer: 'setDays',
},
currentDate: {
type: null,
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: null,
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: null,
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: null,
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" />
<wxs src="../wxs/utils.wxs" module="utils" />
<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"
>
<include src="calendar.wxml" />
</van-popup>
<include wx:else src="calendar.wxml" />
<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
};
... ...
import { link } from '../mixins/link';
import { VantComponent } from '../common/component';
VantComponent({
classes: [
'num-class',
'desc-class',
'thumb-class',
'title-class',
'price-class',
'origin-price-class',
],
mixins: [link],
props: {
tag: String,
num: String,
desc: String,
thumb: String,
title: String,
price: {
type: String,
observer: 'updatePrice',
},
centered: Boolean,
lazyLoad: Boolean,
thumbLink: String,
originPrice: String,
thumbMode: {
type: String,
value: 'aspectFit',
},
currency: {
type: String,
value: '¥',
},
},
methods: {
updatePrice() {
const { price } = this.data;
const priceArr = price.toString().split('.');
this.setData({
integerStr: priceArr[0],
decimalStr: priceArr[1] ? `.${priceArr[1]}` : '',
});
},
onClickThumb() {
this.jumpLink('thumbLink');
},
},
});
... ...
{
"component": true,
"usingComponents": {
"van-tag": "../tag/index"
}
}
... ...
<wxs src="../wxs/utils.wxs" module="utils" />
<view class="custom-class van-card">
<view class="{{ utils.bem('card__header', { center: centered }) }}">
<view class="van-card__thumb" bind:tap="onClickThumb">
<image
wx:if="{{ thumb }}"
src="{{ thumb }}"
mode="{{ thumbMode }}"
lazy-load="{{ lazyLoad }}"
class="van-card__img thumb-class"
/>
<slot wx:else name="thumb" />
<van-tag
wx:if="{{ tag }}"
mark
type="danger"
custom-class="van-card__tag"
>
{{ tag }}
</van-tag>
<slot wx:else name="tag" />
</view>
<view class="van-card__content {{ utils.bem('card__content', { center: centered }) }}">
<view>
<view wx:if="{{ title }}" class="van-card__title title-class">{{ title }}</view>
<slot wx:else name="title" />
<view wx:if="{{ desc }}" class="van-card__desc desc-class">{{ desc }}</view>
<slot wx:else name="desc" />
<slot name="tags" />
</view>
<view class="van-card__bottom">
<slot name="price-top" />
<view wx:if="{{ price || price === 0 }}" class="van-card__price price-class">
<text>{{ currency }}</text>
<text class="van-card__price-integer">{{ integerStr }}</text>
<text class="van-card__price-decimal">{{ decimalStr }}</text>
</view>
<slot wx:else name="price" />
<view wx:if="{{ originPrice || originPrice === 0 }}" class="van-card__origin-price origin-price-class">{{ currency }} {{ originPrice }}</view>
<slot wx:else name="origin-price" />
<view wx:if="{{ num }}" class="van-card__num num-class">x {{ num }}</view>
<slot wx:else name="num" />
<slot name="bottom" />
</view>
</view>
</view>
<view class="van-card__footer">
<slot name="footer" />
</view>
</view>
... ...
@import '../common/index.wxss';.van-card{position:relative;box-sizing:border-box;padding:8px 16px;padding:var(--card-padding,8px 16px);font-size:12px;font-size:var(--card-font-size,12px);color:#323233;color:var(--card-text-color,#323233);background-color:#fafafa;background-color:var(--card-background-color,#fafafa)}.van-card__header{display:-webkit-flex;display:flex}.van-card__header--center{-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center}.van-card__thumb{position:relative;-webkit-flex:none;flex:none;width:88px;width:var(--card-thumb-size,88px);height:88px;height:var(--card-thumb-size,88px);margin-right:8px;margin-right:var(--padding-xs,8px)}.van-card__thumb:empty{display:none}.van-card__img{width:100%;height:100%;border-radius:8px;border-radius:var(--border-radius-lg,8px)}.van-card__content{position:relative;display:-webkit-flex;display:flex;-webkit-flex:1;flex:1;-webkit-flex-direction:column;flex-direction:column;-webkit-justify-content:space-between;justify-content:space-between;min-width:0;min-height:88px;min-height:var(--card-thumb-size,88px)}.van-card__content--center{-webkit-justify-content:center;justify-content:center}.van-card__desc,.van-card__title{word-wrap:break-word}.van-card__title{font-weight:700;line-height:16px;line-height:var(--card-title-line-height,16px)}.van-card__desc{line-height:20px;line-height:var(--card-desc-line-height,20px);color:#646566;color:var(--card-desc-color,#646566)}.van-card__bottom{line-height:20px}.van-card__price{display:inline-block;font-weight:700;color:#ee0a24;color:var(--card-price-color,#ee0a24);font-size:12px;font-size:var(--card-price-font-size,12px)}.van-card__price-integer{font-size:16px;font-size:var(--card-price-integer-font-size,16px)}.van-card__price-decimal,.van-card__price-integer{font-family:Avenir-Heavy,PingFang SC,Helvetica Neue,Arial,sans-serif;font-family:var(--card-price-font-family,Avenir-Heavy,PingFang SC,Helvetica Neue,Arial,sans-serif)}.van-card__origin-price{display:inline-block;margin-left:5px;text-decoration:line-through;font-size:10px;font-size:var(--card-origin-price-font-size,10px);color:#646566;color:var(--card-origin-price-color,#646566)}.van-card__num{float:right}.van-card__tag{position:absolute!important;top:2px;left:0}.van-card__footer{-webkit-flex:none;flex:none;width:100%;text-align:right}
\ No newline at end of file
... ...
import { VantComponent } from '../common/component';
VantComponent({
props: {
title: String,
border: {
type: Boolean,
value: true,
},
},
});
... ...
<view
wx:if="{{ title }}"
class="van-cell-group__title"
>
{{ title }}
</view>
<view class="custom-class van-cell-group {{ border ? 'van-hairline--top-bottom' : '' }}">
<slot />
</view>
... ...
@import '../common/index.wxss';.van-cell-group__title{padding:16px 16px 8px;padding:var(--cell-group-title-padding,16px 16px 8px);font-size:14px;font-size:var(--cell-group-title-font-size,14px);line-height:16px;line-height:var(--cell-group-title-line-height,16px);color:#969799;color:var(--cell-group-title-color,#969799)}
\ No newline at end of file
... ...
import { link } from '../mixins/link';
import { VantComponent } from '../common/component';
VantComponent({
classes: [
'title-class',
'label-class',
'value-class',
'right-icon-class',
'hover-class',
],
mixins: [link],
props: {
title: null,
value: null,
icon: String,
size: String,
label: String,
center: Boolean,
isLink: Boolean,
required: Boolean,
clickable: Boolean,
titleWidth: String,
customStyle: String,
arrowDirection: String,
useLabelSlot: Boolean,
border: {
type: Boolean,
value: true,
},
titleStyle: String,
},
methods: {
onClick(event) {
this.$emit('click', event.detail);
this.jumpLink();
},
},
});
... ...
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index"
}
}
... ...
<wxs src="../wxs/utils.wxs" module="utils" />
<wxs src="./index.wxs" module="computed" />
<view
class="custom-class {{ utils.bem('cell', [size, { center, required, borderless: !border, clickable: isLink || clickable }]) }}"
hover-class="van-cell--hover hover-class"
hover-stay-time="70"
style="{{ customStyle }}"
bind:tap="onClick"
>
<van-icon
wx:if="{{ icon }}"
name="{{ icon }}"
class="van-cell__left-icon-wrap"
custom-class="van-cell__left-icon"
/>
<slot wx:else name="icon" />
<view
style="{{ computed.titleStyle({ titleWidth, titleStyle }) }}"
class="van-cell__title title-class"
>
<block wx:if="{{ title }}">{{ title }}</block>
<slot wx:else name="title" />
<view wx:if="{{ label || useLabelSlot }}" class="van-cell__label label-class">
<slot wx:if="{{ useLabelSlot }}" name="label" />
<block wx:elif="{{ label }}">{{ label }}</block>
</view>
</view>
<view class="van-cell__value value-class">
<block wx:if="{{ value || value === 0 }}">{{ value }}</block>
<slot wx:else />
</view>
<van-icon
wx:if="{{ isLink }}"
name="{{ arrowDirection ? 'arrow' + '-' + arrowDirection : 'arrow' }}"
class="van-cell__right-icon-wrap right-icon-class"
custom-class="van-cell__right-icon"
/>
<slot wx:else name="right-icon" />
<slot name="extra" />
</view>
... ...
/* eslint-disable */
var style = require('../wxs/style.wxs');
var addUnit = require('../wxs/add-unit.wxs');
function titleStyle(data) {
return style([
{
'max-width': addUnit(data.titleWidth),
'min-width': addUnit(data.titleWidth),
},
data.titleStyle,
]);
}
module.exports = {
titleStyle: titleStyle,
};
... ...
@import '../common/index.wxss';.van-cell{position:relative;display:-webkit-flex;display:flex;box-sizing:border-box;width:100%;padding:10px 16px;padding:var(--cell-vertical-padding,10px) var(--cell-horizontal-padding,16px);font-size:14px;font-size:var(--cell-font-size,14px);line-height:24px;line-height:var(--cell-line-height,24px);color:#323233;color:var(--cell-text-color,#323233);background-color:#fff;background-color:var(--cell-background-color,#fff)}.van-cell:after{position:absolute;box-sizing:border-box;-webkit-transform-origin:center;transform-origin:center;content:" ";pointer-events:none;right:16px;bottom:0;left:16px;border-bottom:1px solid #ebedf0;-webkit-transform:scaleY(.5);transform:scaleY(.5)}.van-cell--borderless:after{display:none}.van-cell-group{background-color:#fff;background-color:var(--cell-background-color,#fff)}.van-cell__label{margin-top:3px;margin-top:var(--cell-label-margin-top,3px);font-size:12px;font-size:var(--cell-label-font-size,12px);line-height:18px;line-height:var(--cell-label-line-height,18px);color:#969799;color:var(--cell-label-color,#969799)}.van-cell__value{overflow:hidden;text-align:right;vertical-align:middle;color:#969799;color:var(--cell-value-color,#969799)}.van-cell__title,.van-cell__value{-webkit-flex:1;flex:1}.van-cell__title:empty,.van-cell__value:empty{display:none}.van-cell__left-icon-wrap,.van-cell__right-icon-wrap{display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;height:24px;height:var(--cell-line-height,24px);font-size:16px;font-size:var(--cell-icon-size,16px)}.van-cell__left-icon-wrap{margin-right:4px;margin-right:var(--padding-base,4px)}.van-cell__right-icon-wrap{margin-left:4px;margin-left:var(--padding-base,4px);color:#969799;color:var(--cell-right-icon-color,#969799)}.van-cell__left-icon{vertical-align:middle}.van-cell__left-icon,.van-cell__right-icon{line-height:24px;line-height:var(--cell-line-height,24px)}.van-cell--clickable.van-cell--hover{background-color:#f2f3f5;background-color:var(--cell-active-color,#f2f3f5)}.van-cell--required{overflow:visible}.van-cell--required:before{position:absolute;content:"*";left:8px;left:var(--padding-xs,8px);font-size:14px;font-size:var(--cell-font-size,14px);color:#ee0a24;color:var(--cell-required-color,#ee0a24)}.van-cell--center{-webkit-align-items:center;align-items:center}.van-cell--large{padding-top:12px;padding-top:var(--cell-large-vertical-padding,12px);padding-bottom:12px;padding-bottom:var(--cell-large-vertical-padding,12px)}.van-cell--large .van-cell__title{font-size:16px;font-size:var(--cell-large-title-font-size,16px)}.van-cell--large .van-cell__value{font-size:16px;font-size:var(--cell-large-value-font-size,16px)}.van-cell--large .van-cell__label{font-size:14px;font-size:var(--cell-large-label-font-size,14px)}
\ No newline at end of file
... ...
import { useChildren } from '../common/relation';
import { VantComponent } from '../common/component';
VantComponent({
field: true,
relation: useChildren('checkbox', function (target) {
this.updateChild(target);
}),
props: {
max: Number,
value: {
type: Array,
observer: 'updateChildren',
},
disabled: {
type: Boolean,
observer: 'updateChildren',
},
},
methods: {
updateChildren() {
this.children.forEach((child) => this.updateChild(child));
},
updateChild(child) {
const { value, disabled } = this.data;
child.setData({
value: value.indexOf(child.data.name) !== -1,
parentDisabled: disabled,
});
},
},
});
... ...
@import '../common/index.wxss';
\ No newline at end of file
... ...
import { useParent } from '../common/relation';
import { VantComponent } from '../common/component';
function emit(target, value) {
target.$emit('input', value);
target.$emit('change', value);
}
VantComponent({
field: true,
relation: useParent('checkbox-group'),
classes: ['icon-class', 'label-class'],
props: {
value: Boolean,
disabled: Boolean,
useIconSlot: Boolean,
checkedColor: String,
labelPosition: {
type: String,
value: 'right',
},
labelDisabled: Boolean,
shape: {
type: String,
value: 'round',
},
iconSize: {
type: null,
value: 20,
},
},
data: {
parentDisabled: false,
},
methods: {
emitChange(value) {
if (this.parent) {
this.setParentValue(this.parent, value);
} else {
emit(this, value);
}
},
toggle() {
const { parentDisabled, disabled, value } = this.data;
if (!disabled && !parentDisabled) {
this.emitChange(!value);
}
},
onClickLabel() {
const { labelDisabled, parentDisabled, disabled, value } = this.data;
if (!disabled && !labelDisabled && !parentDisabled) {
this.emitChange(!value);
}
},
setParentValue(parent, value) {
const parentValue = parent.data.value.slice();
const { name } = this.data;
const { max } = parent.data;
if (value) {
if (max && parentValue.length >= max) {
return;
}
if (parentValue.indexOf(name) === -1) {
parentValue.push(name);
emit(parent, parentValue);
}
} else {
const index = parentValue.indexOf(name);
if (index !== -1) {
parentValue.splice(index, 1);
emit(parent, parentValue);
}
}
},
},
});
... ...
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index"
}
}
... ...
<wxs src="../wxs/utils.wxs" module="utils" />
<wxs src="./index.wxs" module="computed" />
<view class="van-checkbox custom-class">
<view
wx:if="{{ labelPosition === 'left' }}"
class="label-class {{ utils.bem('checkbox__label', [labelPosition, { disabled: disabled || parentDisabled }]) }}"
bindtap="onClickLabel"
>
<slot />
</view>
<view class="van-checkbox__icon-wrap" bindtap="toggle">
<slot wx:if="{{ useIconSlot }}" name="icon" />
<van-icon
wx:else
name="success"
size="0.8em"
class="{{ utils.bem('checkbox__icon', [shape, { disabled: disabled || parentDisabled, checked: value }]) }}"
style="{{ computed.iconStyle(checkedColor, value, disabled, parentDisabled, iconSize) }}"
custom-class="icon-class"
custom-style="line-height: 1.25em;"
/>
</view>
<view
wx:if="{{ labelPosition === 'right' }}"
class="label-class {{ utils.bem('checkbox__label', [labelPosition, { disabled: disabled || parentDisabled }]) }}"
bindtap="onClickLabel"
>
<slot />
</view>
</view>
... ...
/* eslint-disable */
var style = require('../wxs/style.wxs');
var addUnit = require('../wxs/add-unit.wxs');
function iconStyle(checkedColor, value, disabled, parentDisabled, iconSize) {
var styles = {
'font-size': addUnit(iconSize),
};
if (checkedColor && value && !disabled && !parentDisabled) {
styles['border-color'] = checkedColor;
styles['background-color'] = checkedColor;
}
return style(styles);
}
module.exports = {
iconStyle: iconStyle,
};
... ...
@import '../common/index.wxss';.van-checkbox{display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;overflow:hidden;-webkit-user-select:none;user-select:none}.van-checkbox__icon-wrap,.van-checkbox__label{line-height:20px;line-height:var(--checkbox-size,20px)}.van-checkbox__icon-wrap{-webkit-flex:none;flex:none}.van-checkbox__icon{display:-webkit-flex;display:flex;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;box-sizing:border-box;width:1em;height:1em;color:transparent;text-align:center;transition-property:color,border-color,background-color;font-size:20px;font-size:var(--checkbox-size,20px);border:1px solid #c8c9cc;border:1px solid var(--checkbox-border-color,#c8c9cc);transition-duration:.2s;transition-duration:var(--checkbox-transition-duration,.2s)}.van-checkbox__icon--round{border-radius:100%}.van-checkbox__icon--checked{color:#fff;color:var(--white,#fff);background-color:#1989fa;background-color:var(--checkbox-checked-icon-color,#1989fa);border-color:#1989fa;border-color:var(--checkbox-checked-icon-color,#1989fa)}.van-checkbox__icon--disabled{background-color:#ebedf0;background-color:var(--checkbox-disabled-background-color,#ebedf0);border-color:#c8c9cc;border-color:var(--checkbox-disabled-icon-color,#c8c9cc)}.van-checkbox__icon--disabled.van-checkbox__icon--checked{color:#c8c9cc;color:var(--checkbox-disabled-icon-color,#c8c9cc)}.van-checkbox__label{word-wrap:break-word;margin-left:10px;margin-left:var(--checkbox-label-margin,10px);color:#323233;color:var(--checkbox-label-color,#323233)}.van-checkbox__label--left{float:left;margin:0 10px 0 0;margin:0 var(--checkbox-label-margin,10px) 0 0}.van-checkbox__label--disabled{color:#c8c9cc;color:var(--checkbox-disabled-label-color,#c8c9cc)}.van-checkbox__label:empty{margin:0}
\ No newline at end of file
... ...
/// <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 { BLUE, WHITE } from '../common/color';
import { VantComponent } from '../common/component';
import { getSystemInfoSync } from '../common/utils';
import { isObj } from '../common/validator';
import { canIUseCanvas2d } from '../common/version';
import { adaptor } from './canvas';
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: null,
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 === '' || !canIUseCanvas2d()) {
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 { useParent } from '../common/relation';
import { VantComponent } from '../common/component';
VantComponent({
relation: useParent('row'),
props: {
span: Number,
offset: Number,
},
});
... ...
<wxs src="../wxs/utils.wxs" module="utils" />
<wxs src="./index.wxs" module="computed" />
<view
class="custom-class {{ utils.bem('col', [span]) }} {{ offset ? 'van-col--offset-' + offset : '' }}"
style="{{ computed.rootStyle({ gutter }) }}"
>
<slot />
</view>
... ...
/* eslint-disable */
var style = require('../wxs/style.wxs');
var addUnit = require('../wxs/add-unit.wxs');
function rootStyle(data) {
if (!data.gutter) {
return '';
}
return style({
'padding-right': addUnit(data.gutter / 2),
'padding-left': addUnit(data.gutter / 2),
});
}
module.exports = {
rootStyle: rootStyle,
};
... ...
@import '../common/index.wxss';.van-col{float:left;box-sizing:border-box}.van-col--1{width:4.16666667%}.van-col--offset-1{margin-left:4.16666667%}.van-col--2{width:8.33333333%}.van-col--offset-2{margin-left:8.33333333%}.van-col--3{width:12.5%}.van-col--offset-3{margin-left:12.5%}.van-col--4{width:16.66666667%}.van-col--offset-4{margin-left:16.66666667%}.van-col--5{width:20.83333333%}.van-col--offset-5{margin-left:20.83333333%}.van-col--6{width:25%}.van-col--offset-6{margin-left:25%}.van-col--7{width:29.16666667%}.van-col--offset-7{margin-left:29.16666667%}.van-col--8{width:33.33333333%}.van-col--offset-8{margin-left:33.33333333%}.van-col--9{width:37.5%}.van-col--offset-9{margin-left:37.5%}.van-col--10{width:41.66666667%}.van-col--offset-10{margin-left:41.66666667%}.van-col--11{width:45.83333333%}.van-col--offset-11{margin-left:45.83333333%}.van-col--12{width:50%}.van-col--offset-12{margin-left:50%}.van-col--13{width:54.16666667%}.van-col--offset-13{margin-left:54.16666667%}.van-col--14{width:58.33333333%}.van-col--offset-14{margin-left:58.33333333%}.van-col--15{width:62.5%}.van-col--offset-15{margin-left:62.5%}.van-col--16{width:66.66666667%}.van-col--offset-16{margin-left:66.66666667%}.van-col--17{width:70.83333333%}.van-col--offset-17{margin-left:70.83333333%}.van-col--18{width:75%}.van-col--offset-18{margin-left:75%}.van-col--19{width:79.16666667%}.van-col--offset-19{margin-left:79.16666667%}.van-col--20{width:83.33333333%}.van-col--offset-20{margin-left:83.33333333%}.van-col--21{width:87.5%}.van-col--offset-21{margin-left:87.5%}.van-col--22{width:91.66666667%}.van-col--offset-22{margin-left:91.66666667%}.van-col--23{width:95.83333333%}.van-col--offset-23{margin-left:95.83333333%}.van-col--24{width:100%}.van-col--offset-24{margin-left:100%}
\ No newline at end of file
... ...
/// <reference types="miniprogram-api-typings" />
export declare function setContentAnimate(
context: WechatMiniprogram.Component.TrivialInstance,
expanded: boolean,
mounted: boolean
): void;
... ...
import { canIUseAnimate } from '../common/version';
import { getRect } from '../common/utils';
function useAnimate(context, expanded, mounted, height) {
const selector = '.van-collapse-item__wrapper';
if (expanded) {
context.animate(
selector,
[
{ height: 0, ease: 'ease-in-out', offset: 0 },
{ height: `${height}px`, ease: 'ease-in-out', offset: 1 },
{ height: `auto`, ease: 'ease-in-out', offset: 1 },
],
mounted ? 300 : 0,
() => {
context.clearAnimation(selector);
}
);
return;
}
context.animate(
selector,
[
{ height: `${height}px`, ease: 'ease-in-out', offset: 0 },
{ height: 0, ease: 'ease-in-out', offset: 1 },
],
300,
() => {
context.clearAnimation(selector);
}
);
}
function useAnimation(context, expanded, mounted, height) {
const animation = wx.createAnimation({
duration: 0,
timingFunction: 'ease-in-out',
});
if (expanded) {
if (height === 0) {
animation.height('auto').top(1).step();
} else {
animation
.height(height)
.top(1)
.step({
duration: mounted ? 300 : 1,
})
.height('auto')
.step();
}
context.setData({
animation: animation.export(),
});
return;
}
animation.height(height).top(0).step({ duration: 1 }).height(0).step({
duration: 300,
});
context.setData({
animation: animation.export(),
});
}
export function setContentAnimate(context, expanded, mounted) {
getRect(context, '.van-collapse-item__content')
.then((rect) => rect.height)
.then((height) => {
canIUseAnimate()
? useAnimate(context, expanded, mounted, height)
: useAnimation(context, expanded, mounted, height);
});
}
... ...
import { VantComponent } from '../common/component';
import { useParent } from '../common/relation';
import { setContentAnimate } from './animate';
VantComponent({
classes: ['title-class', 'content-class'],
relation: useParent('collapse'),
props: {
name: null,
title: null,
value: null,
icon: String,
label: String,
disabled: Boolean,
clickable: Boolean,
border: {
type: Boolean,
value: true,
},
isLink: {
type: Boolean,
value: true,
},
},
data: {
expanded: false,
},
mounted() {
this.updateExpanded();
this.mounted = true;
},
methods: {
updateExpanded() {
if (!this.parent) {
return;
}
const { value, accordion } = this.parent.data;
const { children = [] } = this.parent;
const { name } = this.data;
const index = children.indexOf(this);
const currentName = name == null ? index : name;
const expanded = accordion
? value === currentName
: (value || []).some((name) => name === currentName);
if (expanded !== this.data.expanded) {
setContentAnimate(this, expanded, this.mounted);
}
this.setData({ index, expanded });
},
onClick() {
if (this.data.disabled) {
return;
}
const { name, expanded } = this.data;
const index = this.parent.children.indexOf(this);
const currentName = name == null ? index : name;
this.parent.switch(currentName, !expanded);
},
},
});
... ...
{
"component": true,
"usingComponents": {
"van-cell": "../cell/index"
}
}
... ...
<wxs src="../wxs/utils.wxs" module="utils" />
<view class="van-collapse-item custom-class {{ index !== 0 ? 'van-hairline--top' : '' }}">
<van-cell
title="{{ title }}"
title-class="title-class"
icon="{{ icon }}"
value="{{ value }}"
label="{{ label }}"
is-link="{{ isLink }}"
clickable="{{ clickable }}"
border="{{ border && expanded }}"
class="{{ utils.bem('collapse-item__title', { disabled, expanded }) }}"
right-icon-class="van-cell__right-icon"
custom-class="van-cell"
hover-class="van-cell--hover"
bind:click="onClick"
>
<slot
name="title"
slot="title"
/>
<slot
name="icon"
slot="icon"
/>
<slot name="value" />
<slot
name="right-icon"
slot="right-icon"
/>
</van-cell>
<view
class="{{ utils.bem('collapse-item__wrapper') }}"
style="height: 0;"
animation="{{ animation }}"
>
<view
class="van-collapse-item__content content-class"
>
<slot />
</view>
</view>
</view>
... ...
@import '../common/index.wxss';.van-collapse-item__title .van-cell__right-icon{-webkit-transform:rotate(90deg);transform:rotate(90deg);transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;transition:-webkit-transform var(--collapse-item-transition-duration,.3s);transition:transform var(--collapse-item-transition-duration,.3s);transition:transform var(--collapse-item-transition-duration,.3s),-webkit-transform var(--collapse-item-transition-duration,.3s)}.van-collapse-item__title--expanded .van-cell__right-icon{-webkit-transform:rotate(-90deg);transform:rotate(-90deg)}.van-collapse-item__title--disabled .van-cell,.van-collapse-item__title--disabled .van-cell__right-icon{color:#c8c9cc!important;color:var(--collapse-item-title-disabled-color,#c8c9cc)!important}.van-collapse-item__title--disabled .van-cell--hover{background-color:#fff!important;background-color:var(--white,#fff)!important}.van-collapse-item__wrapper{overflow:hidden}.van-collapse-item__content{padding:15px;padding:var(--collapse-item-content-padding,15px);color:#969799;color:var(--collapse-item-content-text-color,#969799);font-size:13px;font-size:var(--collapse-item-content-font-size,13px);line-height:1.5;line-height:var(--collapse-item-content-line-height,1.5);background-color:#fff;background-color:var(--collapse-item-content-background-color,#fff)}
\ No newline at end of file
... ...