第一次提交

master
xcw 2024-10-21 15:46:12 +08:00
commit eb030a6149
667 changed files with 100973 additions and 15263 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

View File

@ -2,6 +2,10 @@
// launchtypelocalremote, localremote
"version": "0.0",
"configurations": [{
"app-plus" :
{
"launchtype" : "local"
},
"default" :
{
"launchtype" : "local"

105
App.vue
View File

@ -1,55 +1,102 @@
<script>
import toolAll from './jsFile/tools.js';
import {
postLoginIndex,
getInfo
} from "@/api/index";
export default {
globalData:{
projectname:'', //
lat:'', //
lng:'' ,//
hostapi:'https://yisi-scan.scdxtc.cn' //
hostapi:'https://course-buy.dev.scdxtc.cn',//
webapi:'https://course.dev.scdxtc.cn'
},
// show
onLaunch() {
console.log(uni.$u.config.v,'uview版本号');
let that = this;
if (process.env.NODE_ENV === 'development') {
that.globalData.hostapi = 'https://course-buy.dev.scdxtc.cn' //
} else {
that.globalData.hostapi = 'https://course-buy.dev.scdxtc.cn' //
}
// H5
// #ifdef H5
//
getInfo().then(res => {
if (res.code == 0) {
uni.setStorageSync('baseInfo',res.data)//
}
});
let getcode = uni.getStorageSync('code');
console.log(getcode,'codecode');
let link = window.location.href;
console.log(link, 'link',link.indexOf('code='));
//linkcode=
if (link.indexOf('code=') > 0) {
// code=
let temp = link.split("code=")[1],
code = temp.split("&")[0];
console.log(code);
uni.setStorageSync('code',code)//
that.getLogin(code);
}else {
if(!getcode) {
let appid = uni.getStorageSync("baseInfo").official_app_id; //id
//
let uri = that.globalData.webapi; //
window.location.href =
`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${uri}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`
}
}
// #endif
//
// #ifdef MP-WEIXIN
uni.login({
provider: 'weixin',
success: (result)=> {
if (result.code) {
that.$requst.post('/api/user/login',{code:result.code}).then(res => {
//
getInfo().then(res => {
if (res.code == 0) {
uni.setStorageSync('token',res.data.token) //token
uni.setStorageSync('openid',res.data.openid) //openid
that.$isResolve(); //promise
}
},error => {
})
uni.setStorageSync('baseInfo',res.data)//
}
});
that.getLogin(result.code);
},
});
// #endif
},
onShow: ()=> {
onShow() {
},
onHide: ()=> {
onHide() {
},
methods: {
getLogin(code) {
let that = this;
let params = {
code:code
}
postLoginIndex(params).then(res => {
if(res.code == 0){
uni.setStorageSync('token',res.data.token) //token
uni.setStorageSync('userInfo',res.data.baseInfo)//
that.$isResolve();
}
})
}
}
};
</script>
<style>
/* 阿里巴巴矢量图标库 start */
@import url("./commons/icon-font.css");
/* 阿里巴巴矢量图标库 end */
/* 项目页面样式 start */
@import url("./commons/style.css");
/* 项目页面样式 end */
/* 加载中样式 start */
@import url("./commons/loading.css");
/* 加载中样式 end */
<style lang="scss">
// css
@import "@/components/uview-ui/index.scss";
@import "@/commons/common.scss";
@import "@/commons/style.scss";
</style>

28
api/index.js Normal file
View File

@ -0,0 +1,28 @@
import request from '@/jsFile/requst.js'
// 基础配置
export function postLoginIndex(data) {
return request.post('/api.login/index', data);
}
// 基础配置
export function getInfo(params) {
return request.get('/api.base/config', params);
}
// 获取个人信息
export function postUserInfo(data) {
return request.post('/api.user/info', data);
}
// 修改个人信息
export function postEditInfo(data) {
return request.post('/api.user/editInfo', data);
}
// 上传文件
export function postUpload(data) {
return request.upload('/api.upload/image', data);
}
// banner
export function getBanner(params) {
return request.get('/api.base/banner', params);
}

File diff suppressed because one or more lines are too long

475
commons/common.scss Normal file
View File

@ -0,0 +1,475 @@
@mixin icon-image($size) {
min-height: $size;
min-width: $size;
height: $size;
width: $size;
vertical-align: middle;
}
page {
/* 定义一些主题色及基础样式 */
font-family: PingFang SC, Arial, Hiragino Sans GB, Microsoft YaHei, sans-serif;
font-size: 28rpx;
color: $-color-normal;
padding-bottom: env(safe-area-inset-bottom);
background-color: $-color-body;
}
.bold {
font-weight: bold;
}
/* 定义字体颜色 */
.primary {
color: $-color-primary;
}
.black {
color: $-color-black;
}
.white {
color: $-color-white;
}
.normal {
color: $-color-normal;
}
.lighter {
color: $-color-lighter;
}
.muted {
color: $-color-muted;
}
/* 定义背景颜色 */
.bg-primary {
background-color: $-color-primary;
}
.bg-white {
background-color: $-color-white;
}
.bg-body {
background-color: $-color-body;
}
.bg-gray {
background-color: $-color-border;
}
/* 定义常用的弹性布局 */
.flex {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
}
.flex-wrap {
flex-wrap: wrap;
}
.flex-nowrap {
flex-wrap: nowrap;
}
.col-baseline {
align-items: baseline;
}
.col-center {
align-items: center;
}
.col-top {
align-items: flex-start;
}
.col-bottom {
align-items: flex-end;
}
.col-stretch {
align-items:stretch;
}
.row-center {
justify-content: center;
}
.row-left {
justify-content: flex-start;
}
.row-right {
justify-content: flex-end;
}
.row-between {
justify-content: space-between;
}
.row-around {
justify-content: space-around;
}
.text-left {
text-align: left;
}
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
.flex-col {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
}
.flex-none {
flex: none;
}
// flex
@for $i from 0 through 5 {
.flex-#{$i} {
flex: $i;
}
}
// 1-80
@for $i from 0 through 60 {
// 5
@if $i % 2 == 0 or $i % 5 == 0 {
// m-30
.m-#{$i} {
margin: $i + rpx;
}
// p-30
.p-#{$i} {
padding: $i + rpx;
}
@each $short, $long in l left, t top, r right, b bottom {
// ml-30
//
.m#{$short}-#{$i} {
margin-#{$long}: $i + rpx;
}
//
// pl-30
.p#{$short}-#{$i} {
padding-#{$long}: $i + rpx;
}
}
}
}
// 20-60
@for $i from 20 through 60 {
@if $i % 2 == 0 {
.fs-#{$i} {
font-size: $i + rpx;
}
}
}
// 10-60
@for $i from 10 through 60 {
@if $i % 2 == 0 {
.br-#{$i} {
border-radius: $i + rpx;
}
}
}
/* 超出隐藏 */
/* start--文本行数限制--start */
.line-1 {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.line-2 {
-webkit-line-clamp: 2;
}
.line-3 {
-webkit-line-clamp: 3;
}
.line-2, .line-3, {
overflow: hidden;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box; //
-webkit-box-orient: vertical; //
}
/* 中划线 */
.line-through {
text-decoration: line-through;
}
.transition_none {
-webkit-transition: none !important;
-moz-transition: none !important;
-ms-transition: none !important;
-o-transition: none !important;
transition: none !important;
}
.transition_none * {
-webkit-transition: none !important;
-moz-transition: none !important;
-ms-transition: none !important;
-o-transition: none !important;
transition: none !important;
}
.center {
margin-left: auto;
margin-right: auto;
}
.row {
width: 87.5%;
margin: 0 auto;
}
.col-1 {
width: 100%;
}
.col-2 {
width: 50%;
}
.col-3 {
width: 33.333333%;
}
.col-4 {
width: 25%;
}
.col-5 {
width: 20%;
}
.col-6 {
width: 16.666666%;
}
.col-7 {
width: 14.285714%;
}
.col-8 {
width: 12.5%;
}
.col-9 {
width: 11.111111%;
}
.col-10 {
width: 10%;
}
.col-11 {
width: 9.09090909%;
}
.col-12 {
width: 8.3333333%;
}
.auto {
margin: 0 auto;
}
.inline {
display: inline-block;
}
.hidden {
overflow: hidden;
}
.opacity0 {
opacity: 0;
}
.opacity1 {
opacity: 1;
}
.circle {
-webkit-border-radius: 50%;
-moz-border-radius: 50%;
border-radius: 50%;
}
.blcircle {
-webkit-border-bottom-left-radius: 50%;
-moz-border-bottom-left-radius: 50%;
border-bottom-left-radius: 50%;
}
.tlcircle {
-webkit-border-top-left-radius: 50%;
-moz-border-top-left-radius: 50%;
border-top-left-radius: 50%;
}
.brcircle {
-webkit-border-bottom-right-radius: 50%;
-moz-border-bottom-right-radius: 50%;
border-bottom-right-radius: 50%;
}
.trcircle {
-webkit-border-top-right-radius: 50%;
-moz-border-top-right-radius: 50%;
border-top-right-radius: 50%;
}
.isbd {
border: 1px #e0e0e0 solid;
}
.isbdbm {
border-bottom: 1px #e0e0e0 solid;
}
.isbdtp {
border-top: 1px #e0e0e0 solid;
}
.isbdrt {
border-right: 1px #e0e0e0 solid;
}
.isbdlt {
border-left: 1px #e0e0e0 solid;
}
.isshadow {
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.1);
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.1);
}
.ishalo {
-webkit-box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
-moz-box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.isdarkhalo {
-webkit-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
-moz-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
.fl {
float: left;
}
.fr {
float: right;
}
/* 初始化按钮 */
page button {
padding: 0;
margin: 0;
background-color: transparent;
font-weight: normal;
font-size: 28rpx;
overflow: unset;
margin-left: 0;
margin-right: 0;
}
page button::after {
border: none;
}
button[type=primary] {
background-color: $-color-primary;
}
.button-hover[type=primary] {
background-color: $-color-primary;
}
/* 按钮大小 */
button[size="xs"]{
line-height: 58rpx;
height: 58rpx;
font-size: 26rpx;
padding: 0 30rpx;
}
button[size="sm"] {
line-height: 62rpx;
height: 62rpx;
font-size: 28rpx;
padding: 0 30rpx;
}
button[size="md"]{
line-height: 70rpx;
height: 70rpx;
font-size: 30rpx;
padding: 0 30rpx;
}
button[size="lg"]{
line-height: 80rpx;
height: 80rpx;
font-size: 32rpx;
padding: 0 30rpx;
}
//************/
.icon-xs {
@include icon-image(28rpx);
}
.icon-sm {
@include icon-image(30rpx);
}
.icon {
@include icon-image(34rpx);
}
.icon-md {
@include icon-image(44rpx);
}
.icon-lg {
@include icon-image(52rpx);
}
.icon-xl {
@include icon-image(64rpx);
}
.icon-xxl {
@include icon-image(120rpx);
}
.img-null {
width: 300rpx;
height: 300rpx;
}
/* 隐藏滚动条 */
::-webkit-scrollbar {
width: 0;
height: 0;
color: transparent;
}

View File

@ -1,155 +0,0 @@
@font-face {
font-family: "iconfont"; /* Project id 3180711 */
src: url('https://at.alicdn.com/t/font_3180711_atv5gkgm4w4.woff2?t=1651830764889') format('woff2'),
url('https://at.alicdn.com/t/font_3180711_atv5gkgm4w4.woff?t=1651830764889') format('woff'),
url('https://at.alicdn.com/t/font_3180711_atv5gkgm4w4.ttf?t=1651830764889') format('truetype');
}
.icon {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-del:before {
content: "\e718";
}
.icon-cut:before {
content: "\e609";
}
.icon-add:before {
content: "\e60a";
}
.icon-add-picture05:before {
content: "\e639";
}
.icon-add-picture04:before {
content: "\e636";
}
.icon-add-picture03:before {
content: "\e642";
}
.icon-add-picture02:before {
content: "\e8bc";
}
.icon-add-picture01:before {
content: "\e62c";
}
.icon-sandian:before {
content: "\e769";
}
.icon-nothing-collection:before {
content: "\e610";
}
.icon-nothing-more:before {
content: "\e624";
}
.icon-nothing-data:before {
content: "\e60c";
}
.icon-address-check:before {
content: "\e6c2";
}
.icon-address-unchecked:before {
content: "\e623";
}
.icon-navigate-now:before {
content: "\e640";
}
.icon-send-goods:before {
content: "\e601";
}
.icon-payment:before {
content: "\e602";
}
.icon-finish:before {
content: "\e63f";
}
.icon-take:before {
content: "\e649";
}
.icon-refund:before {
content: "\e613";
}
.icon-customer-black:before {
content: "\ec2e";
}
.icon-customer:before {
content: "\e628";
}
.icon-check:before {
content: "\e61e";
}
.icon-del-white:before {
content: "\e61f";
}
.icon-screen:before {
content: "\e60b";
}
.icon-search:before {
content: "\e653";
}
.icon-caidan-mo:before {
content: "\e73e";
}
.icon-renwu-mo:before {
content: "\e73f";
}
.icon-shop-cart:before {
content: "\e73d";
}
.icon-caidan-active:before {
content: "\e608";
}
.icon-renwu-acitve:before {
content: "\e67c";
}
.icon-home-mo:before {
content: "\e673";
}
.icon-home-active:before {
content: "\e674";
}
.icon-return:before {
content: "\e600";
}
.icon-next:before {
content: "\e60e";
}

File diff suppressed because it is too large Load Diff

View File

@ -1,58 +0,0 @@
/* 图片处理 */
image {
/* 照顾低版本浏览器 如果图片外面包含了链接会有边框的问题 */
border: 0;
/* 取消图片底侧有空白缝隙的问题 ① */
vertical-align: middle;
/* 取消图片底侧有空白缝隙的问题 ② */
object-fit: cover;
}
/* 去除滚动条 */
scroll-view ::-webkit-scrollbar {
display: none !important;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
background: transparent;
}
/* 文字行数 */
.clips {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
text-overflow: ellipsis;
word-wrap: break-word;
word-break: break-all;
}
/* 页面样式 */
page {
background-color: #f7f7f7;
color: #333333;
}
.main {
padding-bottom: 120rpx;
}
/* 输入默认提示 */
::-webkit-input-placeholder {
/* WebKit browserswebkit内核浏览器 */
color: #8f989f;
}
:-moz-placeholder {
/* Mozilla Firefox 4 to 18 */
color: #8f989f;
}
::-moz-placeholder {
/* Mozilla Firefox 19+ */
color: #8f989f;
}
:-ms-input-placeholder {
/* Internet Explorer 10+ */
color: #8f989f;
}

34
commons/style.scss Normal file
View File

@ -0,0 +1,34 @@
.main {
margin: 0 auto;
padding-bottom: 30rpx;
position: relative;
max-width: 750px;
}
.main-app {
position: relative;
z-index: 9;
}
/* 分类导航 */
.cate {
display: flex;
flex-wrap: wrap;
padding:0 20rpx 40rpx 20rpx;
margin-top: 25rpx;
}
.cate .item {
display: flex;
flex-direction: column;
align-items: center;
width: 20%;
margin-top: 40rpx;
font-size: 28rpx;
color: #6e6e6e;
}
.cate .item>image {
width: 114rpx;
height: 114rpx;
}

View File

@ -1,9 +1,11 @@
<template>
<view class="foot-bar">
<!-- 底部导航 -->
<view class="item" :style="{'width':`calc(100%/${footBarList.length})`}" @tap="chooseEv(index)" v-for="(item,index) in footBarList" :key="index">
<view class="icon"><image :src="current==index?item.activePath:item.normalPath" mode="heightFix"></image></view>
<view class="title" :style="{'color':current==index?'#0567b8':'#a0a5af'}">{{item.title}}</view>
<view class="item" :style="{'width':`calc(100%/${footBarList.length})`}" @tap="chooseEv(index,item.url)" v-for="(item,index) in footBarList" :key="index">
<view class="icon">
<image :src="current==index?item.activePath:item.normalPath" mode="heightFix"></image>
</view>
<view class="title" :style="{'color':current == index? '#49a149' : '#a0a5af'}">{{item.title}}</view>
</view>
</view>
</template>
@ -24,25 +26,31 @@
{
normalPath: '/static/foot-bar/index.png',
activePath: '/static/foot-bar/index-active.png',
key: "home",
title: "首页"
title:'首页',
url:'/pages/home/home'
},
{
normalPath: '/static/foot-bar/cate.png',
activePath: '/static/foot-bar/cate-active.png',
title:'商城',
url:'/pages/cate/cate'
},
// {
// normalPath: '/static/foot-bar/integral.png',
// activePath: '/static/foot-bar/integral-active.png',
// title:'',
// url:'/pages/integration/integration'
// },
{
normalPath: '/static/foot-bar/my.png',
activePath: '/static/foot-bar/my-active.png',
key: "my",
title: "我的"
title:'我的',
url:'/pages/my/my'
}
], //
};
},
mounted() {
if(uni.getStorageSync('footBarList')){
this.footBarList = uni.getStorageSync('footBarList');
}else{
//
// this.getFootBar();
}
//
const query = wx.createSelectorQuery().in(this);
query.select('.foot-bar').boundingClientRect((rect) => {
@ -50,45 +58,17 @@
}).exec()
},
methods:{
//
getFootBar(){
this.$requst.get('/api/index/mini-program-setting').then(res => {
if(res.code == 0){
console.log(res,'底部信息');
let footBar= [];
res.data.footBar.forEach(item=>{
let obj = {
normalPath: `${getApp().globalData.hostapi}`+item.icon[0],
activePath: `${getApp().globalData.hostapi}`+item.icon[1],
title:item.name
}
footBar.push(obj);
})
this.footBarList = footBar;
uni.setStorageSync('footBarList',this.footBarList)
}else{
this.$toolAll.tools.showToast(res.msg)
}
})
},
// tabbar
chooseEv(index){
console.log(index)
switch (index){
case 0:
chooseEv(index,url){
// if(this.$toolAll.tools.judgeAuth()) {
// uni.reLaunch({
// url:'',
// })
// }
uni.reLaunch({
url:'/pages/index/index',
url:url
})
break;
case 1:
if(this.$toolAll.tools.judgeAuth()) {
uni.reLaunch({
url:'/pages/my/my',
})
}
break;
}
},
}
}
@ -100,7 +80,7 @@
justify-content: space-around;
align-items: center;
width: 100%;
height: 98rpx;
height:110rpx;
background-color: #ffffff;
box-shadow: 0 0 16rpx rgba(146, 146, 146, .06);
position: fixed;
@ -125,8 +105,8 @@
}
.foot-bar .title{
width: 100%;
margin-top: 6rpx;
font-size: 22rpx;
margin-top: 12rpx;
font-size: 24rpx;
line-height: 1.3;
}
</style>

View File

@ -1,260 +0,0 @@
<template>
<view class="goods-list">
<view class="goods-item" :class="showType!==''?showType:''" v-for="(item,index) in goodsList" :key="index" @tap.stop="toDetail(item.id)">
<view class="tag" :style="{backgroundColor:item1}" v-if="item.tag!==''&&item.tag==index1" v-for="(item1,index1) in tag_bg_color" :key="index1">
{{item.tag}}
</view>
<!-- <view class="tag tag-green" v-else-if="">放心购</view> -->
<view class="img">
<image :src="item.src" mode="aspectFit"></image>
</view>
<view class="msg">
<view class="title clips">{{item.title}}</view>
<view class="price-bg">
<view class="price">
<view class="price-item">
<text></text>
<text>{{item.price.substr(0,item.price.indexOf('.'))}}</text>
<text>{{item.price.substr(item.price.indexOf('.'),item.price.length)}}</text>
</view>
<view class="price-item" v-if="item.integral>0">
<text>+</text>
<text>{{item.integral}}</text>
<text>积分</text>
</view>
</view>
<view class="btn">
<view class="icon-spot" v-if="!ifShowCart">
<image src="/static/icon/icon-spot.png" mode="widthFix"></image>
</view>
<view class="icon-cart" v-else @tap.stop="addCart(item.sku_id)">
<image src="/static/icon/icon-add-cart.png" mode="widthFix"></image>
</view>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name:'goods-list',
props:{
//
ifShowCart:{
type:Boolean,
default:true
},
//
ifRefreshCart:{
type:Boolean,
default:false
},
//
showType:{
type:String,
default:'' //search-column cate-column
},
//
goodsList:{
type:Array,
default:[]
},
},
data() {
return {
tag_bg_color:{}, //tag
};
},
mounted() {
//
this.getBaseConfig();
},
methods:{
//
getBaseConfig(){
this.$requst.get('/api.index/baseConfig').then(res => {
if(res.code == 0){
this.tag_bg_color = res.data.tag_bg_color;
}else{
this.$toolAll.tools.showToast(res.msg);
}
})
},
//
toDetail(id){
uni.navigateTo({
url:`/pagesB/goodsDetail/goodsDetail?id=${id}`
})
},
//
addCart(sku_id){
let params = {
sku_id:sku_id,
num:1
}
this.$requst.post('/api/order/shopping-cart-add',params).then(res => {
if(res.code == 0){
this.$toolAll.tools.showToast('已加入购物车');
if(this.ifRefreshCart){
this.$emit("getCartList");
}
}else{
this.$toolAll.tools.showToast(res.msg);
}
})
}
}
}
</script>
<style scoped>
.goods-list{
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.goods-item{
box-sizing: border-box;
width: calc(50% - 9rpx);
padding: 18rpx;
margin-bottom: 18rpx;
border-radius: 10rpx;
background-color: #ffffff;
overflow: hidden;
position: relative;
}
.goods-list .goods-item:nth-last-of-type(1),
.goods-list .goods-item:nth-last-of-type(2){
/* margin-bottom: 0; */
}
.goods-item .tag{
line-height: 34rpx;
padding: 0 8rpx;
background-color: #d4996d;
font-size: 20rpx;
text-align: center;
color: #ffffff;
position: absolute;
top: 0;
left: 0;
}
.goods-item .tag-green{
background-color: #4cc474;
}
.goods-item .img,
.goods-item .img image{
width: 290rpx;
height: 290rpx;
}
.goods-item .msg{
margin-top: 30rpx;
}
.goods-item .msg .title{
font-size: 26rpx;
line-height: 40rpx;
-webkit-line-clamp: 2;
}
.goods-item .msg .price-bg{
display: flex;
justify-content: space-between;
align-items: center;
height: 40rpx;
margin-top: 20rpx;
}
.goods-item .msg .price{
display: flex;
align-items: center;
max-width: calc(100% - 36rpx);
}
.goods-item .msg .price-item{
display: flex;
align-items: flex-end;
}
.goods-item .msg .price-item text{
font-size: 24rpx;
line-height: 30rpx;
color: #f72e2e;
}
.goods-item .msg .price-item text:nth-of-type(2){
font-size: 34rpx;
line-height: 40rpx;
}
.goods-item .icon-spot image{
width: 32rpx;
height: 7rpx;
}
.goods-item .icon-cart image{
width: 36rpx;
height: 35rpx;
}
/* 搜索页面样式 */
.search-column{
display: flex;
justify-content: space-between;
align-items: flex-start;
width: 100%;
padding: 20rpx 20rpx 0;
border-radius: 0;
margin-bottom: 0;
}
.search-column .img{
width: 195rpx;
height: 195rpx;
margin-bottom: 20rpx;
}
.search-column .img image{
width: 195rpx;
height: 195rpx;
}
.search-column .msg{
width: calc(100% - 205rpx);
height: 195rpx;
border-bottom: 1px solid #eaeaea;
padding-bottom: 20rpx;
margin-top: 0;
}
.search-column .msg .title{
margin-top: 10rpx;
}
.search-column .tag{
left: 20rpx;
top: 20rpx;
border-radius: 10rpx 0 0 0;
}
.search-column .msg .price-bg{
margin-top: 46rpx;
}
/* 分类页面样式 */
.cate-column{
display: flex;
justify-content: space-between;
align-items: flex-start;
width: 100%;
padding: 20rpx 0;
border-radius: 0;
margin-bottom: 0;
}
.cate-column .img,
.cate-column .img image{
width: 155rpx;
height: 155rpx;
}
.cate-column .msg{
width: calc(100% - 170rpx);
height: 155rpx;
margin-top: 0;
}
.cate-column .msg .title{
margin-top: 6rpx;
}
.cate-column .tag{
left: 0;
top: 20rpx;
border-radius: 10rpx 0 0 0;
}
</style>

View File

@ -1,41 +0,0 @@
<template>
<view class="nothing">
<view class="nothing-box">
<image v-if="imgSrc!=''" class="nothing-img" :src="imgSrc" mode="aspectFill" lazy-load></image>
<i class="iconImg icon"
:class="['icon-nothing-more','icon-nothing-data','icon-nothing-collection'][currentType]"></i>
<view v-if="currentType!=1" class="nothing-con">{{content}}</view>
</view>
</view>
</template>
<script>
export default {
name:"nothing-page",
props:{
imgSrc:{ //
type:String,
default:''
},
content:{ //
type:String,
default:'暂无内容'
},
currentType:{ // icon
type:Number,
default: 0
}
},
data() {
return {};
}
}
</script>
<style scoped>
.nothing{position: fixed;top: 0;bottom: 0;left: 0;right: 0;display: flex;justify-content: center;align-items: center;}
.nothing-box{display: flex;justify-content: center;flex-direction: column;align-items: center;}
.nothing-box .nothing-img{width: 470rpx;height: 270rpx;}
.iconImg {font-size: 280rpx;color: #999999;}
.nothing-con{font-size: 24rpx;font-family: PingFang SC;font-weight: 500;color: #999999;}
</style>

View File

@ -1,54 +0,0 @@
<template>
<view :style="{
color: textColor,
fontSize: textFontSize,
fontWeight: `${ ifBold ? 'bold' : 0 }`,
textAlign: `${ ifCenter ? 'center' : 'left' }`,
padding: paddingStr
}">{{textStr}}</view>
</template>
<script>
export default {
name:"pitera",
props:{
//
textStr: {
type:String,
default:'-- NO MORE --'
},
//
textColor: {
type:String,
default:'#999999'
},
//
textFontSize: {
type: String,
default: '24rpx'
},
//
ifBold: {
type:Boolean,
default:false
},
//
ifCenter: {
type:Boolean,
default: true
},
//
paddingStr: {
type:String,
default:'20rpx'
}
},
data() {
return {};
}
}
</script>
<style>
</style>

View File

@ -1,4 +1,5 @@
<template>
<!-- #ifdef MP-WEIXIN -->
<view class="status-box" :style="{marginBottom:marginBottom,background:backgroudColor}">
<!-- 网络电量栏 -->
<view :style="{height:statusBarHeight+'px'}"></view>
@ -10,6 +11,10 @@
<i class="icon icon-return" style="font-size: 38rpx;" :style="{color:returnColor}"></i>
</slot>
</view>
<view class="left-box" @tap="backHome" v-if="ifReturnHome" :style="{height:navBarHeight}">
<u-icon name="home" size="20" :color="returnColor"></u-icon>
</view>
<!-- 标题 -->
<view class="tab-title" :style="{color:titleColor,fontWeight:ifBold?'bold':'',justifyContent:ifCenter?'center':'',padding:ifCenter?'0px':`${ifReturn ?'0 38':'0 15'}px`}">
<view class="title-box" :class="['','clips1','clips2'][clipNumber*1]" :style="{maxWidth: ifCenter ?'360rpx':'70%'}">
@ -25,6 +30,7 @@
</view>
</view>
</view>
<!-- #endif -->
</template>
<script>
@ -46,6 +52,10 @@
type: Boolean,
default: true
},
ifReturnHome: {
type: Boolean,
default: false
},
//
returnColor: {
type: String,
@ -133,7 +143,12 @@
})
}
})
}
},
backHome() {
uni.redirectTo({
url: '/pages/index/index'
})
},
}
}
</script>

View File

@ -1,62 +0,0 @@
<template>
<view class="lamp-box">
<swiper :current="lampCur" :style="{height: newHeight}" :autoplay="isplay" :circular="true" :interval="1000" :vertical="true" :duration="1000">
<swiper-item v-for="(item,index) in lampList" :key="index">
<view @tap="toDetail(index)">{{item.title}}</view>
</swiper-item>
<swiper-item v-if="lampList.length==1" v-for="(item,index) in lampList" :key="index">
<view @tap="toDetail(index)">{{item.title}}</view>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
name: "swiper-lamp",
props: {
isplay: {
type: Boolean,
default: true
},
isClick: {
type: Boolean,
default: false
},
lampList: { //
type: Array,
default: []
},
newHeight: { //swiper
type: String,
default: '42rpx'
},
},
data() {
return {
lampCur: 0, //
autoplay: true, //
};
},
methods: {
//
toDetail(index) {
this.lampCur = index;
if(this.isClick){
//
uni.navigateTo({
url: `/pagesB/news/newsDetail?id=${this.lampList[index].id}`
})
}
},
}
}
</script>
<style scoped>
.lamp-box {
width: 100%;
overflow: hidden;
position: relative;
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<view class="banner-box">
<swiper :current="bcurrent" @change="changeBanner" :style="{height: newHeight}" :autoplay="isplay" :circular="true" :interval="3000" :duration="500">
<swiper :current="bcurrent" @change="changeBanner" :style="{height: newHeight}" :autoplay="isplay" :circular="true" :interval="5000" :duration="500" class="swiper">
<swiper-item v-for="(item,index) in bannerList" :key="index">
<view @tap="chooseImg(index,item.url)" class="img-box">
<image :style="{borderRadius:newRadius,height:newHeight}" class="img animated fadeIn" :src="item.imgSrc" mode="widthFix"></image>
@ -42,11 +42,11 @@
},
newHeight: { //swiper
type: String,
default: '330rpx'
default: '350rpx'
},
newBottom: { //
type: String,
default: '12rpx'
default: '30rpx'
},
newRadius: { //
type: String,
@ -116,10 +116,13 @@
<style scoped>
.banner-box {
width: 100%;
height: 100%;
overflow: hidden;
position: relative;
}
.swiper {
height: 100%;
}
.img-box {
display: flex;
justify-content: center;

View File

@ -1,107 +0,0 @@
<template>
<view @touchmove.stop.prevent>
<view class="tui-popup-class tui-bottom-popup" :class="{ 'tui-popup-show': show, 'tui-popup-radius': radius }" :style="{ backgroundColor: backgroundColor, height: height ? height + 'rpx' : 'auto', zIndex: zIndex,transform:`translate3d(0, ${show?translateY:'100%'}, 0)`}">
<slot></slot>
</view>
<view class="tui-popup-mask" :class="[show ? 'tui-mask-show' : '']" :style="{ zIndex: maskZIndex }" v-if="mask" @tap="handleClose"></view>
</view>
</template>
<script>
export default {
name: 'tuiBottomPopup',
emits: ['close'],
props: {
//mask
mask: {
type: Boolean,
default: true
},
//
show: {
type: Boolean,
default: false
},
//
backgroundColor: {
type: String,
default: '#fff'
},
// rpx
height: {
type: Number,
default: 0
},
//
radius: {
type: Boolean,
default: true
},
zIndex: {
type: [Number, String],
default: 997
},
maskZIndex: {
type: [Number, String],
default: 996
},
//
translateY: {
type: String,
default: '0'
}
},
methods: {
handleClose() {
if (!this.show) {
return;
}
this.$emit('close', {});
}
}
};
</script>
<style scoped>
.tui-bottom-popup {
width: 100%;
position: fixed;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
transform: translate3d(0, 100%, 0);
transform-origin: center;
transition: all 0.3s ease-in-out;
min-height: 20rpx;
}
.tui-popup-radius {
border-top-left-radius: 24rpx;
border-top-right-radius: 24rpx;
padding-bottom: env(safe-area-inset-bottom);
overflow: hidden;
}
.tui-popup-show {
opacity: 1;
/* transform: translate3d(0, 0, 0); */
}
.tui-popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
transition: all 0.3s ease-in-out;
opacity: 0;
visibility: hidden;
}
.tui-mask-show {
opacity: 1;
visibility: visible;
}
</style>

View File

@ -1,204 +0,0 @@
<template>
<view :class="{ 'tui-flex-end': flexEnd }">
<view class="tui-popup-list" :class="{ 'tui-popup-show': show,'tui-z_index':show && position!='relative' }" :style="{ width: width, backgroundColor: backgroundColor, borderRadius: radius, color: color, position: position, left: left, right: right, bottom: bottom, top: top,transform:`translate(${translateX},${translateY})` }">
<view class="tui-triangle" :style="{
borderWidth: borderWidth,
borderColor: `transparent transparent ${backgroundColor} transparent`,
left: triangleLeft,
right: triangleRight,
top: triangleTop,
bottom: triangleBottom
}"
v-if="direction == 'top'"></view>
<view class="tui-triangle" :style="{
borderWidth: borderWidth,
borderColor: `${backgroundColor} transparent transparent transparent`,
left: triangleLeft,
right: triangleRight,
top: triangleTop,
bottom: triangleBottom
}"
v-if="direction == 'bottom'"></view>
<view class="tui-triangle" :style="{
borderWidth: borderWidth,
borderColor: `transparent ${backgroundColor} transparent transparent`,
left: triangleLeft,
right: triangleRight,
top: triangleTop,
bottom: triangleBottom
}"
v-if="direction == 'left'"></view>
<view class="tui-triangle" :style="{
borderWidth: borderWidth,
borderColor: `transparent transparent transparent ${backgroundColor}`,
left: triangleLeft,
right: triangleRight,
top: triangleTop,
bottom: triangleBottom
}"
v-if="direction == 'right'"></view>
<slot />
</view>
<view @touchmove.stop.prevent="stop" class="tui-popup-mask" :class="{ 'tui-popup-show': show }" :style="{ backgroundColor: maskBgColor }"
v-if="mask" @tap="handleClose"></view>
</view>
</template>
<script>
export default {
name: 'tuiBubblePopup',
emits: ['close'],
props: {
//
width: {
type: String,
default: '300rpx'
},
//popup
radius: {
type: String,
default: '8rpx'
},
//popup left right top bottom
left: {
type: String,
default: 'auto'
},
right: {
type: String,
default: 'auto'
},
top: {
type: String,
default: 'auto'
},
bottom: {
type: String,
default: 'auto'
},
translateX:{
type: String,
default: '0'
},
translateY:{
type: String,
default: '0'
},
//
backgroundColor: {
type: String,
default: '#4c4c4c'
},
//
color: {
type: String,
default: '#fff'
},
//border-width
borderWidth: {
type: String,
default: '12rpx'
},
// top left right bottom
direction: {
type: String,
default: 'top'
},
// left right top bottom
triangleLeft: {
type: String,
default: 'auto'
},
triangleRight: {
type: String,
default: 'auto'
},
triangleTop: {
type: String,
default: 'auto'
},
triangleBottom: {
type: String,
default: 'auto'
},
// relative absolute fixed
position: {
type: String,
default: 'fixed'
},
//flex-end
flexEnd: {
type: Boolean,
default: false
},
//mask
mask: {
type: Boolean,
default: true
},
maskBgColor: {
type: String,
default: 'rgba(0, 0, 0, 0.4)'
},
//
show: {
type: Boolean,
default: false
}
},
methods: {
handleClose() {
if (!this.show) {
return;
}
this.$emit('close', {});
},
stop() {
return false;
}
}
};
</script>
<style scoped>
.tui-popup-list {
z-index: 1;
transition: all 0.3s ease-in-out;
opacity: 0;
visibility: hidden;
}
.tui-flex-end {
width: 100%;
display: flex;
justify-content: flex-end;
}
.tui-triangle {
position: absolute;
width: 0;
height: 0;
border-style: solid;
z-index: 997;
}
.tui-popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 995;
transition: all 0.3s ease-in-out;
opacity: 0;
visibility: hidden;
}
.tui-popup-show {
opacity: 1;
visibility: visible;
}
.tui-z_index {
z-index: 996;
}
</style>

View File

@ -1,520 +0,0 @@
<template>
<button
class="tui-btn"
:class="[
plain ? 'tui-' + type + '-outline' : 'tui-btn-' + (type || 'primary'),
getDisabledClass(disabled, type, plain),
getShapeClass(shape, plain),
getShadowClass(type, shadow, plain),
bold ? 'tui-text-bold' : '',
link ? 'tui-btn__link' : ''
]"
:hover-class="getHoverClass(disabled, type, plain)"
:style="{ width: width, height: height, lineHeight: height, fontSize: size + 'rpx', margin: margin }"
:loading="loading"
:form-type="formType"
:open-type="openType"
@getuserinfo="bindgetuserinfo"
@getphonenumber="bindgetphonenumber"
@contact="bindcontact"
@error="binderror"
:disabled="disabled"
@tap="handleClick"
>
<slot></slot>
</button>
</template>
<script>
export default {
name: 'tuiButton',
emits: ['click','getuserinfo','contact','getphonenumber','error'],
// #ifndef MP-QQ
behaviors: ['wx://form-field-button'],
// #endif
props: {
// primary, white, danger, warning, green,blue, grayblack,brown,gray-primary,gray-danger,gray-warning,gray-green
type: {
type: String,
default: 'primary'
},
//
shadow: {
type: Boolean,
default: false
},
// rpx %
width: {
type: String,
default: '100%'
},
// rpx
height: {
type: String,
default: '96rpx'
},
// rpx
size: {
type: Number,
default: 32
},
bold: {
type: Boolean,
default: false
},
margin: {
type: String,
default: '0'
},
// circle(), square()rightAngle()
shape: {
type: String,
default: 'square'
},
plain: {
type: Boolean,
default: false
},
//linkplain使
link: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
// button
disabledGray: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
},
formType: {
type: String,
default: ''
},
openType: {
type: String,
default: ''
},
index: {
type: [Number, String],
default: 0
},
//200ms
preventClick: {
type: Boolean,
default: false
}
},
data() {
return {
time: 0
};
},
methods: {
handleClick() {
if (this.disabled) return;
if (this.preventClick) {
if(new Date().getTime() - this.time <= 200) return;
this.time = new Date().getTime();
setTimeout(() => {
this.time = 0;
}, 200);
}
this.$emit('click', {
index: Number(this.index)
});
},
bindgetuserinfo({ detail = {} } = {}) {
this.$emit('getuserinfo', detail);
},
bindcontact({ detail = {} } = {}) {
this.$emit('contact', detail);
},
bindgetphonenumber({ detail = {} } = {}) {
this.$emit('getphonenumber', detail);
},
binderror({ detail = {} } = {}) {
this.$emit('error', detail);
},
getShadowClass: function(type, shadow, plain) {
let className = '';
if (shadow && type != 'white' && !plain) {
className = 'tui-shadow-' + type;
}
return className;
},
getDisabledClass: function(disabled, type, plain) {
let className = '';
if (disabled && type != 'white' && type.indexOf('-') == -1) {
let classVal = this.disabledGray ? 'tui-gray-disabled' : 'tui-dark-disabled';
className = plain ? 'tui-dark-disabled-outline' : classVal;
}
return className;
},
getShapeClass: function(shape, plain) {
let className = '';
if (shape == 'circle') {
className = plain ? 'tui-outline-fillet' : 'tui-fillet';
} else if (shape == 'rightAngle') {
className = plain ? 'tui-outline-rightAngle' : 'tui-rightAngle';
}
return className;
},
getHoverClass: function(disabled, type, plain) {
let className = '';
if (!disabled) {
className = plain ? 'tui-outline-hover' : 'tui-' + (type || 'primary') + '-hover';
}
return className;
}
}
};
</script>
<style scoped>
.tui-btn-primary {
background: #5677fc !important;
color: #fff;
}
.tui-shadow-primary {
box-shadow: 0 10rpx 14rpx 0 rgba(86, 119, 252, 0.2);
}
.tui-btn-danger {
background: #eb0909 !important;
color: #fff;
}
.tui-shadow-danger {
box-shadow: 0 10rpx 14rpx 0 rgba(235, 9, 9, 0.2);
}
.tui-btn-warning {
background: #fc872d !important;
color: #fff;
}
.tui-shadow-warning {
box-shadow: 0 10rpx 14rpx 0 rgba(252, 135, 45, 0.2);
}
.tui-btn-green {
background: #07c160 !important;
color: #fff;
}
.tui-shadow-green {
box-shadow: 0 10rpx 14rpx 0 rgba(7, 193, 96, 0.2);
}
.tui-btn-blue {
background: #007aff !important;
color: #fff;
}
.tui-shadow-blue {
box-shadow: 0 10rpx 14rpx 0 rgba(0, 122, 255, 0.2);
}
.tui-btn-white {
background: #fff !important;
color: #333 !important;
}
.tui-btn-gray {
background: #bfbfbf !important;
color: #fff !important;
}
.tui-btn-black {
background: #333 !important;
color: #fff !important;
}
.tui-btn-brown{
background: #ac9157 !important;
color: #fff !important;
}
.tui-btn-gray-black {
background: #f2f2f2 !important;
color: #333;
}
.tui-btn-gray-primary {
background: #f2f2f2 !important;
color: #5677fc !important;
}
.tui-gray-primary-hover {
background: #d9d9d9 !important;
}
.tui-btn-gray-green {
background: #f2f2f2 !important;
color: #07c160 !important;
}
.tui-gray-green-hover {
background: #d9d9d9 !important;
}
.tui-btn-gray-danger {
background: #f2f2f2 !important;
color: #eb0909 !important;
}
.tui-gray-danger-hover {
background: #d9d9d9 !important;
}
.tui-btn-gray-warning {
background: #f2f2f2 !important;
color: #fc872d !important;
}
.tui-gray-warning-hover {
background: #d9d9d9 !important;
}
.tui-shadow-gray {
box-shadow: 0 10rpx 14rpx 0 rgba(191, 191, 191, 0.2);
}
.tui-hover-gray {
background: #f7f7f9 !important;
}
.tui-black-hover {
background: #555 !important;
color: #e5e5e5 !important;
}
.tui-brown-hover{
background: #A37F49 !important;
color: #e5e5e5 !important;
}
/* button start*/
.tui-btn {
width: 100%;
position: relative;
border: 0 !important;
border-radius: 6rpx;
padding-left: 0;
padding-right: 0;
overflow: visible;
}
.tui-btn::after {
content: '';
position: absolute;
width: 200%;
height: 200%;
transform-origin: 0 0;
transform: scale(0.5, 0.5) translateZ(0);
box-sizing: border-box;
left: 0;
top: 0;
border-radius: 12rpx;
border: 0;
}
.tui-text-bold {
font-weight: bold;
}
.tui-btn-white::after {
border: 1px solid #bfbfbf;
}
.tui-white-hover {
background: #e5e5e5 !important;
color: #2e2e2e !important;
}
.tui-dark-disabled {
opacity: 0.6 !important;
color: #fafbfc !important;
}
.tui-dark-disabled-outline {
opacity: 0.5 !important;
}
.tui-gray-disabled {
background: #f3f3f3 !important;
color: #919191 !important;
box-shadow: none;
}
.tui-outline-hover {
opacity: 0.5;
}
.tui-primary-hover {
background: #4a67d6 !important;
color: #e5e5e5 !important;
}
.tui-primary-outline::after {
border: 1px solid #5677fc !important;
}
.tui-primary-outline {
color: #5677fc !important;
background: transparent;
}
.tui-danger-hover {
background: #c80808 !important;
color: #e5e5e5 !important;
}
.tui-danger-outline {
color: #eb0909 !important;
background: transparent;
}
.tui-danger-outline::after {
border: 1px solid #eb0909 !important;
}
.tui-warning-hover {
background: #d67326 !important;
color: #e5e5e5 !important;
}
.tui-warning-outline {
color: #fc872d !important;
background: transparent;
}
.tui-warning-outline::after {
border: 1px solid #fc872d !important;
}
.tui-green-hover {
background: #06ad56 !important;
color: #e5e5e5 !important;
}
.tui-green-outline {
color: #07c160 !important;
background: transparent;
}
.tui-green-outline::after {
border: 1px solid #07c160 !important;
}
.tui-blue-hover {
background: #0062cc !important;
color: #e5e5e5 !important;
}
.tui-blue-outline {
color: #007aff !important;
background: transparent;
}
.tui-blue-outline::after {
border: 1px solid #007aff !important;
}
/* #ifndef APP-NVUE */
.tui-btn-gradual {
background: linear-gradient(90deg, rgb(255, 89, 38), rgb(240, 14, 44)) !important;
color: #fff !important;
}
.tui-shadow-gradual {
box-shadow: 0 10rpx 14rpx 0 rgba(235, 9, 9, 0.15);
}
/* #endif */
.tui-gray-hover {
background: #a3a3a3 !important;
color: #898989;
}
/* #ifndef APP-NVUE */
.tui-gradual-hover {
background: linear-gradient(90deg, #d74620, #cd1225) !important;
color: #fff !important;
}
/* #endif */
.tui-gray-outline {
color: #999 !important;
background: transparent !important;
}
.tui-white-outline {
color: #fff !important;
background: transparent !important;
}
.tui-black-outline {
background: transparent !important;
color: #333 !important;
}
.tui-gray-outline::after {
border: 1px solid #ccc !important;
}
.tui-white-outline::after {
border: 1px solid #fff !important;
}
.tui-black-outline::after {
border: 1px solid #333 !important;
}
.tui-brown-outline {
color: #ac9157 !important;
background: transparent;
}
.tui-brown-outline::after {
border: 1px solid #ac9157 !important;
}
/*圆角 */
.tui-fillet {
border-radius: 50rpx;
}
.tui-btn-white.tui-fillet::after {
border-radius: 98rpx;
}
.tui-outline-fillet::after {
border-radius: 98rpx;
}
/*平角*/
.tui-rightAngle {
border-radius: 0;
}
.tui-btn-white.tui-rightAngle::after {
border-radius: 0;
}
.tui-outline-rightAngle::after {
border-radius: 0;
}
.tui-btn__link::after {
border: 0 !important;
}
</style>

View File

@ -1,562 +0,0 @@
/**
* @1900-2100区间内的公历农历互转
* @公历转农历solar2lunar(1987,11,01);
* @农历转公历lunar2solar(1987,09,10);
*/
let calendar = {
/**
* 农历1900-2100的润大小信息表
* @Array Of Property
* @return Hex
*/
lunarInfo: [0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, //1900-1909
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, //1910-1919
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, //1920-1929
0x06566, 0x0d4a0, 0x0ea50, 0x06e95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, //1930-1939
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, //1940-1949
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5b0, 0x14573, 0x052b0, 0x0a9a8, 0x0e950, 0x06aa0, //1950-1959
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, //1960-1969
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b6a0, 0x195a6, //1970-1979
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, //1980-1989
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x055c0, 0x0ab60, 0x096d5, 0x092e0, //1990-1999
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, //2000-2009
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, //2010-2019
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, //2020-2029
0x05aa0, 0x076a3, 0x096d0, 0x04afb, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, //2030-2039
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, //2040-2049
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, //2050-2059
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, //2060-2069
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, //2070-2079
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, //2080-2089
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, //2090-2099
0x0d520
], //2100
/**
* 公历每个月份的天数普通表
* @Array Of Property
* @return Number
*/
solarMonth: [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
/**
* 天干地支之天干速查表
* @Array Of Property trans["甲","乙","丙","丁","戊","己","庚","辛","壬","癸"]
* @return Cn string
*/
Gan: ["\u7532", "\u4e59", "\u4e19", "\u4e01", "\u620a", "\u5df1", "\u5e9a", "\u8f9b", "\u58ec", "\u7678"],
/**
* 天干地支之地支速查表
* @Array Of Property
* @trans["子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"]
* @return Cn string
*/
Zhi: ["\u5b50", "\u4e11", "\u5bc5", "\u536f", "\u8fb0", "\u5df3", "\u5348", "\u672a", "\u7533", "\u9149", "\u620c",
"\u4ea5"
],
/**
* 天干地支之地支速查表<=>生肖
* @Array Of Property
* @trans["鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"]
* @return Cn string
*/
Animals: ["\u9f20", "\u725b", "\u864e", "\u5154", "\u9f99", "\u86c7", "\u9a6c", "\u7f8a", "\u7334", "\u9e21",
"\u72d7", "\u732a"
],
/**
* 24节气速查表
* @Array Of Property
* @trans["小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"]
* @return Cn string
*/
solarTerm: ["\u5c0f\u5bd2", "\u5927\u5bd2", "\u7acb\u6625", "\u96e8\u6c34", "\u60ca\u86f0", "\u6625\u5206",
"\u6e05\u660e", "\u8c37\u96e8", "\u7acb\u590f", "\u5c0f\u6ee1", "\u8292\u79cd", "\u590f\u81f3", "\u5c0f\u6691",
"\u5927\u6691", "\u7acb\u79cb", "\u5904\u6691", "\u767d\u9732", "\u79cb\u5206", "\u5bd2\u9732", "\u971c\u964d",
"\u7acb\u51ac", "\u5c0f\u96ea", "\u5927\u96ea", "\u51ac\u81f3"
],
/**
* 1900-2100各年的24节气日期速查表
* @Array Of Property
* @return 0x string For splice
*/
sTermInfo: ['9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f',
'97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f', 'b027097bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd0b06bdb0722c965ce1cfcc920f',
'b027097bd097c36b0b6fc9274c91aa', '9778397bd19801ec9210c965cc920e', '97b6b97bd19801ec95f8c965cc920f',
'97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2', '9778397bd197c36c9210c9274c91aa',
'97b6b97bd19801ec95f8c965cc920e', '97bd09801d98082c95f8e1cfcc920f', '97bd097bd097c36b0b6fc9210c8dc2',
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec95f8c965cc920e', '97bcf97c3598082c95f8e1cfcc920f',
'97bd097bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf97c3598082c95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f',
'97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf97c359801ec95f8c965cc920f', '97bd097bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf97c359801ec95f8c965cc920f', '97bd097bd07f595b0b6fc920fb0722',
'9778397bd097c36b0b6fc9210c8dc2', '9778397bd19801ec9210c9274c920e', '97b6b97bd19801ec95f8c965cc920f',
'97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
'97b6b97bd19801ec95f8c965cc920f', '97bd07f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
'9778397bd097c36c9210c9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bd07f1487f595b0b0bc920fb0722',
'7f0e397bd097c36b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e', '97bcf7f1487f531b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b97bd19801ec9210c965cc920e',
'97bcf7f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b97bd19801ec9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
'9778397bd097c36b0b6fc9210c91aa', '97b6b97bd197c36c9210c9274c920e', '97bcf7f0e47f531b0b0bb0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '9778397bd097c36c9210c9274c920e',
'97b6b7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c36b0b6fc9210c8dc2',
'9778397bd097c36b0b70c9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc9210c8dc2', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f595b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
'9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc920fb0722', '9778397bd097c36b0b6fc9274c91aa', '97b6b7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9274c91aa',
'97b6b7f0e47f531b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
'9778397bd097c36b0b6fc9210c91aa', '97b6b7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '9778397bd097c36b0b6fc9210c8dc2', '977837f0e37f149b0723b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f5307f595b0b0bc920fb0722', '7f0e397bd097c35b0b6fc9210c8dc2',
'977837f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e37f1487f595b0b0bb0b6fb0722',
'7f0e397bd097c35b0b6fc9210c8dc2', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722', '977837f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd097c35b0b6fc920fb0722',
'977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14998082b0787b06bd',
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0b0bb0b6fb0722', '7f0e397bd07f595b0b0bc920fb0722',
'977837f0e37f14998082b0723b06bd', '7f07e7f0e37f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
'7f0e397bd07f595b0b0bc920fb0722', '977837f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f595b0b0bb0b6fb0722', '7f0e37f0e37f14898082b0723b02d5',
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e37f1487f531b0b0bb0b6fb0722',
'7f0e37f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e37f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e37f14898082b072297c35',
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722',
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f149b0723b0787b0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14998082b0723b06bd',
'7f07e7f0e47f149b0723b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722', '7f0e37f0e366aa89801eb072297c35',
'7ec967f0e37f14998082b0723b06bd', '7f07e7f0e37f14998083b0787b0721', '7f0e27f0e47f531b0723b0b6fb0722',
'7f0e37f0e366aa89801eb072297c35', '7ec967f0e37f14898082b0723b02d5', '7f07e7f0e37f14998082b0787b0721',
'7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66aa89801e9808297c35', '665f67f0e37f14898082b0723b02d5',
'7ec967f0e37f14998082b0787b0721', '7f07e7f0e47f531b0723b0b6fb0722', '7f0e36665b66a449801e9808297c35',
'665f67f0e37f14898082b0723b02d5', '7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e36665b66a449801e9808297c35', '665f67f0e37f14898082b072297c35', '7ec967f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f0e26665b66a449801e9808297c35', '665f67f0e37f1489801eb072297c35',
'7ec967f0e37f14998082b0787b06bd', '7f07e7f0e47f531b0723b0b6fb0721', '7f0e27f1487f531b0b0bb0b6fb0722'
],
/**
* 数字转中文速查表
* @Array Of Property
* @trans ['日','一','二','三','四','五','六','七','八','九','十']
* @return Cn string
*/
nStr1: ["\u65e5", "\u4e00", "\u4e8c", "\u4e09", "\u56db", "\u4e94", "\u516d", "\u4e03", "\u516b", "\u4e5d", "\u5341"],
/**
* 日期转农历称呼速查表
* @Array Of Property
* @trans ['初','十','廿','卅']
* @return Cn string
*/
nStr2: ["\u521d", "\u5341", "\u5eff", "\u5345"],
/**
* 月份转农历称呼速查表
* @Array Of Property
* @trans ['正','一','二','三','四','五','六','七','八','九','十','冬','腊']
* @return Cn string
*/
nStr3: ["\u6b63", "\u4e8c", "\u4e09", "\u56db", "\u4e94", "\u516d", "\u4e03", "\u516b", "\u4e5d", "\u5341", "\u51ac",
"\u814a"
],
/**
* 返回农历y年一整年的总天数
* @param lunar Year
* @return Number
* @eg:let count = calendar.lYearDays(1987) ;//count=387
*/
lYearDays: function(y) {
let i, sum = 348;
for (i = 0x8000; i > 0x8; i >>= 1) {
sum += (calendar.lunarInfo[y - 1900] & i) ? 1 : 0;
}
return (sum + calendar.leapDays(y));
},
/**
* 返回农历y年闰月是哪个月若y年没有闰月 则返回0
* @param lunar Year
* @return Number (0-12)
* @eg:let leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
*/
leapMonth: function(y) { //闰字编码 \u95f0
return (calendar.lunarInfo[y - 1900] & 0xf);
},
/**
* 返回农历y年闰月的天数 若该年没有闰月则返回0
* @param lunar Year
* @return Number (02930)
* @eg:let leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
*/
leapDays: function(y) {
if (calendar.leapMonth(y)) {
return ((calendar.lunarInfo[y - 1900] & 0x10000) ? 30 : 29);
}
return (0);
},
/**
* 返回农历y年m月非闰月的总天数计算m为闰月时的天数请使用leapDays方法
* @param lunar Year
* @return Number (-12930)
* @eg:let MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
*/
monthDays: function(y, m) {
if (m > 12 || m < 1) {
return -1
} //月份参数从1至12参数错误返回-1
return ((calendar.lunarInfo[y - 1900] & (0x10000 >> m)) ? 30 : 29);
},
/**
* 返回公历(!)y年m月的天数
* @param solar Year
* @return Number (-128293031)
* @eg:let solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
*/
solarDays: function(y, m) {
if (m > 12 || m < 1) {
return -1
} //若参数错误 返回-1
let ms = m - 1;
if (ms == 1) { //2月份的闰平规律测算后确认返回28或29
return (((y % 4 == 0) && (y % 100 != 0) || (y % 400 == 0)) ? 29 : 28);
} else {
return (calendar.solarMonth[ms]);
}
},
/**
* 农历年份转换为干支纪年
* @param lYear 农历年的年份数
* @return Cn string
*/
toGanZhiYear: function(lYear) {
let ganKey = (lYear - 3) % 10;
let zhiKey = (lYear - 3) % 12;
if (ganKey == 0) ganKey = 10; //如果余数为0则为最后一个天干
if (zhiKey == 0) zhiKey = 12; //如果余数为0则为最后一个地支
return calendar.Gan[ganKey - 1] + calendar.Zhi[zhiKey - 1];
},
/**
* 公历月日判断所属星座
* @param cMonth [description]
* @param cDay [description]
* @return Cn string
*/
toAstro: function(cMonth, cDay) {
let s =
"\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf";
let arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22];
return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + "\u5ea7"; //座
},
/**
* 传入offset偏移量返回干支
* @param offset 相对甲子的偏移量
* @return Cn string
*/
toGanZhi: function(offset) {
return calendar.Gan[offset % 10] + calendar.Zhi[offset % 12];
},
/**
* 传入公历(!)y年获得该年第n个节气的公历日期
* @param y公历年(1900-2100)n二十四节气中的第几个节气(1~24)从n=1(小寒)算起
* @return day Number
* @eg:let _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
*/
getTerm: function(y, n) {
if (y < 1900 || y > 2100) {
return -1;
}
if (n < 1 || n > 24) {
return -1;
}
let _table = calendar.sTermInfo[y - 1900];
let _info = [
parseInt('0x' + _table.substr(0, 5)).toString(),
parseInt('0x' + _table.substr(5, 5)).toString(),
parseInt('0x' + _table.substr(10, 5)).toString(),
parseInt('0x' + _table.substr(15, 5)).toString(),
parseInt('0x' + _table.substr(20, 5)).toString(),
parseInt('0x' + _table.substr(25, 5)).toString()
];
let _calday = [
_info[0].substr(0, 1),
_info[0].substr(1, 2),
_info[0].substr(3, 1),
_info[0].substr(4, 2),
_info[1].substr(0, 1),
_info[1].substr(1, 2),
_info[1].substr(3, 1),
_info[1].substr(4, 2),
_info[2].substr(0, 1),
_info[2].substr(1, 2),
_info[2].substr(3, 1),
_info[2].substr(4, 2),
_info[3].substr(0, 1),
_info[3].substr(1, 2),
_info[3].substr(3, 1),
_info[3].substr(4, 2),
_info[4].substr(0, 1),
_info[4].substr(1, 2),
_info[4].substr(3, 1),
_info[4].substr(4, 2),
_info[5].substr(0, 1),
_info[5].substr(1, 2),
_info[5].substr(3, 1),
_info[5].substr(4, 2),
];
return parseInt(_calday[n - 1]);
},
/**
* 传入农历数字月份返回汉语通俗表示法
* @param lunar month
* @return Cn string
* @eg:let cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
*/
toChinaMonth: function(m) { // 月 => \u6708
if (m > 12 || m < 1) {
return -1
} //若参数错误 返回-1
let s = calendar.nStr3[m - 1];
s += "\u6708"; //加上月字
return s;
},
/**
* 传入农历日期数字返回汉字表示法
* @param lunar day
* @return Cn string
* @eg:let cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
*/
toChinaDay: function(d) { //日 => \u65e5
let s;
switch (d) {
case 10:
s = '\u521d\u5341';
break;
case 20:
s = '\u4e8c\u5341';
break;
break;
case 30:
s = '\u4e09\u5341';
break;
break;
default:
s = calendar.nStr2[Math.floor(d / 10)];
s += calendar.nStr1[d % 10];
}
return (s);
},
/**
* 年份转生肖[!仅能大致转换] => 精确划分生肖分界线是立春
* @param y year
* @return Cn string
* @eg:let animal = calendar.getAnimal(1987) ;//animal='兔'
*/
getAnimal: function(y) {
return calendar.Animals[(y - 4) % 12]
},
/**
* 传入阳历年月日获得详细的公历农历object信息 <=>JSON
* @param y solar year
* @param m solar month
* @param d solar day
* @return JSON object
* @eg:console.log(calendar.solar2lunar(1987,11,01));
*/
solar2lunar: function(y, m, d) { //参数区间1900.1.31~2100.12.31
if (y < 1900 || y > 2100) {
return -1;
} //年份限定、上限
if (y == 1900 && m == 1 && d < 31) {
return -1;
} //下限
let objDate;
if (!y) { //未传参 获得当天
objDate = new Date();
} else {
objDate = new Date(y, parseInt(m) - 1, d)
}
let i, leap = 0,
temp = 0;
//修正ymd参数
y = objDate.getFullYear();
m = objDate.getMonth() + 1;
d = objDate.getDate();
let offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) /
86400000;
for (i = 1900; i < 2101 && offset > 0; i++) {
temp = calendar.lYearDays(i);
offset -= temp;
}
if (offset < 0) {
offset += temp;
i--;
}
//是否今天
let isTodayObj = new Date(),
isToday = false;
if (isTodayObj.getFullYear() == y && isTodayObj.getMonth() + 1 == m && isTodayObj.getDate() == d) {
isToday = true;
}
//星期几
let nWeek = objDate.getDay(),
cWeek = calendar.nStr1[nWeek];
if (nWeek == 0) {
nWeek = 7;
} //数字表示周几顺应天朝周一开始的惯例
//农历年
let year = i;
leap = calendar.leapMonth(i); //闰哪个月
let isLeap = false;
//效验闰月
for (i = 1; i < 13 && offset > 0; i++) {
//闰月
if (leap > 0 && i == (leap + 1) && isLeap == false) {
--i;
isLeap = true;
temp = calendar.leapDays(year); //计算农历闰月天数
} else {
temp = calendar.monthDays(year, i); //计算农历普通月天数
}
//解除闰月
if (isLeap == true && i == (leap + 1)) {
isLeap = false;
}
offset -= temp;
}
if (offset == 0 && leap > 0 && i == leap + 1)
if (isLeap) {
isLeap = false;
} else {
isLeap = true;
--i;
}
if (offset < 0) {
offset += temp;
--i;
}
//农历月
let month = i;
//农历日
let day = offset + 1;
//天干地支处理
let sm = m - 1;
let gzY = calendar.toGanZhiYear(year);
//月柱 1900年1月小寒以前为 丙子月(60进制12)
let firstNode = calendar.getTerm(year, (m * 2 - 1)); //返回当月「节」为几日开始
let secondNode = calendar.getTerm(year, (m * 2)); //返回当月「节」为几日开始
//依据12节气修正干支月
let gzM = calendar.toGanZhi((y - 1900) * 12 + m + 11);
if (d >= firstNode) {
gzM = calendar.toGanZhi((y - 1900) * 12 + m + 12);
}
//传入的日期的节气与否
let isTerm = false;
let Term = null;
if (firstNode == d) {
isTerm = true;
Term = calendar.solarTerm[m * 2 - 2];
}
if (secondNode == d) {
isTerm = true;
Term = calendar.solarTerm[m * 2 - 1];
}
//日柱 当月一日与 1900/1/1 相差天数
let dayCyclical = Date.UTC(y, sm, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10;
let gzD = calendar.toGanZhi(dayCyclical + d - 1);
//该日期所属的星座
let astro = calendar.toAstro(m, d);
return {
'lYear': year,
'lMonth': month,
'lDay': day,
'Animal': calendar.getAnimal(year),
'IMonthCn': (isLeap ? "\u95f0" : '') + calendar.toChinaMonth(month),
'IDayCn': calendar.toChinaDay(day),
'cYear': y,
'cMonth': m,
'cDay': d,
'gzYear': gzY,
'gzMonth': gzM,
'gzDay': gzD,
'isToday': isToday,
'isLeap': isLeap,
'nWeek': nWeek,
'ncWeek': "\u661f\u671f" + cWeek,
'isTerm': isTerm,
'Term': Term,
'astro': astro
};
},
/**
* 传入农历年月日以及传入的月份是否闰月获得详细的公历农历object信息 <=>JSON
* @param y lunar year
* @param m lunar month
* @param d lunar day
* @param isLeapMonth lunar month is leap or not.[如果是农历闰月第四个参数赋值true即可]
* @return JSON object
* @eg:console.log(calendar.lunar2solar(1987,9,10));
*/
lunar2solar: function(y, m, d, isLeapMonth) { //参数区间1900.1.31~2100.12.1
isLeapMonth = !!isLeapMonth;
let leapOffset = 0;
let leapMonth = calendar.leapMonth(y);
let leapDay = calendar.leapDays(y);
if (isLeapMonth && (leapMonth != m)) {
return -1;
} //传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
if (y == 2100 && m == 12 && d > 1 || y == 1900 && m == 1 && d < 31) {
return -1;
} //超出了最大极限值
let day = calendar.monthDays(y, m);
let _day = day;
//bugFix 2016-9-25
//if month is leap, _day use leapDays method
if (isLeapMonth) {
_day = calendar.leapDays(y, m);
}
if (y < 1900 || y > 2100 || d > _day) {
return -1;
} //参数合法性效验
//计算农历的时间差
let offset = 0;
for (let i = 1900; i < y; i++) {
offset += calendar.lYearDays(i);
}
let leap = 0,
isAdd = false;
for (let i = 1; i < m; i++) {
leap = calendar.leapMonth(y);
if (!isAdd) { //处理闰月
if (leap <= i && leap > 0) {
offset += calendar.leapDays(y);
isAdd = true;
}
}
offset += calendar.monthDays(y, i);
}
//转换闰月农历 需补充该年闰月的前一个月的时差
if (isLeapMonth) {
offset += day;
}
//1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
let stmap = Date.UTC(1900, 1, 30, 0, 0, 0);
let calObj = new Date((offset + d - 31) * 86400000 + stmap);
let cY = calObj.getUTCFullYear();
let cM = calObj.getUTCMonth() + 1;
let cD = calObj.getUTCDate();
return calendar.solar2lunar(cY, cM, cD);
}
};
export default {
solar2lunar: calendar.solar2lunar,
lunar2solar: calendar.lunar2solar
};

View File

@ -1,915 +0,0 @@
<template>
<view @touchmove.stop.prevent="stop" v-if="isFixed">
<view class="tui-bottom-popup" :class="{'tui-popup-show': isShow}">
<view class="tui-calendar-header" :class="{ 'tui-calendar-radius': radius }">
<view>日期选择</view>
<view class="tui-iconfont tui-font-close" hover-class="tui-opacity" :hover-stay-time="150" @tap="hide">
</view>
</view>
<view class="tui-date-box">
<view class="tui-iconfont tui-font-arrowleft" :style="{ color: yearArrowColor }"
hover-class="tui-opacity" :hover-stay-time="150" v-if="arrowType == 1" @tap="changeYear(0)"></view>
<view class="tui-iconfont tui-font-arrowleft" :style="{ color: monthArrowColor }"
hover-class="tui-opacity" :hover-stay-time="150" @tap="changeMonth(0)"></view>
<view class="tui-date_time">{{ showTitle }}</view>
<view class="tui-iconfont tui-font-arrowright" :style="{ color: monthArrowColor }"
hover-class="tui-opacity" :hover-stay-time="150" @tap="changeMonth(1)"></view>
<view class="tui-iconfont tui-font-arrowright" :style="{ color: yearArrowColor }"
hover-class="tui-opacity" :hover-stay-time="150" v-if="arrowType == 1" @tap="changeYear(1)"></view>
</view>
<view class="tui-date-header">
<view class="tui-date"></view>
<view class="tui-date"></view>
<view class="tui-date"></view>
<view class="tui-date"></view>
<view class="tui-date"></view>
<view class="tui-date"></view>
<view class="tui-date"></view>
</view>
<view class="tui-date-content" :class="{ 'tui-flex-start': isFixed && fixedHeight }"
:style="{ height: isFixed && fixedHeight ? dateHeight * 6 + 'px' : 'auto' }">
<block v-for="(item, index) in weekdayArr" :key="index">
<view class="tui-date"></view>
</block>
<view class="tui-date" :class="{
'tui-date-pd_0': isFixed && fixedHeight,
'tui-opacity': openDisAbled(year, month, index + 1),
'tui-start-date': (type == 2 && startDate == `${year}-${month}-${index + 1}`) || type == 1,
'tui-end-date': (type == 2 && endDate == `${year}-${month}-${index + 1}`) || type == 1
}" :style="{ backgroundColor: isFixed ? getColor(index, 1) : 'transparent', height: isFixed && fixedHeight ? dateHeight + 'px' : 'auto' }"
v-for="(item, index) in daysArr" :key="index" @tap="dateClick(index)">
<view class="tui-date-text"
:style="{ color: isFixed ? getColor(index, 2) : getStatusData(3, index), backgroundColor: getStatusData(2, index) }">
<view v-if="isFixed || !getStatusData(4, index)">{{ index + 1 }}</view>
<view v-if="!getStatusData(4, index)" class="tui-custom-desc"
:class="{ 'tui-lunar-unshow': !lunar && isFixed }">
{{ getDescText(index, startDate, endDate) }}
</view>
<text class="tui-iconfont tui-font-check" v-if="getStatusData(4, index)"></text>
</view>
<view class="tui-date-desc" :style="{ color: activeColor }"
v-if="!lunar && type == 2 && startDate == `${year}-${month}-${index + 1}` && startDate != endDate">
{{ startText }}
</view>
<view class="tui-date-desc" :style="{ color: activeColor }"
v-if="!lunar && type == 2 && endDate == `${year}-${month}-${index + 1}`">{{ endText }}</view>
</view>
<view class="tui-bg-month">{{ month }}</view>
</view>
<view class="tui-calendar-op">
<view class="tui-calendar-result">
<text>{{ type == 1 ? activeDate : startDate }}</text>
<text v-if="endDate">{{ endDate }}</text>
</view>
<view class="tui-calendar-btn_box">
<tui-button :type="btnType" height="72rpx" shape="circle" :size="28" :disabled="disabled"
@click="btnFix(false)">确定
</tui-button>
</view>
</view>
</view>
<view class="tui-popup-mask" :class="[isShow ? 'tui-mask-show' : '']" @tap="hide"></view>
</view>
<view v-else>
<view class="tui-date-box">
<view class="tui-iconfont tui-font-arrowleft" :style="{ color: yearArrowColor }" hover-class="tui-opacity"
:hover-stay-time="150" v-if="arrowType == 1" @tap="changeYear(0)"></view>
<view class="tui-iconfont tui-font-arrowleft" :style="{ color: monthArrowColor }" hover-class="tui-opacity"
:hover-stay-time="150" @tap="changeMonth(0)"></view>
<view class="tui-date_time">{{ showTitle }}</view>
<view class="tui-iconfont tui-font-arrowright" :style="{ color: monthArrowColor }" hover-class="tui-opacity"
:hover-stay-time="150" @tap="changeMonth(1)"></view>
<view class="tui-iconfont tui-font-arrowright" :style="{ color: yearArrowColor }" hover-class="tui-opacity"
:hover-stay-time="150" v-if="arrowType == 1" @tap="changeYear(1)"></view>
</view>
<view class="tui-date-header">
<view class="tui-date"></view>
<view class="tui-date"></view>
<view class="tui-date"></view>
<view class="tui-date"></view>
<view class="tui-date"></view>
<view class="tui-date"></view>
<view class="tui-date"></view>
</view>
<view class="tui-date-content" :style="{ height: isFixed && fixedHeight ? dateHeight * 6 + 'px' : 'auto' }">
<block v-for="(item, index) in weekdayArr" :key="index">
<view class="tui-date"></view>
</block>
<view class="tui-date" :class="{
'tui-date-pd_0': isFixed && fixedHeight,
'tui-opacity': openDisAbled(year, month, index + 1),
'tui-start-date': (type == 2 && startDate == `${year}-${month}-${index + 1}`) || type == 1,
'tui-end-date': (type == 2 && endDate == `${year}-${month}-${index + 1}`) || type == 1
}" :style="{ backgroundColor: isFixed ? getColor(index, 1) : 'transparent', height: isFixed && fixedHeight ? dateHeight + 'px' : 'auto' }"
v-for="(item, index) in daysArr" :key="index" @tap="dateClick(index)">
<view class="tui-date-text"
:style="{ color: isFixed ? getColor(index, 2) : getStatusData(3, index), backgroundColor: getStatusData(2, index) }">
<view v-if="isFixed || !getStatusData(4, index)">{{ index + 1 }}</view>
<view v-if="!getStatusData(4, index)" class="tui-custom-desc"
:class="{ 'tui-lunar-unshow': !lunar && isFixed }">
{{ getDescText(index, startDate, endDate) }}
</view>
<text class="tui-iconfont tui-font-check" v-if="getStatusData(4, index)"></text>
</view>
<view class="tui-date-desc" :style="{ color: activeColor }"
v-if="!lunar && type == 2 && startDate == `${year}-${month}-${index + 1}` && startDate != endDate">
{{ startText }}
</view>
<view class="tui-date-desc" :style="{ color: activeColor }"
v-if="!lunar && type == 2 && endDate == `${year}-${month}-${index + 1}`">{{ endText }}</view>
</view>
<view class="tui-bg-month">{{ month }}</view>
</view>
</view>
</template>
<script>
//easycom
// import tuiButton from "../tui-button/tui-button"
import calendar from './tui-calendar.js';
export default {
name: 'tuiCalendar',
emits: ['hide', 'change'],
// components:{
// tuiButton
// },
props: {
//1- 2-
arrowType: {
type: [Number, String],
default: 1
},
//1- 2-+
type: {
type: Number,
default: 1
},
//
maxYear: {
type: Number,
default: 2030
},
//
minYear: {
type: Number,
default: 1920
},
//()
minDate: {
type: String,
default: '1920-01-01'
},
/**
* 最大可选日期
* 默认最大值为今天之后的日期不可选
* 2030-12-31
* */
maxDate: {
type: String,
default: ''
},
//
radius: {
type: Boolean,
default: true
},
// index=>day
/**
* [{
* text:"", 描述2字以内
* value:"",状态值
* bgColor:"",背景色
* color:"" 文字颜色,
* check:false //
*
}]
*
* **/
status: {
type: Array,
default () {
return [];
}
},
//
monthArrowColor: {
type: String,
default: '#999'
},
//
yearArrowColor: {
type: String,
default: '#bcbcbc'
},
//
color: {
type: String,
default: '#333'
},
//|
activeBgColor: {
type: String,
default: '#5677fc'
},
//|
activeColor: {
type: String,
default: '#fff'
},
//
rangeBgColor: {
type: String,
default: 'rgba(86,119,252,0.1)'
},
//
rangeColor: {
type: String,
default: '#5677fc'
},
//type=2
startText: {
type: String,
default: '开始'
},
//type=2
endText: {
type: String,
default: '结束'
},
//
btnType: {
type: String,
default: 'primary'
},
//
isFixed: {
type: Boolean,
default: false
},
//isFixed=true
fixedHeight: {
type: Boolean,
default: true
},
//
isActiveCurrent: {
type: Boolean,
default: true
},
// type=1
isChange: {
type: Boolean,
default: false
},
//
lunar: {
type: Boolean,
default: false
},
// 2020-06-06 2020/06/06 type=1 or 2
initStartDate: {
type: String,
default: ''
},
// 2020-06-06 2020/06/06type=2
initEndDate: {
type: String,
default: ''
}
},
data() {
return {
isShow: false,
weekday: 1, // ,1-7
weekdayArr: [],
days: 0, //
daysArr: [],
showTitle: '',
year: 2020,
month: 0,
day: 0,
startYear: 0,
startMonth: 0,
startDay: 0,
endYear: 0,
endMonth: 0,
endDay: 0,
today: '',
activeDate: '',
startDate: '',
endDate: '',
isStart: true,
min: null,
max: null,
dateHeight: 20
};
},
computed: {
dataChange() {
return `${this.type}-${this.minDate}-${this.maxDate}-${this.initStartDate}-${this.initEndDate}`;
},
disabled() {
return this.type == 2 && (!this.startDate || !this.endDate)
}
},
watch: {
dataChange(val) {
this.init();
},
fixedHeight(val) {
if (val) {
this.initDateHeight();
}
}
},
created() {
this.init();
},
methods: {
getColor(index, type) {
let color = type == 1 ? '' : this.color;
let day = index + 1;
let date = `${this.year}-${this.month}-${day}`;
let timestamp = new Date(date.replace(/\-/g, '/')).getTime();
let start = this.startDate.replace(/\-/g, '/');
let end = this.endDate.replace(/\-/g, '/');
if ((this.isActiveCurrent && this.activeDate == date) || this.startDate == date || this.endDate == date) {
color = type == 1 ? this.activeBgColor : this.activeColor;
} else if (this.endDate && timestamp > new Date(start).getTime() && timestamp < new Date(end).getTime()) {
color = type == 1 ? this.rangeBgColor : this.rangeColor;
}
return color;
},
//
getStatusData(type, index) {
//1-text,2-bgColor,3-color 4-check
let val = ['', 'transparent', '#333', ''][type - 1];
if (!this.isFixed && this.status && this.status.length > 0) {
let item = this.status[index];
if (item) {
switch (type) {
case 1:
val = item.text;
break;
case 2:
val = item.bgColor;
break;
case 3:
val = item.color;
break;
case 4:
val = item.check;
break;
default:
break;
}
}
}
return val;
},
getDescText(index, startDate, endDate) {
let text = this.lunar ? this.getLunar(this.year, this.month, index + 1) : '';
if (this.isFixed && this.type == 2) {
//
if (this.lunar) {
let date = `${this.year}-${this.month}-${index + 1}`;
if (startDate == date && startDate != endDate) {
text = this.startText;
} else if (endDate == date) {
text = this.endText;
}
}
} else {
let status = this.getStatusData(1, index);
if (status) text = status;
}
return text;
},
getLunar(year, month, day) {
let obj = calendar.solar2lunar(year, month, day);
return obj.IDayCn;
},
initDateHeight() {
if (this.fixedHeight && this.isFixed) {
this.dateHeight = uni.getSystemInfoSync().windowWidth / 7;
}
},
init() {
this.initDateHeight();
let now = new Date();
this.year = now.getFullYear();
this.month = now.getMonth() + 1;
this.day = now.getDate();
this.today = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
this.activeDate = this.today;
this.min = this.initDate(this.minDate);
this.max = this.initDate(this.maxDate || this.today);
this.startDate = '';
this.startYear = 0;
this.startMonth = 0;
this.startDay = 0;
if (this.initStartDate) {
let start = new Date(this.initStartDate.replace(/\-/g, '/'));
if (this.type == 1) {
this.year = start.getFullYear();
this.month = start.getMonth() + 1;
this.day = start.getDate();
this.activeDate = `${start.getFullYear()}-${start.getMonth() + 1}-${start.getDate()}`;
} else {
this.startDate = `${start.getFullYear()}-${start.getMonth() + 1}-${start.getDate()}`;
this.startYear = start.getFullYear();
this.startMonth = start.getMonth() + 1;
this.startDay = start.getDate();
this.activeDate = '';
}
}
this.endYear = 0;
this.endMonth = 0;
this.endDay = 0;
this.endDate = '';
if (this.initEndDate && this.type == 2) {
let end = new Date(this.initEndDate.replace(/\-/g, '/'));
this.endDate = `${end.getFullYear()}-${end.getMonth() + 1}-${end.getDate()}`;
this.endYear = end.getFullYear();
this.endMonth = end.getMonth() + 1;
this.endDay = end.getDate();
this.activeDate = '';
this.year = end.getFullYear();
this.month = end.getMonth() + 1;
this.day = end.getDate();
}
this.isStart = true;
this.changeData();
},
//
initDate(date) {
let fdate = date.split('-');
return {
year: Number(fdate[0] || 1920),
month: Number(fdate[1] || 1),
day: Number(fdate[2] || 1)
};
},
openDisAbled: function(year, month, day) {
let bool = true;
let date = `${year}/${month}/${day}`;
// let today = this.today.replace(/\-/g, '/');
let min = `${this.min.year}/${this.min.month}/${this.min.day}`;
let max = `${this.max.year}/${this.max.month}/${this.max.day}`;
let timestamp = new Date(date).getTime();
if (timestamp >= new Date(min).getTime() && timestamp <= new Date(max).getTime()) {
bool = false;
}
return bool;
},
generateArray: function(start, end) {
return Array.from(new Array(end + 1).keys()).slice(start);
},
formatNum: function(num) {
return num < 10 ? '0' + num : num + '';
},
stop() {
return false;
},
//
getMonthDay(year, month) {
let days = new Date(year, month, 0).getDate();
return days;
},
getWeekday(year, month) {
let date = new Date(`${year}/${month}/01 00:00:00`);
return date.getDay();
},
checkRange(year) {
let overstep = false;
if (year < this.minYear || year > this.maxYear) {
uni.showToast({
title: '日期超出范围啦~',
icon: 'none'
});
overstep = true;
}
return overstep;
},
changeMonth(isAdd) {
if (isAdd) {
let month = this.month + 1;
let year = month > 12 ? this.year + 1 : this.year;
if (!this.checkRange(year)) {
this.month = month > 12 ? 1 : month;
this.year = year;
this.changeData();
}
} else {
let month = this.month - 1;
let year = month < 1 ? this.year - 1 : this.year;
if (!this.checkRange(year)) {
this.month = month < 1 ? 12 : month;
this.year = year;
this.changeData();
}
}
},
changeYear(isAdd) {
let year = isAdd ? this.year + 1 : this.year - 1;
if (!this.checkRange(year)) {
this.year = year;
this.changeData();
}
},
changeData() {
this.days = this.getMonthDay(this.year, this.month);
this.daysArr = this.generateArray(1, this.days);
this.weekday = this.getWeekday(this.year, this.month);
this.weekdayArr = this.generateArray(1, this.weekday);
this.showTitle = `${this.year}${this.month}`;
if (this.isChange && this.type == 1) {
this.btnFix(true);
}
},
dateClick: function(day) {
day += 1;
if (!this.openDisAbled(this.year, this.month, day)) {
this.day = day;
let date = `${this.year}-${this.month}-${day}`;
if (this.type == 1) {
this.activeDate = date;
} else {
let compare = new Date(date.replace(/\-/g, '/')).getTime() < new Date(this.startDate.replace(
/\-/g, '/')).getTime();
if (this.isStart || compare) {
this.startDate = date;
this.startYear = this.year;
this.startMonth = this.month;
this.startDay = this.day;
this.endYear = 0;
this.endMonth = 0;
this.endDay = 0;
this.endDate = '';
this.activeDate = '';
this.isStart = false;
} else {
this.endDate = date;
this.endYear = this.year;
this.endMonth = this.month;
this.endDay = this.day;
this.isStart = true;
}
}
if (!this.isFixed) {
this.btnFix();
}
}
},
show() {
this.isShow = true;
},
hide() {
this.isShow = false;
this.$emit('hide', {})
},
getWeekText(date) {
date = new Date(`${date.replace(/\-/g, '/')} 00:00:00`);
let week = date.getDay();
return '星期' + ['日', '一', '二', '三', '四', '五', '六'][week];
},
btnFix(show) {
if (!show) {
this.hide();
}
if (this.type == 1) {
let arr = this.activeDate.split('-');
let year = this.isChange ? this.year : Number(arr[0]);
let month = this.isChange ? this.month : Number(arr[1]);
let day = this.isChange ? this.day : Number(arr[2]);
//
let days = this.getMonthDay(year, month);
let result = `${year}-${this.formatNum(month)}-${this.formatNum(day)}`;
let weekText = this.getWeekText(result);
let isToday = false;
if (`${year}-${month}-${day}` == this.today) {
//
isToday = true;
}
let lunar = calendar.solar2lunar(year, month, day);
this.$emit('change', {
year: year,
month: month,
day: day,
days: days,
result: result,
week: weekText,
isToday: isToday,
switch: show, //
lunar: lunar
});
} else {
if (!this.startDate || !this.endDate) return;
let startMonth = this.formatNum(this.startMonth);
let startDay = this.formatNum(this.startDay);
let startDate = `${this.startYear}-${startMonth}-${startDay}`;
let startWeek = this.getWeekText(startDate);
let startLunar = calendar.solar2lunar(this.startYear, startMonth, startDay);
let endMonth = this.formatNum(this.endMonth);
let endDay = this.formatNum(this.endDay);
let endDate = `${this.endYear}-${endMonth}-${endDay}`;
let endWeek = this.getWeekText(endDate);
let endLunar = calendar.solar2lunar(this.endYear, endMonth, endDay);
this.$emit('change', {
startYear: this.startYear,
startMonth: this.startMonth,
startDay: this.startDay,
startDate: startDate,
startWeek: startWeek,
startLunar: startLunar,
endYear: this.endYear,
endMonth: this.endMonth,
endDay: this.endDay,
endDate: endDate,
endWeek: endWeek,
endLunar: endLunar
});
}
}
}
};
</script>
<style scoped>
@font-face {
font-family: 'tuiDateFont';
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAVgAA0AAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAFRAAAABoAAAAci0/w50dERUYAAAUkAAAAHgAAAB4AKQANT1MvMgAAAaAAAABDAAAAVjxuSNNjbWFwAAAB+AAAAEoAAAFS5iPQt2dhc3AAAAUcAAAACAAAAAj//wADZ2x5ZgAAAlQAAAFHAAABvPf29TBoZWFkAAABMAAAADAAAAA2GMsN3WhoZWEAAAFgAAAAHQAAACQHjAOFaG10eAAAAeQAAAATAAAAFgzQAPJsb2NhAAACRAAAABAAAAAQAOoBSG1heHAAAAGAAAAAHgAAACABEwA3bmFtZQAAA5wAAAFJAAACiCnmEVVwb3N0AAAE6AAAADQAAABLUwjqHHjaY2BkYGAAYp5Gj5/x/DZfGbhZGEDg1tUn7+F00P/LzOuY9YFcDgYmkCgAa0gNlHjaY2BkYGBu+N/AEMPCAALM6xgYGVABCwBT4AMaAAAAeNpjYGRgYGBn0GZgYgABEMkFhAwM/8F8BgANaAFLAAB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PGJ49ZG7438AQw9zA0AAUZgTJAQDrcAy8AHjaY2GAABYIDgLCBQx1AAcEAc8AeNpjYGBgZoBgGQZGBhDwAfIYwXwWBgMgzQGETAwMzxifcTx7+P8/kMUAYUkxS/6VVIXqAgNGNgY4lxGoB6QPBTAyDHsAADDkDYkAAAAAAAAAAAAAADQAagC2AN542m2QsU7DMBCG/Tt1bNPUiUnkSgiVtqKpxJAgVLVbeAa6MaK+B4JXgJWBjY21UtW5gpkdMTFX7dzApaJLhXU6n8+n//ttxtn458N79XJWZ8eMxS00C4wy9A1EP8PQncAlIQzS4WgsVtPpSmwzV3OFRqLetH5TSQMK939X61ptPZ2p2EAttNMLBRMrtschQblDeS34aY50cIkCzg/B2Y5C+VpyQxhFkRgu515O8jvU5mmPM2O0wJ5Z27vhX+yMsV437WvCdTM+GI40MgwKfuGammC0uURqeqFMfe9cxaJclkt5GMaB1hIR1VobOgpEiKq+sLZcIrJWhO3/Jw7qWlYj1Jf21FaCtmd5bevrlk28O/7A4spXTl4KTh9MTlqQ8PESBRstReic+sRj0Dni9fIqmNS/pXNWCvWOeYBmx5S9Bsn9Ah+5WtAAeNp9kD1OAzEQhZ/zByQSQiCoXVEA2vyUKRMp9Ailo0g23pBo1155nUg5AS0VB6DlGByAGyDRcgpelkmTImvt6PObmeexAZzjGwr/3yXuhBWO8ShcwREy4Sr1F+Ea+V24jhY+hRvUf4SbuFUD4RYu1BsdVO2Eu5vSbcsKZxgIV3CKJ+Eq9ZVwjfwqXMcVPoQb1L+EmxjjV7iFa2WpDOFhMEFgnEFjig3jAjEcLJIyBtahOfRmEsxMTzd6ETubOBso71dilwMeaDnngCntPbdmvkon/mDLgdSYbh4FS7YpjS4idCgbXyyc1d2oc7D9nu22tNi/a4E1x+xRDWzU/D3bM9JIbAyvkJI18jK3pBJTj2hrrPG7ZynW814IiU68y/SIx5o0dTr3bmniwOLn8owcfbS5kj33qBw+Y1kIeb/dTsQgil2GP5PYcRkAAAB42mNgYoAALjDJyIAO2MGiTIxMjMyMLIys7GmJeRmlmWZQ2pQ5OSORLaU0Mz2/FACDfwlbAAAAAf//AAIAAQAAAAwAAAAWAAAAAgABAAMABgABAAQAAAACAAAAAHjaY2BgYGQAgqtL1DlA9K2rT97DaABNlwiuAAA=) format('woff');
font-weight: normal;
font-style: normal;
}
.tui-iconfont {
font-family: 'tuiDateFont' !important;
font-size: 36rpx;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.tui-font-close:before {
content: '\e608';
}
.tui-font-check:before {
content: '\e6e1';
}
.tui-font-arrowright:before {
content: '\e600';
}
.tui-font-arrowleft:before {
content: '\e601';
}
.tui-date-box {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx 0 30rpx;
background-color: #fff;
}
.tui-calendar-radius {
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
overflow: hidden;
}
.tui-date_time {
padding: 0 16rpx;
color: #333;
font-size: 32rpx;
line-height: 32rpx;
font-weight: bold;
}
.tui-font-arrowleft {
margin-right: 32rpx;
}
.tui-font-arrowright {
margin-left: 32rpx;
}
.tui-date-header {
width: 100%;
display: flex;
align-items: center;
background-color: #fff;
font-size: 24rpx;
line-height: 24rpx;
color: #555;
box-shadow: 0 15rpx 20rpx -15rpx #efefef;
position: relative;
z-index: 2;
}
.tui-date-content {
width: 100%;
display: flex;
flex-wrap: wrap;
padding: 12rpx 0;
box-sizing: border-box;
background-color: #fff;
position: relative;
}
.tui-flex-start {
align-content: flex-start;
}
.tui-bg-month {
position: absolute;
font-size: 260rpx;
line-height: 260rpx;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
color: #f5f5f7;
z-index: 1;
}
.tui-date {
width: 14.2857%;
display: flex;
align-items: center;
justify-content: center;
padding: 12rpx 0;
overflow: hidden;
position: relative;
z-index: 2;
}
.tui-date-pd_0 {
padding: 0 !important;
}
.tui-start-date {
border-top-left-radius: 8rpx;
border-bottom-left-radius: 8rpx;
}
.tui-end-date {
border-top-right-radius: 8rpx;
border-bottom-right-radius: 8rpx;
}
.tui-date-text {
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font-size: 32rpx;
line-height: 32rpx;
position: relative;
border-radius: 50%;
}
.tui-btn-calendar {
padding: 16rpx;
box-sizing: border-box;
text-align: center;
text-decoration: none;
}
.tui-opacity {
opacity: 0.5;
}
.tui-bottom-popup {
width: 100%;
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 9999;
visibility: hidden;
transform: translate3d(0, 100%, 0);
transform-origin: center;
transition: all 0.3s ease-in-out;
min-height: 20rpx;
}
.tui-popup-show {
transform: translate3d(0, 0, 0);
visibility: visible;
}
.tui-popup-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.6);
z-index: 9996;
transition: all 0.3s ease-in-out;
opacity: 0;
visibility: hidden;
}
.tui-mask-show {
opacity: 1;
visibility: visible;
}
.tui-calendar-header {
width: 100%;
height: 80rpx;
padding: 0 40rpx;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
font-size: 30rpx;
background-color: #fff;
color: #555;
position: relative;
}
.tui-font-close {
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
color: #999;
}
.tui-btn-calendar {
padding: 16rpx;
box-sizing: border-box;
text-align: center;
text-decoration: none;
}
.tui-font-check {
color: #fff;
font-size: 54rpx;
line-height: 54rpx;
}
.tui-custom-desc {
width: 100%;
font-size: 24rpx;
line-height: 24rpx;
transform: scale(0.8);
transform-origin: center center;
text-align: center;
}
.tui-lunar-unshow {
position: absolute;
left: 0;
bottom: 8rpx;
z-index: 2;
}
.tui-date-desc {
width: 100%;
font-size: 24rpx;
line-height: 24rpx;
position: absolute;
left: 0;
transform: scale(0.8);
transform-origin: center center;
text-align: center;
bottom: 8rpx;
z-index: 2;
}
.tui-calendar-op {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background-color: #fff;
padding: 0 42rpx 30rpx;
box-sizing: border-box;
font-size: 24rpx;
color: #666;
}
.tui-calendar-result {
height: 48rpx;
transform: scale(0.9);
transform-origin: center 100%;
}
.tui-calendar-btn_box {
width: 100%;
}
</style>

View File

@ -1,212 +0,0 @@
<template>
<view class="tui-card-class tui-card" :class="[full?'tui-card-full':'',border?'tui-card-border':'']" @tap="handleClick"
@longtap="longTap">
<view class="tui-card-header" :class="{'tui-header-line':header.line}" :style="{background:header.bgcolor || '#fff'}">
<view class="tui-header-left">
<image :src="image.url" class="tui-header-thumb" :class="{'tui-thumb-circle':image.circle}" mode="widthFix" v-if="image.url"
:style="{height:(image.height || 60)+'rpx',width:(image.width || 60)+'rpx'}"></image>
<text class="tui-header-title" :style="{fontSize:(title.size || 30)+'rpx',color:(title.color || '#7A7A7A')}" v-if="title.text">{{title.text}}</text>
</view>
<view class="tui-header-right" :style="{fontSize:(tag.size || 24)+'rpx',color:(tag.color || '#b2b2b2')}" v-if="tag.text">
{{tag.text}}
</view>
</view>
<view class="tui-card-body">
<slot name="body"></slot>
</view>
<view class="tui-card-footer">
<slot name="footer"></slot>
</view>
</view>
</template>
<script>
export default {
name: "tuiCard",
emits: ['click','longclick'],
props: {
//
full: {
type: Boolean,
default: false
},
image: {
type: Object,
default: function() {
return {
url: "", //
height: 60, //
width: 60, //
circle: false
}
}
},
//
title: {
type: Object,
default: function() {
return {
text: "", //
size: 30, //
color: "#7A7A7A" //
}
}
},
//
tag: {
type: Object,
default: function() {
return {
text: "", //
size: 24, //
color: "#b2b2b2" //
}
}
},
header: {
type: Object,
default: function() {
return {
bgcolor: "#fff", //
line: false //线
}
}
},
//
border: {
type: Boolean,
default: false
},
index: {
type: Number,
default: 0
}
},
methods: {
handleClick() {
this.$emit('click', {
index: this.index
});
},
longTap() {
this.$emit('longclick', {
index: this.index
});
}
}
}
</script>
<style scoped>
.tui-card {
margin: 0 30rpx;
font-size: 28rpx;
background-color: #fff;
border-radius: 10rpx;
box-shadow: 0 0 10rpx #eee;
box-sizing: border-box;
overflow: hidden;
}
.tui-card-full {
margin: 0 !important;
border-radius: 0 !important;
}
.tui-card-full::after {
border-radius: 0 !important;
}
.tui-card-border {
position: relative;
box-shadow: none !important
}
.tui-card-border::after {
content: ' ';
position: absolute;
height: 200%;
width: 200%;
border: 1px solid #ddd;
transform-origin: 0 0;
-webkit-transform-origin: 0 0;
-webkit-transform: scale(0.5);
transform: scale(0.5);
left: 0;
top: 0;
border-radius: 20rpx;
box-sizing: border-box;
pointer-events: none;
}
.tui-card-header {
width: 100%;
padding: 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
box-sizing: border-box;
overflow: hidden;
border-top-left-radius: 10rpx;
border-top-right-radius: 10rpx;
}
.tui-card-header::after {
content: '';
position: absolute;
border-bottom: 1rpx solid #eaeef1;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
bottom: 0;
right: 0;
left: 0;
pointer-events: none;
}
.tui-header-line::after {
border-bottom: 0 !important;
}
.tui-header-thumb {
height: 60rpx;
width: 60rpx;
vertical-align: middle;
margin-right: 20rpx;
border-radius: 6rpx;
}
.tui-thumb-circle {
border-radius: 50% !important;
}
.tui-header-title {
display: inline-block;
font-size: 30rpx;
color: #7a7a7a;
vertical-align: middle;
max-width: 460rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.tui-header-right {
font-size: 24rpx;
color: #b2b2b2;
}
.tui-card-body {
font-size: 32rpx;
color: #262b3a;
box-sizing: border-box;
}
.tui-card-footer {
font-size: 28rpx;
color: #596d96;
border-bottom-left-radius: 10rpx;
border-bottom-right-radius: 10rpx;
box-sizing: border-box;
}
</style>

View File

@ -1,513 +0,0 @@
<template>
<view class="tui-cascade-selection">
<scroll-view scroll-x scroll-with-animation :scroll-into-view="scrollViewId"
:style="{ backgroundColor: headerBgColor }" class="tui-bottom-line"
:class="{ 'tui-btm-none': !headerLine }">
<view class="tui-selection-header" :style="{ height: tabsHeight, backgroundColor: backgroundColor }">
<view class="tui-header-item" :class="{ 'tui-font-bold': idx === currentTab && bold }"
:style="{ color: idx === currentTab ? activeColor : color, fontSize: size + 'rpx' }"
:id="`id_${idx}`" @tap.stop="swichNav" :data-current="idx" v-for="(item, idx) in selectedArr"
:key="idx">
{{ item.text }}
<view class="tui-active-line" :style="{ backgroundColor: lineColor }"
v-if="idx === currentTab && showLine"></view>
</view>
</view>
</scroll-view>
<swiper class="tui-selection-list" :current="currentTab" duration="300" @change="switchTab"
:style="{ height: height, backgroundColor: backgroundColor }">
<swiper-item v-for="(item, index) in selectedArr" :key="index">
<scroll-view scroll-y :scroll-into-view="item.scrollViewId" class="tui-selection-item"
:style="{ height: height }">
<view class="tui-first-item" :style="{ height: firstItemTop }"></view>
<view class="tui-selection-cell" :style="{ padding: padding, backgroundColor: backgroundColor }"
:id="`id_${subIndex}`" v-for="(subItem, subIndex) in item.list" :key="subIndex"
@tap="change(index, subIndex, subItem)">
<icon type="success_no_circle" v-if="item.index === subIndex" :color="checkMarkColor"
:size="checkMarkSize" class="tui-icon-success"></icon>
<image :src="subItem.src" v-if="subItem.src" class="tui-cell-img"
:style="{ width: imgWidth, height: imgHeight, borderRadius: radius }"></image>
<view class="tui-cell-title"
:class="{ 'tui-font-bold': item.index === subIndex && textBold, 'tui-flex-shrink': nowrap }"
:style="{ color: item.index === subIndex ? textActiveColor : textColor, fontSize: textSize + 'rpx' }">
{{ subItem.text }}
</view>
<view class="tui-cell-sub_title" :style="{ color: subTextColor, fontSize: subTextSize + 'rpx' }"
v-if="subItem.subText">{{ subItem.subText }}</view>
</view>
</scroll-view>
</swiper-item>
</swiper>
</view>
</template>
<script>
export default {
name: 'tuiCascadeSelection',
emits: ['change','complete'],
props: {
/**
* 如果下一级是请求返回则为第一级数据否则所有数据
* 数据格式
[{
src: "",
text: "",
subText: "",
value: 0,
children:[{
text: "",
subText: "",
value: 0,
children:[]
}]
}]
* */
itemList: {
type: Array,
default: () => {
return [];
}
},
/*
初始化默认选中数据
[{
text: "",//text
subText: '',//subText
value: '',//value
src: '', //src
index: 0, //layer
list: [{src: "", text: "", subText: "", value: 101}] //layer
}];
*/
defaultItemList: {
type: Array,
value: []
},
//header线
headerLine: {
type: Boolean,
default: true
},
//header
headerBgColor: {
type: String,
default: '#FFFFFF'
},
//
tabsHeight: {
type: String,
default: '88rpx'
},
//
text: {
type: String,
default: '请选择'
},
//tabs
size: {
type: Number,
default: 28
},
//tabs
color: {
type: String,
default: '#555'
},
//
activeColor: {
type: String,
default: '#5677fc'
},
//
bold: {
type: Boolean,
default: true
},
//线
showLine: {
type: Boolean,
default: true
},
//线
lineColor: {
type: String,
default: '#5677fc'
},
//icon
checkMarkSize: {
type: Number,
default: 15
},
//icon
checkMarkColor: {
type: String,
default: '#5677fc'
},
//item
imgWidth: {
type: String,
default: '40rpx'
},
//item
imgHeight: {
type: String,
default: '40rpx'
},
//
radius: {
type: String,
default: '50%'
},
//item text
textColor: {
type: String,
default: '#333'
},
textActiveColor: {
type: String,
default: '#333'
},
//
textBold: {
type: Boolean,
default: true
},
//item text
textSize: {
type: Number,
default: 28
},
//text
nowrap: {
type: Boolean,
default: false
},
//item subText
subTextColor: {
type: String,
default: '#999'
},
//item subText
subTextSize: {
type: Number,
default: 24
},
// item padding
padding: {
type: String,
default: '20rpx 30rpx'
},
//
firstItemTop: {
type: String,
default: '20rpx'
},
//swiper
height: {
type: String,
default: '300px'
},
//item swiper
backgroundColor: {
type: String,
default: '#FFFFFF'
},
//false
request: {
type: Boolean,
default: false
},
//request=true
receiveData: {
type: Array,
default: () => {
return [];
}
},
//
reset: {
type: [Number, String],
default: 0
}
},
watch: {
itemList(val) {
this.initData(val, -1);
},
receiveData(val) {
this.subLevelData(val, this.currentTab);
},
reset() {
this.initData(this.itemList, -1);
},
defaultItemList(val) {
this.setDefaultData(val)
}
},
created() {
this.setDefaultData(this.defaultItemList)
},
data() {
return {
currentTab: 0,
//tabscrollview
scrollViewId: 'id__1',
selectedArr: []
};
},
methods: {
setDefaultData(val) {
let defaultItemList = val || [];
if (defaultItemList.length > 0) {
defaultItemList.map(item => {
item.scrollViewId = `id_${item.index}`;
});
this.selectedArr = defaultItemList;
this.currentTab = defaultItemList.length - 1;
this.$nextTick(() => {
this.checkCor();
});
} else {
this.initData(this.itemList, -1);
}
},
initData(data, layer) {
if (!data || data.length === 0) return;
if (this.request) {
//
this.subLevelData(data, layer);
} else {
let selectedValue = this.selectedValue || {};
if (selectedValue.type) {
this.setDefaultData(selectedValue);
} else {
this.subLevelData(this.getItemList(layer, -1), layer);
}
}
},
removeChildren(data) {
let list = data.map(item => {
delete item['children'];
return item;
});
return list;
},
getItemList(layer, index) {
let list = [];
let arr = JSON.parse(JSON.stringify(this.itemList));
if (layer == -1) {
list = this.removeChildren(arr);
} else {
let value = this.selectedArr[0].index;
value = value == -1 ? index : value;
list = arr[value].children || [];
if (layer > 0) {
for (let i = 1; i < layer + 1; i++) {
let val = layer === i ? index : this.selectedArr[i].index;
list = list[val].children || [];
if (list.length === 0) break;
}
}
list = this.removeChildren(list);
}
return list;
},
//
switchTab: function(e) {
this.currentTab = e.detail.current;
this.checkCor();
},
//
swichNav: function(e) {
let cur = e.currentTarget.dataset.current;
if (this.currentTab != cur) {
this.currentTab = cur;
}
},
checkCor: function() {
let item = this.selectedArr[this.currentTab];
item.scrollViewId = 'id__1';
this.$nextTick(() => {
setTimeout(() => {
let val = item.index < 2 ? 0 : Number(item.index - 2);
item.scrollViewId = `id_${val}`;
}, 2);
});
if (this.currentTab > 1) {
this.scrollViewId = `id_${this.currentTab - 1}`;
} else {
this.scrollViewId = `id_0`;
}
},
change(index, subIndex, subItem) {
let item = this.selectedArr[index];
if (item.index == subIndex) return;
item.index = subIndex;
item.text = subItem.text;
item.value = subItem.value;
item.subText = subItem.subText || '';
item.src = subItem.src || '';
this.$emit('change', {
layer: index,
subIndex: subIndex, //layer=> Array index
...subItem
});
if (!this.request) {
let data = this.getItemList(index, subIndex);
this.subLevelData(data, index);
}
},
//
subLevelData(data, layer) {
if (!data || data.length === 0) {
if (layer == -1) return;
//
let arr = this.selectedArr;
if (layer < arr.length - 1) {
let newArr = arr.slice(0, layer + 1);
this.selectedArr = newArr;
}
let result = JSON.parse(JSON.stringify(this.selectedArr));
let lastItem = result[result.length - 1] || {};
let text = '';
result.map(item => {
text += item.text;
delete item['list'];
//delete item['index'];
delete item['scrollViewId'];
return item;
});
this.$emit('complete', {
result: result,
value: lastItem.value,
text: text,
subText: lastItem.subText,
src: lastItem.src
});
} else {
// >layer
let item = [{
text: this.text,
subText: '',
value: '',
src: '',
index: -1,
scrollViewId: 'id__1',
list: data
}];
if (layer == -1) {
this.selectedArr = item;
} else {
let retainArr = this.selectedArr.slice(0, layer + 1);
this.selectedArr = retainArr.concat(item);
}
this.$nextTick(() => {
this.currentTab = this.selectedArr.length - 1;
});
}
}
}
};
</script>
<style scoped>
.tui-cascade-selection {
width: 100%;
box-sizing: border-box;
}
.tui-selection-header {
width: 100%;
display: flex;
align-items: center;
position: relative;
box-sizing: border-box;
}
.tui-bottom-line {
position: relative;
}
.tui-bottom-line::after {
width: 100%;
content: '';
position: absolute;
border-bottom: 1rpx solid #eaeef1;
-webkit-transform: scaleY(0.5) translateZ(0);
transform: scaleY(0.5) translateZ(0);
transform-origin: 0 100%;
bottom: 0;
right: 0;
left: 0;
}
.tui-btm-none::after {
border-bottom: 0 !important;
}
.tui-header-item {
max-width: 240rpx;
padding: 15rpx 30rpx;
box-sizing: border-box;
flex-shrink: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
position: relative;
}
.tui-font-bold {
font-weight: bold;
}
.tui-active-line {
width: 60rpx;
height: 6rpx;
border-radius: 4rpx;
position: absolute;
bottom: 0;
right: 0;
left: 50%;
transform: translateX(-50%);
}
.tui-selection-cell {
width: 100%;
box-sizing: border-box;
display: flex;
align-items: center;
}
.tui-icon-success {
margin-right: 12rpx;
}
.tui-cell-img {
margin-right: 12rpx;
flex-shrink: 0;
}
.tui-cell-title {
word-break: break-all;
}
.tui-flex-shrink {
flex-shrink: 0;
}
.tui-font-bold {
font-weight: bold;
}
.tui-cell-sub_title {
margin-left: 20rpx;
word-break: break-all;
}
.tui-first-item {
width: 100%;
}
</style>

View File

@ -1,265 +0,0 @@
<template>
<view class="tui-circular-container" :style="{ width: diam + 'px', height: (height || diam) + 'px' }">
<canvas
class="tui-circular-default"
:canvas-id="defaultCanvasId"
:id="defaultCanvasId"
:style="{ width: diam + 'px', height: (height || diam) + 'px' }"
v-if="defaultShow"
></canvas>
<canvas class="tui-circular-progress" :canvas-id="progressCanvasId" :id="progressCanvasId" :style="{ width: diam + 'px', height: (height || diam) + 'px' }"></canvas>
<slot />
</view>
</template>
<script>
export default {
name: 'tuiCircularProgress',
emits: ['change','end'],
props: {
/*
传值需使用rpx进行转换保证各终端兼容
px = rpx / 750 * wx.getSystemInfoSync().windowWidth
圆形进度条(画布)宽度直径 [px]
*/
diam: {
type: Number,
default: 60
},
//()diam[heightheight]
height: {
type: Number,
default: 0
},
//线[px]
lineWidth: {
type: Number,
default: 4
},
/*
线条的端点样式
butt向线条的每个末端添加平直的边缘
round 向线条的每个末端添加圆形线帽
square 向线条的每个末端添加正方形线帽
*/
lineCap: {
type: String,
default: 'round'
},
// [px]
fontSize: {
type: Number,
default: 12
},
//
fontColor: {
type: String,
default: '#5677fc'
},
//
fontShow: {
type: Boolean,
default: true
},
/*
自定义显示文字[默认为空显示百分比fontShow=true时生效]
可以使用 slot自定义显示内容
*/
percentText: {
type: String,
default: ''
},
//()
defaultShow: {
type: Boolean,
default: true
},
//
defaultColor: {
type: String,
default: '#CCC'
},
//
progressColor: {
type: String,
default: '#5677fc'
},
//[progressColor使]
gradualColor: {
type: String,
default: ''
},
//
sAngle: {
type: Number,
default: -Math.PI / 2
},
//false
counterclockwise: {
type: Boolean,
default: false
},
// [10% 10]
percentage: {
type: Number,
default: 0
},
//[使100%2]
multiple: {
type: Number,
default: 1
},
//[50]
duration: {
type: Number,
default: 800
},
//backwards: forwards
activeMode: {
type: String,
default: 'backwards'
}
},
watch: {
percentage(val) {
this.initDraw();
}
},
data() {
return {
// #ifdef MP-WEIXIN
progressCanvasId: 'progressCanvasId',
defaultCanvasId: 'defaultCanvasId',
// #endif
// #ifndef MP-WEIXIN
progressCanvasId: this.getCanvasId(),
defaultCanvasId: this.getCanvasId(),
// #endif
progressContext: null,
linearGradient: null,
//
startPercentage: 0
// dpi
//pixelRatio: uni.getSystemInfoSync().pixelRatio
};
},
mounted() {
this.initDraw(true);
},
methods: {
//
initDraw(init) {
let start = this.activeMode === 'backwards' ? 0 : this.startPercentage;
start = start > this.percentage ? 0 : start;
if (this.defaultShow && init) {
this.drawDefaultCircular();
}
this.drawProgressCircular(start);
},
//()
drawDefaultCircular() {
let ctx = uni.createCanvasContext(this.defaultCanvasId, this);
ctx.setLineWidth(this.lineWidth);
ctx.setStrokeStyle(this.defaultColor);
//
let eAngle = Math.PI * (this.height ? 1 : 2) + this.sAngle;
this.drawArc(ctx, eAngle);
},
//
drawProgressCircular(startPercentage) {
let ctx = this.progressContext;
let gradient = this.linearGradient;
if (!ctx) {
ctx = uni.createCanvasContext(this.progressCanvasId, this);
//线 CanvasGradient
gradient = ctx.createLinearGradient(0, 0, this.diam, 0);
gradient.addColorStop('0', this.progressColor);
if (this.gradualColor) {
gradient.addColorStop('1', this.gradualColor);
}
// #ifdef APP-PLUS || MP
const res = uni.getSystemInfoSync();
if (!this.gradualColor && res.platform.toLocaleLowerCase() == 'android') {
gradient.addColorStop('1', this.progressColor);
}
// #endif
this.progressContext = ctx;
this.linearGradient = gradient;
}
ctx.setLineWidth(this.lineWidth);
ctx.setStrokeStyle(gradient);
let time = this.percentage == 0 || this.duration < 50 ? 0 : this.duration / this.percentage;
if (this.percentage > 0) {
startPercentage = this.duration < 50 ? this.percentage - 1 : startPercentage;
startPercentage++;
}
if (this.fontShow) {
ctx.setFontSize(this.fontSize);
ctx.setFillStyle(this.fontColor);
ctx.setTextAlign('center');
ctx.setTextBaseline('middle');
let percentage = this.percentText;
if (!percentage) {
percentage = this.counterclockwise ? 100 - startPercentage * this.multiple : startPercentage * this.multiple;
percentage = `${percentage}%`;
}
let radius = this.diam / 2;
ctx.fillText(percentage, radius, radius);
}
if (this.percentage == 0 || (this.counterclockwise && startPercentage == 100)) {
ctx.draw();
}else{
let eAngle = ((2 * Math.PI) / 100) * startPercentage + this.sAngle;
this.drawArc(ctx, eAngle);
}
setTimeout(() => {
this.startPercentage = startPercentage;
if (startPercentage == this.percentage) {
this.$emit('end', {
canvasId: this.progressCanvasId,
percentage: startPercentage
});
} else {
this.drawProgressCircular(startPercentage);
}
this.$emit('change', {
percentage: startPercentage
});
}, time);
// #ifdef H5
// requestAnimationFrame(()=>{})
// #endif
},
//线
drawArc(ctx, eAngle) {
ctx.setLineCap(this.lineCap);
ctx.beginPath();
let radius = this.diam / 2; //x=y
ctx.arc(radius, radius, radius - this.lineWidth, this.sAngle, eAngle, this.counterclockwise);
ctx.stroke();
ctx.draw();
},
//canvasId
getCanvasId() {
let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
return (c === 'x' ? (Math.random() * 16) | 0 : 'r&0x3' | '0x8').toString(16);
});
return uuid;
}
}
};
</script>
<style scoped>
.tui-circular-container,
.tui-circular-default {
position: relative;
}
.tui-circular-progress {
position: absolute;
left: 0;
top: 0;
z-index: 10;
}
</style>

View File

@ -1,167 +0,0 @@
<template>
<view class="tui-collapse" :style="{backgroundColor:bgColor}">
<view class="tui-collapse-head" :style="{backgroundColor:hdBgColor}" @tap.stop="handleClick">
<view class="tui-header" :class="{'tui-opacity':disabled}">
<slot name="title"></slot>
<view class="tui-collapse-icon tui-icon-arrow" :class="{'tui-icon-active':isOpen}" :style="{color:arrowColor}" v-if="arrow"></view>
</view>
</view>
<view class="tui-collapse-body_box" :style="{backgroundColor:bdBgColor,height:isOpen?height:'0rpx'}">
<view class="tui-collapse-body" :class="{'tui-collapse-transform':height=='auto','tui-collapse-body_show':isOpen && height=='auto'}">
<slot name="content"></slot>
</view>
</view>
</view>
</template>
<script>
export default {
name: "tuiCollapse",
emits: ['click'],
props: {
//collapse
bgColor: {
type: String,
default: 'transparent'
},
//collapse-head
hdBgColor: {
type: String,
default: '#fff'
},
//collapse-body
bdBgColor: {
type: String,
default: 'transparent'
},
//collapse-body open使
height: {
type: String,
default: 'auto'
},
//
index: {
type: Number,
default: 0
},
//index==current
current: {
type: Number,
default: -1
},
//
disabled: {
type: [Boolean, String],
default: false
},
//
arrow: {
type: [Boolean, String],
default: true
},
//
arrowColor: {
type: String,
default: "#333"
}
},
watch: {
current() {
this.updateCurrentChange()
}
},
created() {
this.updateCurrentChange()
},
data() {
return {
isOpen: false
};
},
methods: {
updateCurrentChange() {
this.isOpen = this.index == this.current
},
handleClick() {
if (this.disabled) return;
this.$emit("click", {
index: Number(this.index)
})
}
}
}
</script>
<style scoped>
@font-face {
font-family: 'tuiCollapse';
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAQ4AA0AAAAABlgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAEHAAAABoAAAAciRx3B0dERUYAAAP8AAAAHgAAAB4AKQAKT1MvMgAAAaAAAABCAAAAVjxuR/JjbWFwAAAB9AAAAD4AAAFCAA/pq2dhc3AAAAP0AAAACAAAAAj//wADZ2x5ZgAAAkAAAABEAAAARCs1U/toZWFkAAABMAAAADAAAAA2FpaT+mhoZWEAAAFgAAAAHQAAACQHngOFaG10eAAAAeQAAAAPAAAAEAwAAEBsb2NhAAACNAAAAAoAAAAKACIAAG1heHAAAAGAAAAAHwAAACABDwAdbmFtZQAAAoQAAAFJAAACiCnmEVVwb3N0AAAD0AAAACMAAAA1DunpUnjaY2BkYGAAYja/oO54fpuvDNwsDCBwc4/6fzjtwNDNfICpBMjlYGACiQIAGVAKZnjaY2BkYGBu+N/AEMPCAALMBxgYGVABCwBVNgMsAAAAeNpjYGRgYGBhEGQA0QwMTEDMBYQMDP/BfAYACnYBLQB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PGJ4xMDf8b2CIYW5gaAAKM4LkANq9C9sAAHjaY2GAABYIdgAAAMAATQB42mNgYGBmgGAZBkYGELAB8hjBfBYGBSDNAoRA/jOG//8hpBQzVCUDIxsDjMnAyAQkmBhQASPDsAcAMCAGoQAAAAAAAAAAAAAAIgAAAAEAQACLA8ACdAAQAAAlASYiBhQXARYyNwE2NCYiBwIA/oYNIBkMAZcNIA0BlwwZIA3uAXoMGSAN/mkMDAGXDSAZDAB42n2QPU4DMRCFn/MHJBJCIKhdUQDa/JQpEyn0CKWjSDbekGjXXnmdSDkBLRUHoOUYHIAbINFyCl6WSZMia+3o85uZ57EBnOMbCv/fJe6EFY7xKFzBETLhKvUX4Rr5XbiOFj6FG9R/hJu4VQPhFi7UGx1U7YS7m9JtywpnGAhXcIon4Sr1lXCN/CpcxxU+hBvUv4SbGONXuIVrZakM4WEwQWCcQWOKDeMCMRwskjIG1qE59GYSzExPN3oRO5s4GyjvV2KXAx5oOeeAKe09t2a+Sif+YMuB1JhuHgVLtimNLiJ0KBtfLJzV3ahzsP2e7ba02L9rgTXH7FENbNT8Pdsz0khsDK+QkjXyMrekElOPaGus8btnKdbzXgiJTrzL9IjHmjR1OvduaeLA4ufyjBx9tLmSPfeoHD5jWQh5v91OxCCKXYY/k9hxGQAAAHjaY2BigAAuMMnIgA5YwKJMjExciUVF+eW6KfnleQAZ0wQyAAAAAAH//wACAAEAAAAMAAAAFgAAAAIAAQADAAMAAQAEAAAAAgAAAAB42mNgYGBkAIKrS9Q5QPTNPer/YTQAQ+0HIAAA) format('woff');
font-weight: normal;
font-style: normal;
}
.tui-collapse-icon {
font-family: "tuiCollapse" !important;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.tui-icon-arrow:before {
content: "\e600";
}
.tui-icon-arrow {
font-size: 32rpx;
transform: rotate(0);
transform-origin: center center;
transition: all 0.3s;
position: absolute;
top: 50%;
margin-top: -8px;
right: 30rpx;
}
.tui-arrow-padding {
padding-right: 62rpx;
box-sizing: border-box;
}
.tui-icon-active {
transform: rotate(180deg);
transform-origin: center center;
}
.tui-header {
position: relative;
z-index: 2;
}
.tui-collapse-body_box{
transition: all 0.25s;
overflow: hidden;
}
.tui-collapse-body {
transition: all 0.25s;
overflow: hidden;
position: relative;
z-index: 1;
}
.tui-collapse-transform {
opacity: 0;
visibility: hidden;
-webkit-transform: translateY(-40%);
transform: translateY(-40%);
}
.tui-collapse-body_show {
opacity: 1;
visibility: visible;
-webkit-transform: translateY(0);
transform: translateY(0);
}
.tui-opacity {
opacity: 0.6;
}
</style>

View File

@ -1,343 +0,0 @@
<template>
<view class="tui-countdown-box">
<view class="tui-countdown-item" :style="{ background: backgroundColor, borderColor: borderColor, width: getWidth(d, width) + 'rpx', height: height + 'rpx' }" v-if="days">
<view class="tui-countdown-time" :class="[scale ? 'tui-countdown-scale' : '']" :style="{ fontSize: size + 'rpx', color: color, lineHeight: size + 'rpx' }">
{{ d }}
</view>
</view>
<view
class="tui-countdown-colon"
:class="{ 'tui-colon-pad': borderColor == 'transparent' }"
:style="{ lineHeight: colonSize + 'rpx', fontSize: colonSize + 'rpx', color: colonColor }"
v-if="days"
>
{{ isColon ? ':' : '天' }}
</view>
<view class="tui-countdown-item" :style="{ background: backgroundColor, borderColor: borderColor, width: getWidth(h, width) + 'rpx', height: height + 'rpx' }" v-if="hours">
<view class="tui-countdown-time" :class="[scale ? 'tui-countdown-scale' : '']" :style="{ fontSize: size + 'rpx', color: color, lineHeight: size + 'rpx' }">
{{ h }}
</view>
</view>
<view
class="tui-countdown-colon"
:class="{ 'tui-colon-pad': borderColor == 'transparent' }"
:style="{ lineHeight: colonSize + 'rpx', fontSize: colonSize + 'rpx', color: colonColor }"
v-if="hours"
>
{{ isColon ? ':' : '时' }}
</view>
<view
class="tui-countdown-item"
:style="{ background: backgroundColor, borderColor: borderColor, width: getWidth(i, width) + 'rpx', height: height + 'rpx' }"
v-if="minutes"
>
<view class="tui-countdown-time" :class="[scale ? 'tui-countdown-scale' : '']" :style="{ fontSize: size + 'rpx', color: color, lineHeight: size + 'rpx' }">
{{ i }}
</view>
</view>
<view
class="tui-countdown-colon"
:class="{ 'tui-colon-pad': borderColor == 'transparent' }"
:style="{ lineHeight: colonSize + 'rpx', fontSize: colonSize + 'rpx', color: colonColor }"
v-if="minutes"
>
{{ isColon ? ':' : '分' }}
</view>
<view
class="tui-countdown-item"
:style="{ background: backgroundColor, borderColor: borderColor, width: getWidth(s, width) + 'rpx', height: height + 'rpx' }"
v-if="seconds"
>
<view class="tui-countdown-time" :class="[scale ? 'tui-countdown-scale' : '']" :style="{ fontSize: size + 'rpx', color: color, lineHeight: size + 'rpx' }">
{{ s }}
</view>
</view>
<view
class="tui-countdown-colon"
:class="{ 'tui-colon-pad': borderColor == 'transparent' }"
:style="{ lineHeight: colonSize + 'rpx', fontSize: colonSize + 'rpx', color: colonColor }"
v-if="seconds && !isColon"
>
{{ unitEn ? 's' : '秒' }}
</view>
<view class="tui-countdown-colon" :style="{ lineHeight: colonSize + 'rpx', fontSize: colonSize + 'rpx', color: colonColor }" v-if="seconds && isMs && isColon">.</view>
<view
class="tui-countdown__ms"
:style="{
background: backgroundColor,
borderColor: borderColor,
fontSize: msSize + 'rpx',
color: msColor,
height: height + 'rpx',
width: msWidth > 0 ? msWidth + 'rpx' : 'auto'
}"
v-if="seconds && isMs"
>
<view :class="{ 'tui-ms__list': ani }">
<view class="tui-ms__item" :style="{ height: height + 'rpx' }" v-for="(item, index) in ms" :key="index">
<view :class="[scale ? 'tui-countdown-scale' : '']">{{item}}</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'tuiCountdown',
emits: ['end','time'],
props: {
//
width: {
type: Number,
default: 32
},
//
height: {
type: Number,
default: 32
},
//border
borderColor: {
type: String,
default: '#333'
},
//
backgroundColor: {
type: String,
default: '#fff'
},
//
size: {
type: Number,
default: 24
},
//
color: {
type: String,
default: '#333'
},
// 0.9
scale: {
type: Boolean,
default: false
},
//
colonSize: {
type: Number,
default: 28
},
//
colonColor: {
type: String,
default: '#333'
},
// ()
time: {
type: Number,
default: 0
},
//
days: {
type: Boolean,
default: false
},
//
hours: {
type: Boolean,
default: true
},
//
minutes: {
type: Boolean,
default: true
},
//
seconds: {
type: Boolean,
default: true
},
// seconds
unitEn: {
type: Boolean,
default: false
},
//,false
isColon: {
type: Boolean,
default: true
},
//
returnTime: {
type: Boolean,
default: false
},
//
isMs: {
type: Boolean,
default: false
},
msWidth: {
type: Number,
default: 32
},
msSize: {
type: Number,
default: 24
},
msColor: {
type: String,
default: '#333'
}
},
watch: {
time(val) {
this.clearTimer();
this.doLoop();
}
},
data() {
return {
countdown: null,
d: '0',
h: '00',
i: '00',
s: '00',
//91
ms: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
ani: false
};
},
created() {
this.clearTimer();
this.doLoop();
},
// #ifndef VUE3
beforeDestroy() {
this.clearTimer();
},
// #endif
// #ifdef VUE3
beforeUnmount(){
this.clearTimer();
},
// #endif
methods: {
getWidth: function(num, width) {
return num > 99 ? (width / 2) * num.toString().length : width;
},
clearTimer() {
clearInterval(this.countdown);
this.countdown = null;
},
endOfTime() {
this.ani = false;
this.clearTimer();
this.$emit('end', {});
},
doLoop: function() {
let seconds = this.time || 0;
this.ani = true;
this.countDown(seconds);
this.countdown = setInterval(() => {
seconds--;
if (seconds < 0) {
this.endOfTime();
return;
}
this.countDown(seconds);
if (this.returnTime) {
this.$emit('time', { seconds: seconds });
}
}, 1000);
},
countDown(seconds) {
let [day, hour, minute, second] = [0, 0, 0, 0];
if (seconds > 0) {
day = this.days ? Math.floor(seconds / (60 * 60 * 24)) : 0;
hour = this.hours ? Math.floor(seconds / (60 * 60)) - day * 24 : 0;
minute = this.minutes ? Math.floor(seconds / 60) - hour * 60 - day * 24 * 60 : 0;
second = Math.floor(seconds) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60;
} else {
this.endOfTime();
}
hour = hour < 10 ? '0' + hour : hour;
minute = minute < 10 ? '0' + minute : minute;
second = second < 10 ? '0' + second : second;
this.d = day;
this.h = hour;
this.i = minute;
this.s = second;
}
}
};
</script>
<style scoped>
.tui-countdown-box {
display: flex;
align-items: center;
}
.tui-countdown-box {
display: flex;
align-items: center;
}
.tui-countdown-item {
border: 1rpx solid;
display: flex;
align-items: center;
justify-content: center;
border-radius: 6rpx;
white-space: nowrap;
transform: translateZ(0);
}
.tui-countdown-time {
margin: 0;
padding: 0;
}
.tui-countdown-colon {
display: flex;
justify-content: center;
padding: 0 5rpx;
}
.tui-colon-pad {
padding: 0 !important;
}
.tui-countdown-scale {
transform: scale(0.9);
transform-origin: center center;
}
.tui-countdown__ms {
border: 1rpx solid;
overflow: hidden;
border-radius: 6rpx;
}
/*ms使用css3代替js频繁更新操作性能优化*/
.tui-ms__list {
animation: loop 1s steps(10) infinite;
}
@keyframes loop {
from {
transform: translateY(0);
}
to {
transform: translateY(-100%);
}
}
.tui-ms__item {
display: flex;
align-items: center;
justify-content: center;
}
</style>

View File

@ -1,103 +0,0 @@
<template>
<view class="tui-divider" :style="{ height: height + 'rpx' }">
<view class="tui-divider-line" :style="{ width: width, background: getBgColor(gradual, gradualColor, dividerColor) }"></view>
<view
class="tui-divider-text"
:style="{ color: color, fontSize: size + 'rpx', lineHeight: size + 'rpx', backgroundColor: backgroundColor, fontWeight: bold ? 'bold' : 'normal' }"
>
<slot></slot>
</view>
</view>
</template>
<script>
export default {
name: 'tuiDivider',
props: {
//divider
height: {
type: Number,
default: 100
},
//divider400rpx
width: {
type: String,
default: '100%'
},
//divider线
dividerColor: {
type: String,
default: '#e5e5e5'
},
//
color: {
type: String,
default: '#999'
},
// rpx
size: {
type: Number,
default: 24
},
bold: {
type: Boolean,
default: false
},
//
backgroundColor: {
type: String,
default: '#fafafa'
},
//线truedivideColor
gradual: {
type: Boolean,
default: false
},
//to right
gradualColor: {
type: Array,
default: function() {
return ['#eee', '#ccc'];
}
}
},
methods: {
getBgColor: function(gradual, gradualColor, dividerColor) {
let bgColor = dividerColor;
if (gradual) {
bgColor = 'linear-gradient(to right,' + gradualColor[0] + ',' + gradualColor[1] + ',' + gradualColor[1] + ',' + gradualColor[0] + ')';
}
return bgColor;
}
}
};
</script>
<style scoped>
.tui-divider {
width: 100%;
position: relative;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
overflow: hidden;
}
.tui-divider-line {
position: absolute;
height: 1rpx;
top: 50%;
left: 50%;
-webkit-transform: scaleY(0.5) translateX(-50%) translateZ(0);
transform: scaleY(0.5) translateX(-50%) translateZ(0);
}
.tui-divider-text {
position: relative;
text-align: center;
padding: 0 18rpx;
z-index: 1;
}
</style>

View File

@ -1,140 +0,0 @@
<template>
<!-- @touchmove.stop.prevent -->
<view>
<view v-if="mask" class="tui-drawer-mask" :class="{ 'tui-drawer-mask_show': visible }" :style="{ zIndex: maskZIndex }" @tap="handleMaskClick"></view>
<view
class="tui-drawer-container"
:class="[`tui-drawer-container_${mode}`, visible ? `tui-drawer-${mode}__show` : '']"
:style="{ zIndex: zIndex, backgroundColor: backgroundColor }"
>
<slot></slot>
</view>
</view>
</template>
<script>
/**
* 超过一屏时插槽使用scroll-view
**/
export default {
name: 'tuiDrawer',
emits: ['close'],
props: {
visible: {
type: Boolean,
default: false
},
mask: {
type: Boolean,
default: true
},
maskClosable: {
type: Boolean,
default: true
},
// left right bottom top
mode: {
type: String,
default: 'right'
},
//drawer z-index
zIndex: {
type: [Number, String],
default: 9999
},
//mask z-index
maskZIndex: {
type: [Number, String],
default: 9998
},
backgroundColor: {
type: String,
default: '#17172F'
}
},
methods: {
handleMaskClick() {
if (!this.maskClosable) {
return;
}
this.$emit('close', {});
}
}
};
</script>
<style scoped>
.tui-drawer-mask {
opacity: 0;
visibility: hidden;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
transition: all 0.3s ease-in-out;
}
.tui-drawer-mask_show {
display: block;
visibility: visible;
opacity: 1;
}
.tui-drawer-container {
position: fixed;
left: 80%;
height: 100.2%;
top: 0;
transform: translate3d(-50%, -50%, 0);
transform-origin: center;
transition: all 0.3s ease-in-out;
opacity: 0;
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
-ms-touch-action: pan-y cross-slide-y;
-ms-scroll-chaining: none;
-ms-scroll-limit: 0 50 0 50;
}
.tui-drawer-container_left {
left: 0;
top: 50%;
transform: translate3d(-100%, -50%, 0);
}
.tui-drawer-container_right {
right: 0;
top: 50%;
left: auto;
transform: translate3d(100%, -80%, 0);
}
.tui-drawer-container_bottom,
.tui-drawer-container_top {
width: 100%;
height: auto !important;
min-height: 20rpx;
left: 0;
right: 0;
transform-origin: center;
transition: all 0.3s ease-in-out;
}
.tui-drawer-container_bottom {
bottom: 0;
top: auto;
transform: translate3d(0, 100%, 0);
}
.tui-drawer-container_top {
transform: translate3d(0, -100%, 0);
}
.tui-drawer-left__show,
.tui-drawer-right__show {
opacity: 1;
transform: translate3d(0, -50%, 0);
}
.tui-drawer-top__show,
.tui-drawer-bottom__show {
opacity: 1;
transform: translate3d(0, 0, 0);
}
</style>

View File

@ -1,190 +0,0 @@
export default {
"about": "\ue772",
"about-fill": "\ue771",
"add": "\ue770",
"add-fill": "\ue76f",
"addmessage": "\ue76e",
"addressbook": "\ue76d",
"agree": "\ue76c",
"agree-fill": "\ue76b",
"alarm": "\ue76a",
"alarm-fill": "\ue769",
"alipay": "\ue768",
"android": "\ue767",
"applets": "\ue766",
"arrowdown": "\ue765",
"arrowleft": "\ue764",
"arrowright": "\ue763",
"arrowup": "\ue762",
"attestation": "\ue761",
"back": "\ue760",
"bag": "\ue75f",
"bag-fill": "\ue75e",
"balloon": "\ue75d",
"bankcard": "\ue75c",
"bankcard-fill": "\ue75b",
"bottom": "\ue75a",
"calendar": "\ue759",
"camera": "\ue758",
"camera-fill": "\ue757",
"camera-add": "\ue756",
"card": "\ue755",
"card-fill": "\ue754",
"cart": "\ue753",
"cart-fill": "\ue752",
"category": "\ue751",
"category-fill": "\ue750",
"check": "\ue74f",
"circle": "\ue74e",
"circle-fill": "\ue74d",
"circle-selected": "\ue74c",
"clock": "\ue74b",
"clock-fill": "\ue74a",
"close": "\ue749",
"close-fill": "\ue748",
"community": "\ue747",
"community-fill": "\ue746",
"computer": "\ue745",
"computer-fill": "\ue744",
"coupon": "\ue743",
"delete": "\ue742",
"deletekey": "\ue741",
"dingtalk": "\ue740",
"dissatisfied": "\ue73f",
"down": "\ue73e",
"download": "\ue73d",
"edit": "\ue73c",
"ellipsis": "\ue73b",
"enlarge": "\ue73a",
"evaluate": "\ue739",
"exchange": "\ue738",
"explain": "\ue737",
"explain-fill": "\ue736",
"explore": "\ue735",
"explore-fill": "\ue734",
"eye": "\ue733",
"feedback": "\ue732",
"fingerprint": "\ue730",
"friendadd": "\ue72f",
"friendadd-fill": "\ue72e",
"gps": "\ue72d",
"histogram": "\ue72c",
"home": "\ue72b",
"home-fill": "\ue72a",
"house": "\ue729",
"imface": "\ue728",
"imkeyboard": "\ue727",
"immore": "\ue726",
"imvoice": "\ue725",
"ios": "\ue724",
"kefu": "\ue723",
"label": "\ue722",
"label-fill": "\ue721",
"like": "\ue720",
"like-fill": "\ue71f",
"link": "\ue71e",
"listview": "\ue71d",
"loading": "\ue71c",
"location": "\ue71b",
"mail": "\ue71a",
"mail-fill": "\ue719",
"manage": "\ue718",
"manage-fill": "\ue717",
"member": "\ue716",
"member-fill": "\ue715",
"message": "\ue714",
"message-fill": "\ue713",
"mobile": "\ue712",
"moments": "\ue711",
"more": "\ue710",
"more-fill": "\ue70f",
"narrow": "\ue70e",
"news": "\ue70d",
"news-fill": "\ue70c",
"nodata": "\ue70b",
"notice": "\ue699",
"notice-fill": "\ue698",
"offline": "\ue697",
"offline-fill": "\ue696",
"oppose": "\ue695",
"oppose-fill": "\ue694",
"order": "\ue693",
"partake": "\ue692",
"people": "\ue691",
"people-fill": "\ue690",
"pic": "\ue68f",
"pic-fill": "\ue68e",
"picture": "\ue68d",
"pie": "\ue68c",
"plus": "\ue689",
"polygonal": "\ue688",
"position": "\ue686",
"pwd": "\ue685",
"qq": "\ue684",
"qrcode": "\ue682",
"redpacket": "\ue681",
"redpacket-fill": "\ue680",
"reduce": "\ue67f",
"refresh": "\ue67e",
"revoke": "\ue67d",
"satisfied": "\ue67c",
"screen": "\ue67b",
"search": "\ue67a",
"search-2": "\ue679",
"send": "\ue678",
"service": "\ue677",
"service-fill": "\ue676",
"setup": "\ue675",
"setup-fill": "\ue674",
"share": "\ue673",
"share-fill": "\ue672",
"shield": "\ue671",
"shop": "\ue670",
"shop-fill": "\ue66f",
"shut": "\ue66e",
"signin": "\ue66d",
"sina": "\ue66c",
"skin": "\ue66b",
"soso": "\ue669",
"square": "\ue668",
"square-fill": "\ue667",
"square-selected": "\ue666",
"star": "\ue665",
"star-fill": "\ue664",
"strategy": "\ue663",
"sweep": "\ue662",
"time": "\ue661",
"time-fill": "\ue660",
"todown": "\ue65f",
"toleft": "\ue65e",
"tool": "\ue65d",
"top": "\ue65c",
"toright": "\ue65b",
"towardsleft": "\ue65a",
"towardsright": "\ue659",
"towardsright-fill": "\ue658",
"transport": "\ue657",
"transport-fill": "\ue656",
"turningdown": "\ue654",
"turningleft": "\ue653",
"turningright": "\ue652",
"turningup": "\ue651",
"unreceive": "\ue650",
"seen": "\ue7d2",
"unseen": "\ue7d1",
"up": "\ue64e",
"upload": "\ue64c",
"video": "\ue64b",
"voice": "\ue649",
"voice-fill": "\ue648",
"voipphone": "\ue647",
"wallet": "\ue646",
"warning": "\ue645",
"wealth": "\ue644",
"wealth-fill": "\ue643",
"weather": "\ue642",
"wechat": "\ue641",
"wifi": "\ue640",
"play": "\ue7d5",
"suspend": "\ue7d4"
}

File diff suppressed because one or more lines are too long

View File

@ -1,78 +0,0 @@
<template>
<view class="tui-loading-init">
<view class="tui-loading-center"></view>
<view class="tui-loadmore-tips">{{text}}</view>
</view>
</template>
<script>
export default {
name: "tuiLoading",
props: {
text: {
type: String,
default: "正在加载..."
}
}
}
</script>
<style scoped>
.tui-loading-init {
min-width: 200rpx;
min-height: 200rpx;
max-width: 500rpx;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 9999;
font-size: 26rpx;
color: #fff;
background-color: rgba(0, 0, 0, 0.7);
border-radius: 10rpx;
}
.tui-loading-center {
width: 50rpx;
height: 50rpx;
border: 3px solid #fff;
border-radius: 50%;
margin: 0 6px;
display: inline-block;
vertical-align: middle;
clip-path: polygon(0% 0%, 100% 0%, 100% 40%, 0% 40%);
animation: rotate 1s linear infinite;
margin-bottom: 36rpx;
}
.tui-loadmore-tips {
text-align: center;
padding: 0 20rpx;
box-sizing: border-box;
}
@-webkit-keyframes rotate {
from {
transform: rotatez(0deg);
}
to {
transform: rotatez(360deg);
}
}
@keyframes rotate {
from {
transform: rotatez(0deg);
}
to {
transform: rotatez(360deg);
}
}
</style>

View File

@ -1,408 +0,0 @@
<template>
<view class="tui-modal__container" :class="[show ? 'tui-modal-show' : '']" :style="{zIndex:zIndex}" @touchmove.stop.prevent>
<view
class="tui-modal-box"
:style="{ width: width, padding: padding, borderRadius: radius, backgroundColor: backgroundColor,zIndex:zIndex+1 }"
:class="[fadeIn || show ? 'tui-modal-normal' : 'tui-modal-scale', show ? 'tui-modal-show' : '']"
>
<view v-if="!custom">
<view class="tui-modal-title" v-if="title">{{ title }}</view>
<view class="tui-modal-content" :class="[title ? '' : 'tui-mtop']" :style="{ color: color, fontSize: size + 'rpx' }">{{ content }}</view>
<view class="tui-modalBtn-box" :class="[button.length != 2 ? 'tui-flex-column' : '']">
<block v-for="(item, index) in button" :key="index">
<button
class="tui-modal-btn"
:class="[
'tui-' + (item.type || 'primary') + (item.plain ? '-outline' : ''),
button.length != 2 ? 'tui-btn-width' : '',
button.length > 2 ? 'tui-mbtm' : '',
shape == 'circle' ? 'tui-circle-btn' : ''
]"
:hover-class="'tui-' + (item.plain ? 'outline' : item.type || 'primary') + '-hover'"
:data-index="index"
@tap="handleClick"
>
{{ item.text || '确定' }}
</button>
</block>
</view>
</view>
<view v-else><slot></slot></view>
</view>
<view class="tui-modal-mask" :class="[show ? 'tui-mask-show' : '']" :style="{zIndex:maskZIndex}" @tap="handleClickCancel"></view>
</view>
</template>
<script>
export default {
name: 'tuiModal',
emits: ['click','cancel'],
props: {
//
show: {
type: Boolean,
default: false
},
width: {
type: String,
default: '84%'
},
backgroundColor: {
type: String,
default: '#fff'
},
padding: {
type: String,
default: '30rpx 0rpx 0rpx 0rpx'
},
radius: {
type: String,
default: '24rpx'
},
//
title: {
type: String,
default: ''
},
//
content: {
type: String,
default: ''
},
//
color: {
type: String,
default: '#999'
},
// rpx
size: {
type: Number,
default: 28
},
// circle, square
shape: {
type: String,
default: 'square'
},
button: {
type: Array,
default: function() {
return [
{
text: '取消',
type: 'red',
plain: true //
},
{
text: '确定',
type: 'red',
plain: false
}
];
}
},
//
maskClosable: {
type: Boolean,
default: true
},
//inputtrue
fadeIn: {
type: Boolean,
default: false
},
//
custom: {
type: Boolean,
default: false
},
//z-index
zIndex:{
type: Number,
default: 9997
},
//mask z-index
maskZIndex:{
type: Number,
default: 9990
}
},
data() {
return {};
},
methods: {
handleClick(e) {
if (!this.show) return;
const dataset = e.currentTarget.dataset;
this.$emit('click', {
index: Number(dataset.index)
});
},
handleClickCancel() {
if (!this.maskClosable) return;
this.$emit('cancel');
}
}
};
</script>
<style scoped>
.tui-modal__container {
width: 100%;
height: 100%;
position: fixed;
left: 0;
top: 0;
display: flex;
align-items: center;
justify-content: center;
visibility: hidden;
}
.tui-modal-box {
position: relative;
opacity: 0;
visibility: hidden;
box-sizing: border-box;
transition: all 0.3s ease-in-out;
}
.tui-modal-scale {
transform: scale(0);
}
.tui-modal-normal {
transform: scale(1);
}
.tui-modal-show {
opacity: 1;
visibility: visible;
}
.tui-modal-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.6);
transition: all 0.3s ease-in-out;
opacity: 0;
visibility: hidden;
}
.tui-mask-show {
visibility: visible;
opacity: 1;
}
.tui-modal-title {
text-align: center;
font-size: 34rpx;
color: #333;
padding-top: 20rpx;
font-weight: bold;
}
.tui-modal-content {
text-align: center;
color: #999;
font-size: 28rpx;
padding-top: 20rpx;
padding-bottom: 60rpx;
}
.tui-mtop {
margin-top: 30rpx;
}
.tui-mbtm {
margin-bottom: 30rpx;
}
.tui-modalBtn-box {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.tui-flex-column {
flex-direction: column;
}
.tui-modal-btn {
width: 46%;
height: 68rpx;
line-height: 68rpx;
position: relative;
border-radius: 10rpx;
font-size: 26rpx;
overflow: visible;
margin-left: 0;
margin-right: 0;
}
.tui-modal-btn::after {
content: ' ';
position: absolute;
width: 200%;
height: 200%;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
transform: scale(0.5, 0.5) translateZ(0);
left: 0;
top: 0;
border-radius: 20rpx;
z-index: 2;
}
.tui-btn-width {
width: 80% !important;
}
.tui-primary {
background: #5677fc;
color: #fff;
}
.tui-primary-hover {
background: #4a67d6;
color: #e5e5e5;
}
.tui-primary-outline {
color: #5677fc;
background: transparent;
}
.tui-primary-outline::after {
border: 1px solid #5677fc;
}
.tui-danger {
background: #ed3f14;
color: #fff;
}
.tui-danger-hover {
background: #d53912;
color: #e5e5e5;
}
.tui-danger-outline {
color: #ed3f14;
background: transparent;
}
.tui-danger-outline::after {
border: 1px solid #ed3f14;
}
.tui-red {
background: #e41f19;
color: #fff;
}
.tui-red-hover {
background: #c51a15;
color: #e5e5e5;
}
.tui-red-outline {
color: #e41f19;
background: transparent;
}
.tui-red-outline::after {
border: 1px solid #e41f19;
}
.tui-warning {
background: #ff7900;
color: #fff;
}
.tui-warning-hover {
background: #e56d00;
color: #e5e5e5;
}
.tui-warning-outline {
color: #ff7900;
background: transparent;
}
.tui-warning-outline::after {
border: 1px solid #ff7900;
}
.tui-green {
background: #19be6b;
color: #fff;
}
.tui-green-hover {
background: #16ab60;
color: #e5e5e5;
}
.tui-green-outline {
color: #19be6b;
background: transparent;
}
.tui-green-outline::after {
border: 1px solid #19be6b;
}
.tui-white {
background: #fff;
color: #333;
}
.tui-white-hover {
background: #f7f7f9;
color: #666;
}
.tui-white-outline {
color: #333;
background: transparent;
}
.tui-white-outline::after {
border: 1px solid #333;
}
.tui-gray {
background: #ededed;
color: #999;
}
.tui-gray-hover {
background: #d5d5d5;
color: #898989;
}
.tui-gray-outline {
color: #999;
background: transparent;
}
.tui-gray-outline::after {
border: 1px solid #999;
}
.tui-outline-hover {
opacity: 0.6;
}
.tui-circle-btn {
border-radius: 40rpx !important;
}
.tui-circle-btn::after {
border-radius: 80rpx !important;
}
</style>

View File

@ -1,118 +0,0 @@
<template>
<view class="tui-nodata-box" :class="[fixed?'tui-nodata-fixed':'']">
<image v-if="imgUrl" :src="imgUrl" class="tui-tips-icon" :style="{width:imgWidth+'rpx',height:imgHeight+'rpx'}"></image>
<view class="tui-tips-content">
<slot></slot>
</view>
<view class="tui-tips-btn" hover-class="tui-btn__hover" :hover-stay-time="150" :style="{width:btnWidth+'rpx',height:btnHeight+'rpx',background:backgroundColor,borderRadius:radius,fontSize:size+'rpx'}" v-if="btnText" @tap="handleClick">{{btnText}}</view>
</view>
</template>
<script>
export default {
name: "tuiNoData",
emits: ['click'],
props: {
//
fixed: {
type: Boolean,
default: true
},
//
imgUrl: {
type: String,
default: ""
},
//
imgWidth: {
type: Number,
default: 200
},
//
imgHeight:{
type: Number,
default: 200
},
//
btnWidth:{
type: Number,
default: 200
},
btnHeight:{
type: Number,
default: 60
},
//
btnText:{
type:String,
default: ""
},
//
backgroundColor:{
type:String,
default: "#EB0909"
},
size:{
type:Number,
default:28
},
radius:{
type:String,
default:'8rpx'
}
},
methods: {
handleClick(e) {
this.$emit('click', {});
}
}
}
</script>
<style scoped>
.tui-nodata-box {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.tui-nodata-fixed {
width: 90%;
position: fixed;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.tui-tips-icon {
display: block;
flex-shrink: 0;
width: 280rpx;
height: 280rpx;
margin-bottom: 40rpx;
}
.tui-tips-content {
text-align: center;
color: #666666;
font-size: 28rpx;
padding: 0 50rpx 28rpx 50rpx;
box-sizing: border-box;
word-break: break-all;
word-wrap: break-word;
}
.tui-tips-btn {
color: #fff;
margin: 0;
display: flex;
align-items: center;
justify-content: center;
}
.tui-btn__hover{
opacity: 0.5;
}
</style>

View File

@ -1,115 +0,0 @@
<template>
<view class="tui-nomore-class tui-loadmore-none">
<view :class="[isDot?'tui-nomore-dot':'tui-nomore']">
<view :style="{backgroundColor:backgroundColor}" :class="[isDot?'tui-dot-text':'tui-nomore-text']">{{isDot?dotText:text}}</view>
</view>
</view>
</template>
<script>
export default {
name: "tuiNomore",
props: {
//
backgroundColor: {
type: String,
default: "#F6F7FA"
},
// ""
isDot: {
type: Boolean,
default: false
},
//isDotfalse
text: {
type: String,
default: "到底啦~"
}
},
data() {
return {
dotText: "●"
};
}
}
</script>
<style scoped>
.tui-loadmore-none {
width: 50%;
margin: 1.5em auto;
line-height: 1.5em;
font-size: 24rpx;
display: flex;
justify-content: center;
}
.tui-nomore {
width: 100%;
height: 100%;
position: relative;
display: flex;
justify-content: center;
margin-top: 10rpx;
padding-bottom: 6rpx;
}
.tui-nomore::before {
content: ' ';
position: absolute;
border-bottom: 1rpx solid #e5e5e5;
-webkit-transform: scaleY(0.5);
transform: scaleY(0.5);
width: 100%;
top: 18rpx;
left: 0;
}
.tui-nomore-text {
color: #999;
font-size: 24rpx;
text-align: center;
padding: 0 18rpx;
height: 36rpx;
line-height: 36rpx;
position: relative;
z-index: 1;
}
.tui-nomore-dot {
position: relative;
text-align: center;
-webkit-display: flex;
display: flex;
-webkit-justify-content: center;
justify-content: center;
margin-top: 10rpx;
padding-bottom: 6rpx;
}
.tui-nomore-dot::before {
content: '';
position: absolute;
border-bottom: 1rpx solid #e5e5e5;
-webkit-transform: scaleY(0.5) translateX(-50%);
transform: scaleY(0.5) translateX(-50%);
width: 360rpx;
top: 18rpx;
left: 50%;
}
.tui-dot-text {
position: relative;
color: #e5e5e5;
font-size: 10px;
text-align: center;
width: 50rpx;
height: 36rpx;
line-height: 36rpx;
-webkit-transform: scale(0.8);
transform: scale(0.8);
-webkit-transform-origin: center center;
transform-origin: center center;
z-index: 1;
}
</style>

View File

@ -1,231 +0,0 @@
<template>
<view class="tui-numberbox">
<view class="tui-numbox-icon tui-icon-reduce " :class="[disabled || min >= inputValue ? 'tui-disabled' : '']"
@tap="reduce" :style="{ color: iconColor, fontSize: iconSize + 'rpx' }"></view>
<input type="number" v-model="inputValue" :disabled="disabled" @blur="blur" class="tui-num-input"
:style="{ color: color, fontSize: size + 'rpx', backgroundColor: backgroundColor, height: height + 'rpx', minHeight: height + 'rpx', width: width + 'rpx' }" />
<view class="tui-numbox-icon tui-icon-plus" :class="[disabled || inputValue >= max ? 'tui-disabled' : '']"
@tap="plus" :style="{ color: iconColor, fontSize: iconSize + 'rpx' }"></view>
</view>
</template>
<script>
export default {
name: 'tuiNumberbox',
emits: ['change'],
props: {
value: {
type: [Number, String],
default: 1
},
//
min: {
type: Number,
default: 1
},
//
max: {
type: Number,
default: 99
},
// 1 1.1 10...
step: {
type: Number,
default: 1
},
//
disabled: {
type: Boolean,
default: false
},
// rpx
iconSize: {
type: Number,
default: 26
},
iconColor: {
type: String,
default: '#666666'
},
//input
height: {
type: Number,
default: 42
},
//input
width: {
type: Number,
default: 80
},
size: {
type: Number,
default: 28
},
//input
backgroundColor: {
type: String,
default: '#F5F5F5'
},
//input
color: {
type: String,
default: '#333'
},
//使
index: {
type: [Number, String],
default: 0
},
//
custom: {
type: [Number, String],
default: 0
}
},
created() {
this.inputValue = +this.value;
},
data() {
return {
inputValue: 0
};
},
watch: {
value(val) {
this.inputValue = +val;
}
},
methods: {
getLen(val, step) {
let len = 0;
let lenVal = 0;
//
if (!Number.isInteger(step)) {
len = (step + '').split('.')[1].length
}
//
if (!Number.isInteger(val)) {
lenVal = (val + '').split('.')[1].length
}
return Math.max(len, lenVal);
},
getScale(val, step) {
let scale = 1;
let scaleVal = 1;
//
if (!Number.isInteger(step)) {
scale = Math.pow(10, (step + '').split('.')[1].length);
}
//
if (!Number.isInteger(val)) {
scaleVal = Math.pow(10, (val + '').split('.')[1].length);
}
return Math.max(scale, scaleVal);
},
calcNum: function(type) {
if (this.disabled || (this.inputValue == this.min && type === 'reduce') || (this.inputValue == this
.max && type === 'plus')) {
return;
}
const scale = this.getScale(this.inputValue, this.step);
let len = this.getLen(this.inputValue, this.step);
let num = Number(this.inputValue) * scale;
let step = this.step * scale;
if (type === 'reduce') {
num -= step;
} else if (type === 'plus') {
num += step;
}
let value = this.toFixed(num / scale, len);
if (value < this.min) {
value = this.min;
}else if (value > this.max) {
value = this.max;
}
this.handleChange(value, type);
},
plus: function() {
this.calcNum('plus');
},
reduce: function() {
this.calcNum('reduce');
},
blur: function(e) {
let value = e.detail.value;
if (value) {
if (~value.indexOf('.') && Number.isInteger(this.step) && Number.isInteger(Number(value))) {
value = value.split('.')[0];
}
value = Number(value);
if (value > this.max) {
value = this.max;
} else if (value < this.min) {
value = this.min;
}
} else {
value = this.min;
}
if ((value == this.value && value != this.inputValue) || !e.detail.value) {
this.inputValue = value;
}
this.handleChange(value, 'blur');
},
handleChange(value, type) {
if (this.disabled) return;
this.$emit('change', {
value: Number(value),
type: type,
index: this.index,
custom: this.custom
});
},
toFixed(num, s) {
let times = Math.pow(10, s)
let des = num * times + 0.5
des = parseInt(des, 10) / times
return des + ''
}
}
};
</script>
<style scoped>
@font-face {
font-family: 'numberbox';
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAASQAA0AAAAABtwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAEdAAAABoAAAAciBpnRUdERUYAAARUAAAAHgAAAB4AKQALT1MvMgAAAZwAAABDAAAAVjxzSINjbWFwAAAB9AAAAEYAAAFK5zLpOGdhc3AAAARMAAAACAAAAAj//wADZ2x5ZgAAAkgAAACHAAAAnIfIEjxoZWFkAAABMAAAAC8AAAA2FZWEOWhoZWEAAAFgAAAAHAAAACQH3gOFaG10eAAAAeAAAAARAAAAEgwAAAFsb2NhAAACPAAAAAwAAAAMADAATm1heHAAAAF8AAAAHwAAACABEAAobmFtZQAAAtAAAAFJAAACiCnmEVVwb3N0AAAEHAAAAC0AAABV/+8iFXjaY2BkYGAA4gVmC5Tj+W2+MnCzMIDATWsFOQT9v5GFgbkeyOVgYAKJAgDrogf+AHjaY2BkYGBu+N/AEMPCAAJAkpEBFbAAAEcKAm142mNgZGBgYGWQYQDRDAxMQMwFhAwM/8F8BgALpAE5AHjaY2BkYWCcwMDKwMDUyXSGgYGhH0IzvmYwYuQAijKwMjNgBQFprikMDs9Yn01kbvjfwBDD3MDQABRmBMkBAOXpDHEAeNpjYYAAFghmZGAAAACdAA4AAAB42mNgYGBmgGAZBkYGEHAB8hjBfBYGDSDNBqQZGZiesT6b+P8/AwOElvwnWQxVDwSMbAxwDiMTkGBiQAWMDMMeAABRZwszAAAAAAAAAAAAAAAwAE542iWKQQrCMBBF5xNpd0pQ7EIoTEnahSCTUNqdWz2A9TrieXKeXCc1qcPn/zfzh0BYv2pVH7oQgbvqdG5Yt/DTrNlPYz+wHvuuqhFSME4sFshTgKUsKfhH5lg8BSul3i5bS3mQdd0RIh2IjnvUrkXDd8zuhuFt86tY9fonIsSYgsXpB+cCGosAeNp9kD1OAzEQhZ/zByQSQiCoXVEA2vyUKRMp9Ailo0g23pBo1155nUg5AS0VB6DlGByAGyDRcgpelkmTImvt6PObmeexAZzjGwr/3yXuhBWO8ShcwREy4Sr1F+Ea+V24jhY+hRvUf4SbuFUD4RYu1BsdVO2Eu5vSbcsKZxgIV3CKJ+Eq9ZVwjfwqXMcVPoQb1L+EmxjjV7iFa2WpDOFhMEFgnEFjig3jAjEcLJIyBtahOfRmEsxMTzd6ETubOBso71dilwMeaDnngCntPbdmvkon/mDLgdSYbh4FS7YpjS4idCgbXyyc1d2oc7D9nu22tNi/a4E1x+xRDWzU/D3bM9JIbAyvkJI18jK3pBJTj2hrrPG7ZynW814IiU68y/SIx5o0dTr3bmniwOLn8owcfbS5kj33qBw+Y1kIeb/dTsQgil2GP5PYcRkAAAB42mNgYoAALjDJyIAOWMGiTIxMjMwiWZmJQJRXVQoigTgjMd9QGIsgAFDsEBsAAAAAAAAB//8AAgABAAAADAAAABYAAAACAAEAAwAEAAEABAAAAAIAAAAAeNpjYGBgZACCq0vUOUD0TWsFORgNADPBBE4AAA==) format('woff');
font-weight: normal;
font-style: normal;
}
.tui-numbox-icon {
font-family: 'numberbox' !important;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding: 10rpx;
}
.tui-icon-reduce:before {
content: '\e691';
}
.tui-icon-plus:before {
content: '\e605';
}
.tui-numberbox {
display: -webkit-inline-flex;
display: inline-flex;
align-items: center;
}
.tui-num-input {
text-align: center;
margin: 0 12rpx;
font-weight: 400;
}
.tui-disabled {
color: #ededed !important;
}
</style>

View File

@ -1,168 +0,0 @@
<template>
<view class="tui-rate-class tui-rate-box" @touchmove="touchMove">
<block v-for="(item, index) in quantity" :key="index">
<view class="tui-icon tui-relative"
:class="['tui-icon-collection' + (hollow && (current <= index || (disabled && current <= index + 1)) ? '' : '-fill')]"
:data-index="index" @tap="handleTap"
:style="{ fontSize: size + 'px', color: current > index + 1 || (!disabled && current > index) ? active : normal }">
<view class="tui-icon tui-icon-main tui-icon-collection-fill" v-if="disabled && current == index + 1"
:style="{ fontSize: size + 'px', color: active, width: percent + '%' }"></view>
</view>
</block>
</view>
</template>
<script>
export default {
name: 'tuiRate',
emits: ['change'],
props: {
//
quantity: {
type: Number,
default: 5
},
//
current: {
type: Number,
default: 0
},
//(01)
score: {
type: [Number, String],
default: 1
},
//
disabled: {
type: Boolean,
default: false
},
//
size: {
type: Number,
default: 20
},
//
normal: {
type: String,
default: '#b2b2b2'
},
//
active: {
type: String,
default: '#e41f19'
},
//
hollow: {
type: Boolean,
default: false
},
//
params: {
type: [Number, String],
default: 0
}
},
data() {
return {
pageX: 0,
percent: 0
};
},
created() {
this.percent = Number(this.score || 0) * 100;
},
watch: {
score(newVal, oldVal) {
this.percent = Number(newVal || 0) * 100;
}
},
methods: {
handleTap(e) {
if (this.disabled) {
return;
}
const index = e.currentTarget.dataset.index;
this.$emit('change', {
index: Number(index) + 1,
params: this.params
});
},
touchMove(e) {
if (this.disabled) {
return;
}
if (!e.changedTouches[0]) {
return;
}
const movePageX = e.changedTouches[0].pageX;
const distance = movePageX - this.pageX;
if (distance <= 0) {
return;
}
let index = Math.ceil(distance / this.size);
index = index > this.quantity ? this.quantity : index;
this.$emit('change', {
index: index,
params: this.params
});
}
},
mounted() {
const className = '.tui-rate-box';
let query = uni.createSelectorQuery().in(this);
query
.select(className)
.boundingClientRect(res => {
this.pageX = res.left || 0;
})
.exec();
}
};
</script>
<style scoped>
@font-face {
font-family: 'rateFont';
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAT4AA0AAAAAB4wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAE3AAAABoAAAAciBprQUdERUYAAAS8AAAAHgAAAB4AKQALT1MvMgAAAaAAAABDAAAAVj1YSN1jbWFwAAAB+AAAAEIAAAFCAA/qlmdhc3AAAAS0AAAACAAAAAj//wADZ2x5ZgAAAkgAAADwAAABZLMTdXtoZWFkAAABMAAAADAAAAA2FZKISmhoZWEAAAFgAAAAHQAAACQHYgOFaG10eAAAAeQAAAARAAAAEgx6AHpsb2NhAAACPAAAAAwAAAAMAEYAsm1heHAAAAGAAAAAHgAAACABEQBPbmFtZQAAAzgAAAFJAAACiCnmEVVwb3N0AAAEhAAAAC0AAABHLO3vkXjaY2BkYGAA4t2/VF7G89t8ZeBmYQCBm9ZKMnC6ikGMuYXpP5DLwcAEEgUAHPQJOXjaY2BkYGBu+N/AEMPCAALMLQyMDKiABQBQwgLwAAAAeNpjYGRgYGBlcGZgYgABEMkFhAwM/8F8BgAPigFhAAB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PXj17zdzwv4EhhrmBoQEozAiSAwD/YA2wAHjaY2GAABYIrmKoAgACggEBAAAAeNpjYGBgZoBgGQZGBhCwAfIYwXwWBgUgzQKEQP6z1///A8lX//9LSkJVMjCyMcCYDIxMQIKJARUwMgx7AAA/9QiLAAAAAAAAAAAAAABGALJ42mNgZKhiEGNuYfrPoMnAwGimps+ox6jPqKbEz8jHCMLyjHJAmk1czMie0cxInlHMDChrZs6cJyaosI+NlzmU34I/lImPdb+CoHgXCyujIosYtzTfKlYBtlWyuqwKjKwsjNvFTdlkGDnZ1srKrmXjZJRhMxVvZxFgA+rgYI9iYoriV1TYzybAwsDABHeLBIMT0DUg29VBTjEHucvcjtGeUVyOUZ6JaFcybefnZ5HuFdEX6ZVm5uMvniemxuXmzqUmNs+FeOfHCeiKzfPi4vKaJ6YrUCDOIiM8YYKwDIu4OMRbrOtkZdex4vMWACzGM5B42n2QPU4DMRCFn/MHJBJCIKhdUQDa/JQpEyn0CKWjSDbekGjXXnmdSDkBLRUHoOUYHIAbINFyCl6WSZMia+3o85uZ57EBnOMbCv/fJe6EFY7xKFzBETLhKvUX4Rr5XbiOFj6FG9R/hJu4VQPhFi7UGx1U7YS7m9JtywpnGAhXcIon4Sr1lXCN/CpcxxU+hBvUv4SbGONXuIVrZakM4WEwQWCcQWOKDeMCMRwskjIG1qE59GYSzExPN3oRO5s4GyjvV2KXAx5oOeeAKe09t2a+Sif+YMuB1JhuHgVLtimNLiJ0KBtfLJzV3ahzsP2e7ba02L9rgTXH7FENbNT8Pdsz0khsDK+QkjXyMrekElOPaGus8btnKdbzXgiJTrzL9IjHmjR1OvduaeLA4ufyjBx9tLmSPfeoHD5jWQh5v91OxCCKXYY/k9hxGQAAAHjaY2BigAAuMMnIgA5YwaJMjEyMzPzJ+Tk5qcklmfl58WmZOTlcCD4Ak9QKlAAAAAAAAAH//wACAAEAAAAMAAAAFgAAAAIAAQADAAQAAQAEAAAAAgAAAAB42mNgYGBkAIKrS9Q5QPRNayUZGA0AM8UETgAA) format('woff');
font-weight: normal;
font-style: normal;
}
.tui-icon {
font-family: 'rateFont' !important;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
display: block;
}
.tui-relative {
position: relative;
}
.tui-icon-main {
position: absolute;
height: 100%;
left: 0;
top: 0;
overflow: hidden;
}
.tui-icon-collection-fill:before {
content: '\e6ea';
}
.tui-icon-collection:before {
content: '\e6eb';
}
.tui-rate-box {
display: -webkit-inline-flex;
display: inline-flex;
align-items: center;
margin: 0;
padding: 0;
}
</style>

View File

@ -1,218 +0,0 @@
<template>
<view class="tui-slide-vcode" :style="{width:slideBarWidth+'px',height:slideBlockWidth+'px',backgroundColor:backgroundColor}">
<text class="tui-text-flashover" :style="{fontSize:size+'rpx',background:getBgColor}">拖动滑块验证</text>
<view class="tui-slide-glided" :style="{backgroundColor:activeBgColor}">
<text :style="{fontSize:size+'rpx',color:activeColor}" v-if="isPass">{{passText}}</text>
</view>
<view class="tui-slider-block" :style="{width:slideBlockWidth+'px',height:slideBlockWidth+'px',borderColor:isPass?activeBorderColor: borderColor}"
:change:prop="parse.slidereset" :prop="reset" :data-slideBarWidth="slideBarWidth" :data-slideBlockWidth="slideBlockWidth"
:data-errorRange="errorRange" :data-disabled="disabled" @touchstart="parse.touchstart" @touchmove="parse.touchmove"
@touchend="parse.touchend">
<text class="tui-slide-icon tui-icon-double_arrow" :style="{fontSize:iconSize+'rpx',color:arrowColor}" v-if="!isPass"></text>
<text class="tui-slide-icon tui-icon-check_mark" :style="{fontSize:iconSize+'rpx',color:checkColor}" v-if="isPass"></text>
</view>
</view>
</template>
<script src="./tui-slide-verify.wxs" module="parse" lang="wxs"></script>
<script>
export default {
name: "tuiSlideVerify",
emits: ['success'],
props: {
// px
slideBarWidth: {
type: [Number, String],
default: 300
},
// px =
slideBlockWidth: {
type: [Number, String],
default: 40
},
//border
borderColor: {
type: String,
default: '#E9E9E9'
},
//border
activeBorderColor: {
type: String,
default: '#19be6b'
},
// px
errorRange: {
type: [Number, String],
default: 2
},
//
resetSlide: {
type: Number,
default: 0
},
//
size: {
type: Number,
default: 30
},
//
color: {
type: String,
default: "#444"
},
//
activeColor: {
type: String,
default: "#fff"
},
// rpx
iconSize: {
type: Number,
default: 32
},
//
arrowColor: {
type: String,
default: "#cbcbcb"
},
checkColor: {
type: String,
default: "#19be6b"
},
//
backgroundColor: {
type: String,
default: "#E9E9E9"
},
//
activeBgColor: {
type: String,
default: "#19be6b"
},
//
passText: {
type: String,
default: '验证通过'
}
},
computed: {
getBgColor() {
return `-webkit-gradient(linear, left top, right top, color-stop(0, ${this.color}), color-stop(.4, ${this.color}), color-stop(.5, white), color-stop(.6, ${this.color}), color-stop(1, ${this.color}))`
}
},
watch: {
resetSlide(val) {
if (val > 0) {
this.slideReset()
}
}
},
data() {
return {
isPass: false,
disabled: false,
reset: 0
}
},
methods: {
success() {
//
this.isPass = true;
this.disabled = true;
this.$emit('success', {})
},
slideReset() {
this.isPass = false;
this.disabled = false;
this.reset++;
}
}
}
</script>
<style scoped>
@font-face {
font-family: 'tuiSlideVcode';
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAUYAA0AAAAAB1wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAE/AAAABoAAAAci6lfG0dERUYAAATcAAAAHgAAAB4AKQALT1MvMgAAAaAAAABCAAAAVjxuSCZjbWFwAAAB+AAAAEUAAAFK5n3pi2dhc3AAAATUAAAACAAAAAj//wADZ2x5ZgAAAkwAAAD8AAABJDQ/n7JoZWFkAAABMAAAADAAAAA2GSR8FGhoZWEAAAFgAAAAHQAAACQHygOFaG10eAAAAeQAAAARAAAAEgwUAD5sb2NhAAACQAAAAAwAAAAMAFQAkm1heHAAAAGAAAAAHgAAACABEQA6bmFtZQAAA0gAAAFJAAACiCnmEVVwb3N0AAAElAAAAD0AAABPYJEgVXjaY2BkYGAA4oqPSw3j+W2+MnCzMIDAbaY5nHBa5P905jfMeUAuBwMTSBQAHycKCHjaY2BkYGBu+N/AEMPCAALMbxgYGVABCwBYegNYAAAAeNpjYGRgYGBl0GNgYgABEMkFhAwM/8F8BgANfQFMAAB42mNgZGFgnMDAysDA1Ml0hoGBoR9CM75mMGLkAIoysDIzYAUBaa4pDA7PGJ6ZMDf8b2CIYW5gaAAKM4LkAN6ZDA8AAHjaY2GAABYItmMQAQABaABfAAAAeNpjYGBgZoBgGQZGBhBwAfIYwXwWBg0gzQakGRmYnjE8M/n/n4EBQksxS16AqgcCRjYGOIeRCUgwMaACRoZhDwDR6wnSAAAAAAAAAAAAAAAAVACSeNpFzjFOwzAYxfHv2Yodu4ozxHEq2qoSEilLQYoqh6lIIBaugMTC3hswMcPQhYmBjV4AMSFxAppjQDmDSzJle9L7DX9itNx/8i9+QY7mRPDn8ItTlDOcQLhCwcBVtWLCOl/D10v0L5vHnAGMx+EuLSctvQ8PBpMyxWU30/GxwUvMwXqDW6lkNIikllgnGM1MeAqPyWxkeNktczRGgrXUXOkeETGy+2f+x1c0oGnbKUg6KjzVJWUQh23TwlfTrhW+cpZRE3ZCIG8a5EKE3U34yM/sRttCb5hiuNLDjK+i8PO9Db8igmu2cOE1vNsWDTP9xhiuVXZARP+yvTqbeNp9kD1OAzEQhZ/zByQSQiCoXVEA2vyUKRMp9Ailo0g23pBo1155nUg5AS0VB6DlGByAGyDRcgpelkmTImvt6PObmeexAZzjGwr/3yXuhBWO8ShcwREy4Sr1F+Ea+V24jhY+hRvUf4SbuFUD4RYu1BsdVO2Eu5vSbcsKZxgIV3CKJ+Eq9ZVwjfwqXMcVPoQb1L+EmxjjV7iFa2WpDOFhMEFgnEFjig3jAjEcLJIyBtahOfRmEsxMTzd6ETubOBso71dilwMeaDnngCntPbdmvkon/mDLgdSYbh4FS7YpjS4idCgbXyyc1d2oc7D9nu22tNi/a4E1x+xRDWzU/D3bM9JIbAyvkJI18jK3pBJTj2hrrPG7ZynW814IiU68y/SIx5o0dTr3bmniwOLn8owcfbS5kj33qBw+Y1kIeb/dTsQgil2GP5PYcRkAAAB42mNgYoAALjDJyIAOWMGiTIxMjMyCOalpJbop+aVJOam6iUVF+eUCKaWZ6fmlJZmJeckZ+XnpugDvDw1eAAAAAAAAAf//AAIAAQAAAAwAAAAWAAAAAgABAAMABAABAAQAAAACAAAAAHjaY2BgYGQAgqtL1DlA9G2mOZwwGgA1wQSuAAA=) format('woff');
font-weight: normal;
font-style: normal;
font-display: swap;
}
.tui-slide-icon {
font-family: "tuiSlideVcode" !important;
font-size: 34rpx;
font-style: normal;
-webkit-font-smoothing: antialiased;
}
.tui-icon-check_mark:before {
content: "\e634";
}
.tui-icon-double_arrow:before {
content: "\e600";
}
.tui-slide-vcode {
background-color: #EAEEF1;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
.tui-slide-glided {
width: 0;
height: 100%;
background-color: #19BE6B;
position: absolute;
left: 0;
top: 0;
z-index: 1;
display: flex;
align-items: center;
justify-content: center;
}
.tui-slider-block {
position: absolute;
z-index: 2;
background-color: #FFFFFF;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
border: 1rpx solid;
box-sizing: border-box;
left: 0;
top: 0;
transition: border-color 0.08s;
}
.tui-text-flashover {
-webkit-background-clip: text !important;
-webkit-text-fill-color: transparent !important;
-webkit-animation: animate 1.8s infinite;
}
@-webkit-keyframes animate {
from {
background-position: -90rpx;
}
to {
background-position: 90rpx;
}
}
@keyframes animate {
from {
background-position: -90rpx;
}
to {
background-position: 90rpx;
}
}
</style>

View File

@ -1,73 +0,0 @@
var slideBarWidth = 200;
var slideBlockWidth = 32;
var errorRange = 2
var disabled = false
function bool(str) {
return str === 'true' || str == true ? true : false
}
function touchstart(e, ins) {
var state=e.instance.getState()
var touch = e.touches[0] || e.changedTouches[0]
var dataset = e.instance.getDataset()
state.startX = touch.pageX
slideBarWidth = +dataset.slidebarwidth
slideBlockWidth = +dataset.slideblockwidth
errorRange = +dataset.errorrange
disabled = bool(dataset.disabled)
}
function styleChange(left, ins) {
if (!ins) return;
ins.selectComponent('.tui-slider-block').setStyle({
transform: 'translate3d(' + left + 'px,0,0)'
})
ins.selectComponent('.tui-slide-glided').setStyle({
width: left + 'px'
})
}
function touchmove(e, ins) {
if (disabled) return;
var state=e.instance.getState()
var touch = e.touches[0] || e.changedTouches[0]
var pageX = touch.pageX;
var left = pageX - state.startX + (state.lastLeft || 0);
left = left < 0 ? 0 : left;
var width = slideBarWidth - slideBlockWidth;
left = left >= width ? width : left;
state.startX = pageX
state.lastLeft = left
styleChange(left, ins)
}
function touchend(e, ins) {
if (disabled) return;
var state=e.instance.getState()
let left = slideBarWidth - slideBlockWidth
if (left - state.lastLeft <= errorRange) {
styleChange(left, ins)
ins.callMethod('success')
} else {
state.startX = 0;
state.lastLeft = 0;
styleChange(0, ins)
}
}
function slidereset(reset, oldreset, owner, ins) {
var state=ins.getState()
if (reset > 0) {
state.startX = 0;
state.lastLeft = 0;
styleChange(0, owner)
}
}
module.exports = {
touchstart: touchstart,
touchmove: touchmove,
touchend: touchend,
slidereset: slidereset
}

View File

@ -1,253 +0,0 @@
<template>
<view class="tui-steps-box" :class="{ 'tui-steps-column': direction === 'column' }">
<view class="tui-step-item" :style="{ width: direction === 'column' ? '100%' : spacing }"
:class="[direction === 'row' ? 'tui-step-horizontal' : 'tui-step-vertical']" v-for="(item, index) in items"
:key="index" @tap.stop="handleClick(index)">
<view class="tui-step-item-ico" :class="[direction === 'column' ? 'tui-step-column_ico' : 'tui-step-row_ico']" :style="{ width: direction === 'column' ? '36rpx' : '100%' }">
<view v-if="!item.name && !item.icon" class="tui-step-ico"
:style="{
width: type == 2 || activeSteps === index ? '36rpx' : '16rpx',
height: type == 2 || activeSteps === index ? '36rpx' : '16rpx',
backgroundColor: index <= activeSteps ? activeColor : type == 2 ? '#fff' : deactiveColor,
borderColor: index <= activeSteps ? activeColor : deactiveColor
}">
<text v-if="activeSteps !== index"
:style="{ color: index <= activeSteps ? '#fff' : '' }">{{ type == 1 ? '' : index + 1 }}</text>
<tui-icon name="check" :size="16" color="#fff" v-if="activeSteps === index"></tui-icon>
</view>
<view class="tui-step-custom" :style="{ backgroundColor: backgroundColor }"
v-if="item.name || item.icon">
<tui-icon :name="item.name" :size="20" :color="index <= activeSteps ? activeColor : deactiveColor"
v-if="item.name"></tui-icon>
<image :src="index <= activeSteps ? item.activeIcon : item.icon" class="tui-step-img"
mode="widthFix" v-if="!item.name"></image>
</view>
<view class="tui-step-line"
:class="['tui-step-' + direction + '_line', direction == 'column' && (item.name || item.icon) ? 'tui-custom-left' : '']"
:style="{
borderColor: index <= activeSteps - 1 ? activeColor : deactiveColor,
borderRightStyle: direction == 'column' ? lineStyle : '',
borderTopStyle: direction == 'column' ? '' : lineStyle
}" v-if="index != items.length - 1"></view>
</view>
<view class="tui-step-item-main" :class="['tui-step-' + direction + '_item_main']">
<view class="tui-step-item-title" :style="{
color: index <= activeSteps ? activeColor : deactiveColor,
fontSize: titleSize + 'rpx',
lineHeight: titleSize + 'rpx',
fontWeight: bold ? 'bold' : 'normal'
}">
{{ item.title }}
</view>
<view class="tui-step-item-content"
:style="{ color: index <= activeSteps ? activeColor : deactiveColor, fontSize: descSize + 'rpx' }">
{{ item.desc }}</view>
</view>
</view>
</view>
</template>
<script>
//
export default {
name: 'tuiSteps',
emits: ['click'],
props: {
// 1- 2-
type: {
type: Number,
default: 1
},
spacing: {
type: String,
default: '160rpx'
},
// row column
direction: {
type: String,
default: 'row'
},
//
activeColor: {
type: String,
default: '#5677fc'
},
//
deactiveColor: {
type: String,
default: '#999999'
},
//title
titleSize: {
type: Number,
default: 28
},
//title
bold: {
type: Boolean,
default: false
},
//desc
descSize: {
type: Number,
default: 24
},
//
activeSteps: {
type: Number,
default: -1
},
//线 border线
lineStyle: {
type: String,
default: 'solid'
},
/**
* [{
title: "标题",
desc: "描述",
name:"字体图标 thorui icon内",
icon:"图片图标",
activeIcon:"已完成步骤显示图片图标"
}]
* */
items: {
type: Array,
default () {
return [];
}
},
//item
backgroundColor: {
type: String,
default: '#fff'
}
},
data() {
return {};
},
methods: {
handleClick(index) {
this.$emit('click', {
index: index
});
}
}
};
</script>
<style scoped>
.tui-steps-box {
width: 100%;
display: flex;
justify-content: center;
}
.tui-steps-column {
flex-direction: column;
}
.tui-step-ico {
border-radius: 50%;
position: relative;
z-index: 3;
margin: 0 auto;
border-width: 1rpx;
border-style: solid;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.tui-step-row_ico {
align-items: center;
}
.tui-step-column_ico {
align-items: flex-start;
}
.tui-step-line {
position: absolute;
left: 50%;
top: 20rpx;
width: 100%;
height: 0rpx;
border-top-width: 1rpx;
z-index: 2;
transform: translateY(-50%) translateZ(0);
}
.tui-step-row_item_main {
text-align: center;
}
.tui-step-item {
font-size: 24rpx;
position: relative;
box-sizing: border-box;
}
.tui-step-item-ico {
height: 36rpx;
display: flex;
justify-content: center;
}
.tui-step-custom {
display: flex;
align-items: center;
justify-content: center;
width: 48rpx;
height: 40rpx;
position: relative;
z-index: 4;
margin: 0 auto;
}
.tui-step-img {
width: 40rpx;
height: 40rpx;
}
.tui-step-item-main {
margin-top: 16rpx;
clear: both;
}
.tui-step-item-title {
word-break: break-all;
}
.tui-step-item-content {
margin-top: 8rpx;
word-break: break-all;
}
.tui-step-vertical {
width: 100%;
display: flex;
padding-bottom: 60rpx;
}
.tui-step-column_item_main {
margin-top: 0;
padding-left: 20rpx;
}
.tui-step-column_line {
position: absolute;
height: 100%;
top: 0;
left: 18rpx;
margin: 0;
width: 0rpx;
border-right-width: 1rpx;
transform: none !important;
}
.tui-custom-left {
left: 20rpx !important;
}
</style>

View File

@ -1,125 +0,0 @@
<template>
<view class="tui-sticky-class" :change:prop="parse.stickyChange" :prop="scrollTop" :data-top="top" :data-height="height"
:data-stickytop="stickyTop" :data-container="container" :data-isNativeHeader="isNativeHeader" :data-index="index">
<!--sticky 容器-->
<view class="tui-sticky-seat" :style="{ height: stickyHeight, backgroundColor: backgroundColor }"></view>
<view class="tui-sticky-bar">
<slot name="header"></slot>
</view>
<!--sticky 容器-->
<!--内容-->
<slot name="content"></slot>
</view>
</template>
<script src="./tui-sticky.wxs" module="parse" lang="wxs"></script>
<script>
export default {
name: 'tuiStickyWxs',
emits: ['prop', 'change'],
props: {
scrollTop: {
type: [Number, String],
value: 0
},
//px
stickyTop: {
type: [Number, String],
// #ifndef H5
default: 0,
// #endif
// #ifdef H5
default: 44
// #endif
},
//content
container: {
type: Boolean,
default: false
},
//header
isNativeHeader: {
type: Boolean,
default: true
},
// rpx
stickyHeight: {
type: String,
default: 'auto'
},
//
backgroundColor: {
type: String,
default: 'transparent'
},
//[使,0]
recalc: {
type: Number,
default: 0
},
//
index: {
type: [Number, String],
default: 0
}
},
watch: {
recalc(newValue, oldValue) {
this.updateScrollChange(() => {
//prop scrollTop(+0.1),change
this.$emit("prop",{})
});
}
},
mounted() {
setTimeout(() => {
this.updateScrollChange();
}, 20);
},
data() {
return {
timer: null,
top: 0,
height: 0
};
},
methods: {
updateScrollChange(callback) {
if (this.timer) {
clearTimeout(this.timer);
this.timer = null;
}
this.timer = setTimeout(() => {
const className = '.tui-sticky-class';
const query = uni.createSelectorQuery().in(this);
query
.select(className)
.boundingClientRect(res => {
if (res) {
this.top = res.top + (this.scrollTop || 0);
this.height = res.height;
callback && callback();
this.$emit('change', {
index: Number(this.index),
top: this.top
});
}
})
.exec();
}, 0);
}
}
};
</script>
<style scoped>
.tui-sticky-fixed {
width: 100%;
position: fixed;
left: 0;
z-index: 998;
}
.tui-sticky-seat {
display: none;
}
</style>

View File

@ -1,44 +0,0 @@
var stickyChange = function(scrollTop, oldScrollTop, ownerInstance, ins) {
if (!oldScrollTop && scrollTop === 0) return false;
var dataset = ins.getDataset()
var top = +dataset.top;
var height = +dataset.height;
var stickyTop = +dataset.stickytop;
var isNativeHeader = dataset.isnativeheader;
var isFixed = false;
var distance = stickyTop
// #ifdef H5
if (isNativeHeader) {
distance = distance - 44
distance = distance < 0 ? 0 : distance
}
// #endif
if (dataset.container) {
isFixed = (scrollTop + distance >= top && scrollTop + distance < top + height) ? true : false
} else {
isFixed = scrollTop + distance >= top ? true : false
}
if (isFixed) {
ownerInstance.selectComponent('.tui-sticky-bar').setStyle({
"top": stickyTop + 'px'
}).addClass('tui-sticky-fixed')
ownerInstance.selectComponent('.tui-sticky-seat').setStyle({
"display": 'block'
})
} else {
ownerInstance.selectComponent('.tui-sticky-bar').setStyle({
"top": 'auto'
}).removeClass('tui-sticky-fixed')
ownerInstance.selectComponent('.tui-sticky-seat').setStyle({
"display": 'none'
})
}
ownerInstance.triggerEvent("sticky", [{
isFixed: isFixed,
index: parseInt(dataset.index)
}])
}
module.exports = {
stickyChange: stickyChange
}

View File

@ -1,155 +0,0 @@
<template>
<view class="tui-sticky-class">
<!--sticky 容器-->
<view :style="{height: stickyHeight,backgroundColor:backgroundColor}" v-if="isFixed"></view>
<view :class="{'tui-sticky-fixed':isFixed}" :style="{top:isFixed?stickyTop+'px':'auto'}">
<slot name="header"></slot>
</view>
<!--sticky 容器-->
<!--内容-->
<slot name="content"></slot>
</view>
</template>
<script>
export default {
name: "tuiSticky",
emits: ['sticky', 'change'],
props: {
scrollTop: {
type: Number
},
//px
stickyTop: {
type: [Number, String]
// #ifndef H5
,
default: 0
// #endif
// #ifdef H5
,
default: 44
// #endif
},
//content
container: {
type: Boolean,
default: false
},
//header
isNativeHeader: {
type: Boolean,
default: true
},
// rpx
stickyHeight: {
type: String,
default: "auto"
},
//
backgroundColor: {
type: String,
default: "transparent"
},
//[使,0]
recalc: {
type: Number,
default: 0
},
//
index: {
type: [Number, String],
default: 0
}
},
watch: {
scrollTop(newValue, oldValue) {
if (this.initialize != 0) {
this.updateScrollChange(() => {
this.updateStickyChange();
this.initialize = 0
});
} else {
this.updateStickyChange();
}
},
recalc(newValue, oldValue) {
this.updateScrollChange(() => {
this.updateStickyChange();
this.initialize = 0;
});
}
},
created() {
this.initialize = this.recalc
},
mounted() {
setTimeout(() => {
this.updateScrollChange();
}, 20)
},
data() {
return {
timer: null,
top: 0,
height: 0,
isFixed: false,
initialize: 0 //
};
},
methods: {
updateStickyChange() {
const top = this.top;
const height = this.height;
const scrollTop = this.scrollTop
let stickyTop = this.stickyTop
// #ifdef H5
if (this.isNativeHeader) {
stickyTop = stickyTop - 44
stickyTop = stickyTop < 0 ? 0 : stickyTop
}
// #endif
if (this.container) {
this.isFixed = (scrollTop + stickyTop >= top && scrollTop + stickyTop < top + height) ? true : false
} else {
this.isFixed = scrollTop + stickyTop >= top ? true : false
}
//
this.$emit("sticky", {
isFixed: this.isFixed,
index: this.index
})
},
updateScrollChange(callback) {
if (this.timer) {
clearTimeout(this.timer)
this.timer = null
}
this.timer = setTimeout(() => {
const className = '.tui-sticky-class';
const query = uni.createSelectorQuery().in(this);
query.select(className).boundingClientRect((res) => {
if (res) {
this.top = res.top + (this.scrollTop || 0);
this.height = res.height;
callback && callback();
this.$emit("change", {
index: Number(this.index),
top: this.top
})
}
}).exec()
}, 0)
}
}
}
</script>
<style scoped>
.tui-sticky-fixed {
width: 100%;
position: fixed;
left: 0;
z-index: 888;
}
</style>

View File

@ -1,360 +0,0 @@
<template>
<view class="tui-tag" :hover-class="hover ? 'tui-tag-opcity' : ''" :hover-stay-time="150" :class="[originLeft ? 'tui-origin-left' : '', originRight ? 'tui-origin-right' : '', getClassName(shape, plain), getTypeClass(type, plain)]"
:style="{ transform: `scale(${scaleMultiple})`, padding: padding, margin: margin, fontSize: size, lineHeight: size }"
@tap="handleClick">
<slot></slot>
</view>
</template>
<script>
export default {
name: 'tuiTag',
emits: ['click'],
props: {
type: {
type: String,
default: 'primary'
},
//padding
padding: {
type: String,
default: '16rpx 26rpx'
},
margin: {
type: String,
default: '0'
},
// rpx
size: {
type: String,
default: '28rpx'
},
// circle, squarecircleLeftcircleRight
shape: {
type: String,
default: 'square'
},
//
plain: {
type: Boolean,
default: false
},
//
hover: {
type: Boolean,
default: false
},
//
scaleMultiple: {
type: Number,
default: 1
},
originLeft: {
type: Boolean,
default: false
},
originRight: {
type: Boolean,
default: false
},
index: {
type: Number,
default: 0
}
},
methods: {
handleClick() {
this.$emit('click', {
index: this.index
});
},
getTypeClass: function(type, plain) {
return plain ? 'tui-' + type + '-outline' : 'tui-' + type;
},
getClassName: function(shape, plain) {
//circle, squarecircleLeftcircleRight
var className = plain ? 'tui-tag-outline ' : '';
if (shape != 'square') {
if (shape == 'circle') {
className = className + (plain ? 'tui-tag-outline-fillet' : 'tui-tag-fillet');
} else if (shape == 'circleLeft') {
className = className + 'tui-tag-fillet-left';
} else if (shape == 'circleRight') {
className = className + 'tui-tag-fillet-right';
}
}
return className;
}
}
};
</script>
<style scoped>
/* color start*/
.tui-primary {
background: #5677fc !important;
color: #fff;
}
.tui-light-primary {
background: #5c8dff !important;
color: #fff;
}
.tui-dark-primary {
background: #4a67d6 !important;
color: #fff;
}
.tui-dLight-primary {
background: #4e77d9 !important;
color: #fff;
}
.tui-danger {
background: #ed3f14 !important;
color: #fff;
}
.tui-red {
background: #ff201f !important;
color: #fff;
}
.tui-warning {
background: #ff7900 !important;
color: #fff;
}
.tui-green {
background: #19be6b !important;
color: #fff;
}
.tui-high-green {
background: #52dcae !important;
color: #52dcae;
}
.tui-black {
background: #000 !important;
color: #fff;
}
.tui-white {
background: #fff !important;
color: #333 !important;
}
.tui-translucent {
background: rgba(0, 0, 0, 0.7);
}
.tui-light-black {
background: #333 !important;
}
.tui-gray {
background: #ededed !important;
}
.tui-phcolor-gray {
background: #ccc !important;
}
.tui-divider-gray {
background: #eaeef1 !important;
}
.tui-btn-gray {
background: #ededed !important;
color: #999 !important;
}
.tui-hover-gray {
background: #f7f7f9 !important;
}
.tui-bg-gray {
background: #fafafa !important;
}
.tui-light-blue {
background: #ecf6fd;
color: #4dabeb !important;
}
.tui-light-brownish {
background: #fcebef;
color: #8a5966 !important;
}
.tui-light-orange {
background: #fef5eb;
color: #faa851 !important;
}
.tui-light-green {
background: #e8f6e8;
color: #44cf85 !important;
}
.tui-primary-outline::after {
border: 1px solid #5677fc !important;
}
.tui-primary-outline {
color: #5677fc !important;
background: none;
}
.tui-danger-outline {
color: #ed3f14 !important;
background: none;
}
.tui-danger-outline::after {
border: 1px solid #ed3f14 !important;
}
.tui-red-outline {
color: #ff201f !important;
background: none;
}
.tui-red-outline::after {
border: 1px solid #ff201f !important;
}
.tui-warning-outline {
color: #ff7900 !important;
background: none;
}
.tui-warning-outline::after {
border: 1px solid #ff7900 !important;
}
.tui-green-outline {
color: #44cf85 !important;
background: none;
}
.tui-green-outline::after {
border: 1px solid #44cf85 !important;
}
.tui-high-green-outline {
color: #52dcae !important;
background: none;
}
.tui-high-green-outline::after {
border: 1px solid #52dcae !important;
}
.tui-gray-outline {
color: #999 !important;
background: none;
}
.tui-gray-outline::after {
border: 1px solid #ccc !important;
}
.tui-black-outline {
color: #333 !important;
background: none;
}
.tui-black-outline::after {
border: 1px solid #333 !important;
}
.tui-white-outline {
color: #fff !important;
background: none;
}
.tui-white-outline::after {
border: 1px solid #fff !important;
}
/* color end*/
/* tag start*/
.tui-tag {
padding: 16rpx 26rpx;
font-size: 28rpx;
border-radius: 6rpx;
/* display: inline-block;
vertical-align: middle; */
line-height: 28rpx;
}
.tui-tag-small {
padding: 10rpx 16rpx;
font-size: 24rpx;
border-radius: 6rpx;
/* display: inline-block;
vertical-align: middle; */
line-height: 24rpx;
}
.tui-tag-outline {
position: relative;
background: none;
color: #5677fc;
}
.tui-tag-outline::after {
content: "";
position: absolute;
width: 200%;
height: 200%;
-webkit-transform-origin: 0 0;
transform-origin: 0 0;
-webkit-transform: scale(0.5, 0.5);
transform: scale(0.5, 0.5);
-webkit-box-sizing: border-box;
box-sizing: border-box;
left: 0;
top: 0;
border-radius: 80rpx;
border: 1px solid #5677fc;
}
.tui-tag-fillet {
border-radius: 50rpx;
}
.tui-white.tui-tag-fillet::after {
border-radius: 80rpx;
}
.tui-tag-outline-fillet::after {
border-radius: 80rpx;
}
.tui-tag-fillet-left {
border-radius: 50rpx 0 0 50rpx;
}
.tui-tag-fillet-right {
border-radius: 0 50rpx 50rpx 0;
}
.tui-tag-fillet-left.tui-tag-outline::after {
border-radius: 100rpx 0 0 100rpx;
}
.tui-tag-fillet-right.tui-tag-outline::after {
border-radius: 0 100rpx 100rpx 0;
}
/* tag end*/
</style>

View File

@ -1,129 +0,0 @@
<template>
<block v-if="position == 'top'">
<view class="tui-tips-class tui-toptips" :style="{backgroundColor:backgroundColor,color:color,fontSize:size+'rpx'}" :class="[show ? 'tui-top-show' : '']">{{ msg }}</view>
</block>
<block v-else>
<view class="tui-tips-class tui-toast" :class="[position == 'center' ? 'tui-centertips' : 'tui-bottomtips', show ? 'tui-toast-show' : '']">
<view class="tui-tips-content" :style="{backgroundColor:backgroundColor,color:color,fontSize:size+'rpx'}">{{ msg }}</view>
</view>
</block>
</template>
<script>
export default {
name: 'tuiTips',
props: {
//top bottom center
position: {
type: String,
default: 'top'
},
backgroundColor: {
type: String,
default: 'rgba(0, 0, 0, 0.7)'
},
color: {
type: String,
default: '#fff'
},
size: {
type: Number,
default: 30
}
},
data() {
return {
timer: null,
show: false,
msg: '无法连接到服务器~'
};
},
methods: {
showTips: function(options) {
const {duration = 2000 } = options;
clearTimeout(this.timer);
this.show = true;
// this.duration = duration < 2000 ? 2000 : duration;
this.msg = options.msg;
this.timer = setTimeout(() => {
this.show = false;
clearTimeout(this.timer);
this.timer = null;
}, duration);
}
}
};
</script>
<style scoped>
/*顶部消息提醒 start*/
.tui-toptips {
width: 100%;
padding: 18rpx 30rpx;
box-sizing: border-box;
position: fixed;
z-index: 9999;
left: 0;
top: 0;
display: flex;
align-items: center;
justify-content: center;
word-break: break-all;
opacity: 0;
transform: translateZ(0) translateY(-100%);
transition: all 0.3s ease-in-out;
}
.tui-top-show {
transform: translateZ(0) translateY(0);
opacity: 1;
}
/*顶部消息提醒 end*/
/*toast消息提醒 start*/
/*
1fixed 元素宽度无法自适应所以增加了子元素
2fixed display冲突导致动画效果消失暂时使用visibility替代
*/
.tui-toast {
width: 80%;
box-sizing: border-box;
color: #fff;
font-size: 28rpx;
position: fixed;
visibility: hidden;
opacity: 0;
left: 50%;
transition: all 0.3s ease-in-out;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
}
.tui-toast-show {
visibility: visible;
opacity: 1;
}
.tui-tips-content {
word-wrap: break-word;
word-break: break-all;
border-radius: 8rpx;
padding: 18rpx 30rpx;
}
.tui-bottomtips {
bottom: 120rpx;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
}
.tui-centertips {
top: 50%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
</style>

View File

@ -1,121 +0,0 @@
<template>
<view class="tui-toast" :class="[visible?'tui-toast-show':'',content?'tui-toast-padding':'',icon?'':'tui-unicon-padding']" :style="{width:getWidth(icon,content),zIndex:zIndex}">
<image :src="imgUrl" class="tui-toast-img" v-if="icon"></image>
<view class="tui-toast-text" :class="[icon?'':'tui-unicon']">{{title}}</view>
<view class="tui-toast-text tui-content-ptop" v-if="content && icon">{{content}}</view>
</view>
</template>
<script>
export default {
name: "tuiToast",
props: {
zIndex:{
type:Number,
default:99999
}
},
data() {
return {
timer: null,
//
visible: false,
//
title: "操作成功",
//
content: "",
//icon
icon:false,
imgUrl:""
};
},
methods: {
show: function(options) {
let {
duration = 2000,
icon=false
} = options;
clearTimeout(this.timer);
this.visible = true;
this.title = options.title || "";
this.content = options.content || "";
this.icon=icon;
if(icon && options.imgUrl){
this.imgUrl=options.imgUrl
}
this.timer = setTimeout(() => {
this.visible = false;
clearTimeout(this.timer);
this.timer = null;
}, duration);
},
getWidth(icon,content){
let width="auto";
if(icon){
width=content?'420rpx':'360rpx'
}
return width
}
}
}
</script>
<style scoped>
.tui-toast {
background-color: rgba(0, 0, 0, 0.75);
border-radius: 10rpx;
position: fixed;
visibility: hidden;
opacity: 0;
left: 50%;
top: 48%;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
transition: 0.3s ease-in-out;
transition-property:opacity,visibility;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
padding: 60rpx 20rpx 54rpx 20rpx;
box-sizing: border-box;
}
.tui-toast-padding {
padding-top: 50rpx !important;
padding-bottom: 50rpx !important;
}
.tui-unicon-padding {
padding: 24rpx 40rpx !important;
word-break: break-all;
}
.tui-toast-show {
visibility: visible;
opacity: 1;
}
.tui-toast-img {
width: 120rpx;
height: 120rpx;
display: block;
margin-bottom: 28rpx;
}
.tui-toast-text {
font-size: 30rpx;
line-height: 30rpx;
font-weight: 400;
color: #fff;
text-align: center;
}
.tui-unicon{
line-height: 40rpx !important;
font-size: 32rpx !important;
}
.tui-content-ptop {
padding-top: 10rpx;
font-size: 26rpx !important;
}
</style>

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 www.uviewui.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,66 @@
<p align="center">
<img alt="logo" src="https://uviewui.com/common/logo.png" width="120" height="120" style="margin-bottom: 10px;">
</p>
<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uView 2.0</h3>
<h3 align="center">多平台快速开发的UI框架</h3>
[![stars](https://img.shields.io/github/stars/umicro/uView2.0?style=flat-square&logo=GitHub)](https://github.com/umicro/uView2.0)
[![forks](https://img.shields.io/github/forks/umicro/uView2.0?style=flat-square&logo=GitHub)](https://github.com/umicro/uView2.0)
[![issues](https://img.shields.io/github/issues/umicro/uView2.0?style=flat-square&logo=GitHub)](https://github.com/umicro/uView2.0/issues)
[![Website](https://img.shields.io/badge/uView-up-blue?style=flat-square)](https://uviewui.com)
[![release](https://img.shields.io/github/v/release/umicro/uView2.0?style=flat-square)](https://gitee.com/umicro/uView2.0/releases)
[![license](https://img.shields.io/github/license/umicro/uView2.0?style=flat-square)](https://en.wikipedia.org/wiki/MIT_License)
## 说明
uView UI是[uni-app](https://uniapp.dcloud.io/)全面兼容nvue的uni-app生态框架全面的组件和便捷的工具会让您信手拈来如鱼得水
## [官方文档https://uviewui.com](https://uviewui.com)
## 预览
您可以通过**微信**扫码,查看最佳的演示效果。
<br>
<br>
<img src="https://uviewui.com/common/weixin_mini_qrcode.png" width="220" height="220" >
## 链接
- [官方文档](https://www.uviewui.com/)
- [更新日志](https://www.uviewui.com/components/changelog.html)
- [升级指南](https://www.uviewui.com/components/changeGuide.html)
- [关于我们](https://www.uviewui.com/cooperation/about.html)
## 交流反馈
欢迎加入我们的QQ群交流反馈[点此跳转](https://www.uviewui.com/components/addQQGroup.html)
## 关于PR
> 我们非常乐意接受各位的优质PR但在此之前我希望您了解uView2.0是一个需要兼容多个平台的小程序、h5、ios app、android app包括nvue页面、vue页面。
> 所以希望在您修复bug并提交之前尽可能的去这些平台测试一下兼容性。最好能携带测试截图以方便审核。非常感谢
## 安装
#### **uni-app插件市场链接** —— [https://ext.dcloud.net.cn/plugin?id=1593](https://ext.dcloud.net.cn/plugin?id=1593)
请通过[官网安装文档](https://www.uviewui.com/components/install.html)了解更详细的内容
## 快速上手
请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容
## 使用方法
配置easycom规则后自动按需引入无需`import`组件,直接引用即可。
```html
<template>
<u-button text="按钮"></u-button>
</template>
```
## 版权信息
uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议意味着您无需支付任何费用也无需授权即可将uView应用到您的产品中。

View File

@ -0,0 +1,374 @@
## 2.0.372024-03-17
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复表单校验`trigger`触发器参数无效问题
2. 修复`u-input`组件的`password`属性在动态切换为`false`时失效的问题
3. 添加微信小程序用户同意隐私协议事件回调
4. 修复支付宝小程序picker样式问题
5. `u-modal`添加`duration`字段控制动画过度时间
6. 修复`picker` `lastIndex`异常导致的`column`异常问题
7. `tabs`增加长按事件支持
8. 修复`u-avatar` `square`属性在小程序`open-data`下无效问题
9. 其他一些修复
## 2.0.362023-03-27
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 重构`deepClone` & `deepMerge`方法
2. 其他优化
## 2.0.342022-09-24
# uView2.0重磅发布,利剑出鞘,一统江湖
1. `u-input`、`u-textarea`增加`ignoreCompositionEvent`属性
2. 修复`route`方法调用可能报错的问题
3. 修复`u-no-network`组件`z-index`无效的问题
4. 修复`textarea`组件在h5上confirmType=""报错的问题
5. `u-rate`适配`nvue`
6. 优化验证手机号码的正则表达式(根据工信部发布的《电信网编号计划2017年版》进行修改。)
7. `form-item`添加`labelPosition`属性
8. `u-calendar`修复`maxDate`设置为当前日期并且当前时间大于0800时无法显示日期列表的问题 (#724)
9. `u-radio`增加一个默认插槽用于自定义修改label内容 (#680)
10. 修复`timeFormat`函数在safari重的兼容性问题 (#664)
## 2.0.332022-06-17
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复`loadmore`组件`lineColor`类型错误问题
2. 修复`u-parse`组件`imgtap`、`linktap`不生效问题
## 2.0.322022-06-16
# uView2.0重磅发布,利剑出鞘,一统江湖
1. `u-loadmore`新增自定义颜色、虚/实线
2. 修复`u-swiper-action`组件部分平台不能上下滑动的问题
3. 修复`u-list`回弹问题
4. 修复`notice-bar`组件动画在低端安卓机可能会抖动的问题
5. `u-loading-page`添加控制图标大小的属性`iconSize`
6. 修复`u-tooltip`组件`color`参数不生效的问题
7. 修复`u--input`组件使用`blur`事件输出为`undefined`的bug
8. `u-code-input`组件新增键盘弹起时,是否自动上推页面参数`adjustPosition`
9. 修复`image`组件`load`事件无回调对象问题
10. 修复`button`组件`loadingSize`设置无效问题
10. 其他修复
## 2.0.312022-04-19
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复`upload`在`vue`页面上传成功后没有成功标志的问题
2. 解决演示项目中微信小程序模拟上传图片一直出于上传中问题
3. 修复`u-code-input`组件在`nvue`页面编译到`app`平台上光标异常问题(`app`去除此功能)
4. 修复`actionSheet`组件标题关闭按钮点击事件名称错误的问题
5. 其他修复
## 2.0.302022-04-04
# uView2.0重磅发布,利剑出鞘,一统江湖
1. `u-rate`增加`readonly`属性
2. `tabs`滑块支持设置背景图片
3. 修复`u-subsection` `mode`为`subsection`时,滑块样式不正确的问题
4. `u-code-input`添加光标效果动画
5. 修复`popup`的`open`事件不触发
6. 修复`u-flex-column`无效的问题
7. 修复`u-datetime-picker`索引在特定场合异常问题
8. 修复`u-datetime-picker`最小时间字符串模板错误问题
9. `u-swiper`添加`m3u8`验证
10. `u-swiper`修改判断image和video逻辑
11. 修复`swiper`无法使用本地图片问题,增加`type`参数
12. 修复`u-row-notice`格式错误问题
13. 修复`u-switch`组件当`unit`为`rpx`时,`nodeStyle`消失的问题
14. 修复`datetime-picker`组件`showToolbar`与`visibleItemCount`属性无效的问题
15. 修复`upload`组件条件编译位置判断错误,导致`previewImage`属性设置为`false`时,整个组件都会被隐藏的问题
16. 修复`u-checkbox-group`设置`shape`属性无效的问题
17. 修复`u-upload`的`capture`传入字符串的时候不生效的问题
18. 修复`u-action-sheet`组件,关闭事件逻辑错误的问题
19. 修复`u-list`触顶事件的触发错误的问题
20. 修复`u-text`只有手机号可拨打的问题
21. 修复`u-textarea`不能换行的问题
22. 其他修复
## 2.0.292022-03-13
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复`u--text`组件设置`decoration`属性未生效的问题
2. 修复`u-datetime-picker`使用`formatter`后返回值不正确
3. 修复`u-datetime-picker` `intercept` 可能为undefined
4. 修复已设置单位 uni..config.unit = 'rpx'时,线型指示器 `transform` 的位置翻倍,导致指示器超出宽度
5. 修复mixin中bem方法生成的类名在支付宝和字节小程序中失效
6. 修复默认值传值为空的时候,打开`u-datetime-picker`报错不能选中第一列时间的bug
7. 修复`u-datetime-picker`使用`formatter`后返回值不正确
8. 修复`u-image`组件`loading`无效果的问题
9. 修复`config.unit`属性设为`rpx`时,导航栏占用高度不足导致塌陷的问题
10. 修复`u-datetime-picker`组件`itemHeight`无效问题
11. 其他修复
## 2.0.282022-02-22
# uView2.0重磅发布,利剑出鞘,一统江湖
1. search组件新增searchIconSize属性
2. 兼容Safari/Webkit中传入时间格式如2022-02-17 12:00:56
3. 修复text value.js 判断日期出format错误问题
4. priceFormat格式化金额出现精度错误
5. priceFormat在部分情况下出现精度损失问题
6. 优化表单rules提示
7. 修复avatar组件src为空时展示状态不对
8. 其他修复
## 2.0.272022-01-28
# uView2.0重磅发布,利剑出鞘,一统江湖
1.样式修复
## 2.0.262022-01-28
# uView2.0重磅发布,利剑出鞘,一统江湖
1.样式修复
## 2.0.252022-01-27
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复text组件mode=price时可能会导致精度错误的问题
2. 添加$u.setConfig()方法可设置uView内置的config, props, zIndex, color属性详见[修改uView内置配置方案](https://uviewui.com/components/setting.html#%E9%BB%98%E8%AE%A4%E5%8D%95%E4%BD%8D%E9%85%8D%E7%BD%AE)
3. 优化form组件在errorType=toast时如果输入错误页面会有抖动的问题
4. 修复$u.addUnit()对配置默认单位可能无效的问题
## 2.0.242022-01-25
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复swiper在current指定非0时缩放有误
2. 修复u-icon添加stop属性的时候报错
3. 优化遗留的通过正则判断rpx单位的问题
4. 优化Layout布局 vue使用gutter时会超出固定区域
5. 优化search组件高度单位问题rpx -> px
6. 修复u-image slot 加载和错误的图片失去了高度
7. 修复u-index-list中footer插槽与header插槽存在性判断错误
8. 修复部分机型下u-popup关闭时会闪烁
9. 修复u-image在nvue-app下失去宽高
10. 修复u-popup运行报错
11. 修复u-tooltip报错
12. 修复box-sizing在app下的警告
13. 修复u-navbar在小程序中报运行时错误
14. 其他修复
## 2.0.232022-01-24
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复image组件在hx3.3.9的nvue下可能会显示异常的问题
2. 修复col组件gutter参数带rpx单位处理不正确的问题
3. 修复text组件单行时无法显示省略号的问题
4. navbar添加titleStyle参数
5. 升级到hx3.3.9可消除nvue下控制台样式警告的问题
## 2.0.222022-01-19
# uView2.0重磅发布,利剑出鞘,一统江湖
1. $u.page()方法优化,避免在特殊场景可能报错的问题
2. picker组件添加immediateChange参数
3. 新增$u.pages()方法
## 2.0.212022-01-19
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 优化form组件在用户设置rules的时候提示用户model必传
2. 优化遗留的通过正则判断rpx单位的问题
3. 修复微信小程序环境中tabbar组件开启safeAreaInsetBottom属性后placeholder高度填充不正确
4. 修复swiper在current指定非0时缩放有误
5. 修复u-icon添加stop属性的时候报错
6. 修复upload组件在accept=all的时候没有作用
7. 修复在text组件mode为phone时call属性无效的问题
8. 处理u-form clearValidate方法
9. 其他修复
## 2.0.202022-01-14
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复calendar默认会选择一个日期如果直接点确定的话无法取到值的问题
2. 修复Slider缺少disabled props 还有注释
3. 修复u-notice-bar点击事件无法拿到index索引值的问题
4. 修复u-collapse-item在vue文件下app端自定义插槽不生效的问题
5. 优化头像为空时显示默认头像
6. 修复图片地址赋值后判断加载状态为完成问题
7. 修复日历滚动到默认日期月份区域
8. search组件暴露点击左边icon事件
9. 修复u-form clearValidate方法不生效
10. upload h5端增加返回文件参数文件的name参数
11. 处理upload选择文件后url为blob类型无法预览的问题
12. u-code-input 修复输入框没有往左移出一半屏幕
13. 修复Upload上传 disabled为true时控制台报hoverClass类型错误
14. 临时处理ios app下grid点击坍塌问题
15. 其他修复
## 2.0.192021-12-29
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 优化微信小程序包体积可在微信中预览请升级HbuilderX3.3.4,同时在“运行->运行到小程序模拟器”中勾选“运行时是否压缩代码”
2. 优化微信小程序setData性能处理某些方法如$u.route()无法在模板中使用的问题
3. navbar添加autoBack参数
4. 允许avatar组件的事件冒泡
5. 修复cell组件报错问题
6. 其他修复
## 2.0.182021-12-28
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复app端编译报错问题
2. 重新处理微信小程序端setData过大的性能问题
3. 修复边框问题
4. 修复最大最小月份不大于0则没有数据出现的问题
5. 修复SwipeAction微信小程序端无法上下滑动问题
6. 修复input的placeholder在小程序端默认显示为true问题
7. 修复divider组件click事件无效问题
8. 修复u-code-input maxlength 属性值为 String 类型时显示异常
9. 修复当 grid只有 1到2时 在小程序端algin设置无效的问题
10. 处理form-item的label为top时取消错误提示的左边距
11. 其他修复
## 2.0.172021-12-26
## uView正在参与开源中国的“年度最佳项目”评选之前投过票的现在也可以投票恳请同学们投一票[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 解决HBuilderX3.3.3.20211225版本导致的样式问题
2. calendar日历添加monthNum参数
3. navbar添加center slot
## 2.0.162021-12-25
## uView正在参与开源中国的“年度最佳项目”评选之前投过票的现在也可以投票恳请同学们投一票[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 解决微信小程序setData性能问题
2. 修复count-down组件change事件不触发问题
## 2.0.152021-12-21
## uView正在参与开源中国的“年度最佳项目”评选之前投过票的现在也可以投票恳请同学们投一票[点此帮助uView](https://www.oschina.net/project/top_cn_2021/?id=583)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复Cell单元格titleWidth无效
2. 修复cheakbox组件ischecked不更新
3. 修复keyboard是否显示"."按键默认值问题
4. 修复number-keyboard是否显示键盘的"."符号问题
5. 修复Input输入框 readonly无效
6. 修复u-avatar 导致打包app、H5时候报错问题
7. 修复Upload上传deletable无效
8. 修复upload当设置maxSize时无效的问题
9. 修复tabs lineWidth传入带单位的字符串的时候偏移量计算错误问题
10. 修复rate组件在有padding的view内显示的星星位置和可触摸区域不匹配无法正常选中星星
## 2.0.132021-12-14
## [点击加群交流反馈364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复配置默认单位为rpx可能会导致自定义导航栏高度异常的问题
## 2.0.122021-12-14
## [点击加群交流反馈364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复tabs组件在vue环境下划线消失的问题
2. 修复upload组件在安卓小程序无法选择视频的问题
3. 添加uni.$u.config.unit配置用于配置参数默认单位详见[默认单位配置](https://www.uviewui.com/components/setting.html#%E9%BB%98%E8%AE%A4%E5%8D%95%E4%BD%8D%E9%85%8D%E7%BD%AE)
4. 修复textarea组件在没绑定v-model时字符统计不生效问题
5. 修复nvue下控制是否出现滚动条失效问题
## 2.0.112021-12-13
## [点击加群交流反馈364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. text组件align参数无效的问题
2. subsection组件添加keyName参数
3. upload组件无法判断[Object file]类型的问题
4. 处理notify层级过低问题
5. codeInput组件添加disabledDot参数
6. 处理actionSheet组件round参数无效的问题
7. calendar组件添加round参数用于控制圆角值
8. 处理swipeAction组件在vue环境下默认被打开的问题
9. button组件的throttleTime节流参数无效的问题
10. 解决u-notify手动关闭方法close()无效的问题
11. input组件readonly不生效问题
12. tag组件type参数为info不生效问题
## 2.0.102021-12-08
## [点击加群交流反馈364463526](https://jq.qq.com/?_chanwv=1027&k=mCxS3TGY)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复button sendMessagePath属性不生效
2. 修复DatetimePicker选择器title无效
3. 修复u-toast设置loading=true不生效
4. 修复u-text金额模式传0报错
5. 修复u-toast组件的icon属性配置不生效
6. button的icon在特殊场景下的颜色优化
7. IndexList优化增加#
## 2.0.92021-12-01
## [点击加群交流反馈232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 优化swiper的height支持100%值(仅vue有效)修复嵌入视频时click事件无法触发的问题
2. 优化tabs组件对list值为空的判断或者动态变化list时重新计算相关尺寸的问题
3. 优化datetime-picker组件逻辑让其后续打开的默认值为上一次的选中值需要通过v-model绑定值才有效
4. 修复upload内嵌在其他组件中选择图片可能不会换行的问题
## 2.0.82021-12-01
## [点击加群交流反馈232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复toast的position参数无效问题
2. 处理input在ios nvue上无法获得焦点的问题
3. avatar-group组件添加extraValue参数让剩余展示数量可手动控制
4. tabs组件添加keyName参数用于配置从对象中读取的键名
5. 处理text组件名字脱敏默认配置无效的问题
6. 处理picker组件item文本太长换行问题
## 2.0.72021-11-30
## [点击加群交流反馈232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 修复radio和checkbox动态改变v-model无效的问题。
2. 优化form规则validator在微信小程序用法
3. 修复backtop组件mode参数在微信小程序无效的问题
4. 处理Album的previewFullImage属性无效的问题
5. 处理u-datetime-picker组件mode='time'在选择改变时间时,控制台报错的问题
## 2.0.62021-11-27
## [点击加群交流反馈232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. 处理tag组件在vue下边框无效的问题。
2. 处理popup组件圆角参数可能无效的问题。
3. 处理tabs组件lineColor参数可能无效的问题。
4. propgress组件在值很小时显示异常的问题。
## 2.0.52021-11-25
## [点击加群交流反馈232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. calendar在vue下显示异常问题。
2. form组件labelPosition和errorType参数无效的问题
3. input组件inputAlign无效的问题
4. 其他一些修复
## 2.0.42021-11-23
## [点击加群交流反馈232041042](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
0. input组件缺失@confirm事件以及subfix和prefix无效问题
1. component.scss文件样式在vue下干扰全局布局问题
2. 修复subsection在vue环境下表现异常的问题
3. tag组件的bgColor等参数无效的问题
4. upload组件不换行的问题
5. 其他的一些修复处理
## 2.0.32021-11-16
## [点击加群交流反馈1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. uView2.0已实现全面兼容nvue
2. uView2.0对1.x进行了架构重构细节和性能都有极大提升
3. 目前uView2.0为公测阶段,相关细节可能会有变动
4. 我们写了一份与1.x的对比指南详见[对比1.x](https://www.uviewui.com/components/diff1.x.html)
5. 处理modal的confirm回调事件拼写错误问题
6. 处理input组件@input事件参数错误问题
7. 其他一些修复
## 2.0.22021-11-16
## [点击加群交流反馈1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. uView2.0已实现全面兼容nvue
2. uView2.0对1.x进行了架构重构细节和性能都有极大提升
3. 目前uView2.0为公测阶段,相关细节可能会有变动
4. 我们写了一份与1.x的对比指南详见[对比1.x](https://www.uviewui.com/components/diff1.x.html)
5. 修复input组件formatter参数缺失问题
6. 优化loading-icon组件的scss写法问题防止不兼容新版本scss
## 2.0.0(2020-11-15)
## [点击加群交流反馈1129077272](https://jq.qq.com/?_wv=1027&k=KnbeceDU)
# uView2.0重磅发布,利剑出鞘,一统江湖
1. uView2.0已实现全面兼容nvue
2. uView2.0对1.x进行了架构重构细节和性能都有极大提升
3. 目前uView2.0为公测阶段,相关细节可能会有变动
4. 我们写了一份与1.x的对比指南详见[对比1.x](https://www.uviewui.com/components/diff1.x.html)
5. 修复input组件formatter参数缺失问题

View File

@ -0,0 +1,78 @@
<template>
<uvForm
ref="uForm"
:model="model"
:rules="rules"
:errorType="errorType"
:borderBottom="borderBottom"
:labelPosition="labelPosition"
:labelWidth="labelWidth"
:labelAlign="labelAlign"
:labelStyle="labelStyle"
:customStyle="customStyle"
>
<slot />
</uvForm>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u-form被uni-app官方占用了u-form在nvue中相当于form组件
* 所以在nvue下取名为u--form内部其实还是u-form.vue只不过做一层中转
*/
import uvForm from '../u-form/u-form.vue';
import props from '../u-form/props.js'
export default {
// #ifdef MP-WEIXIN
name: 'u-form',
// #endif
// #ifndef MP-WEIXIN
name: 'u--form',
// #endif
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvForm
},
created() {
this.children = []
},
methods: {
//
setRules(rules) {
this.$refs.uForm.setRules(rules)
},
validate() {
/**
* 在微信小程序中通过this.$parent拿到的父组件是u--form而不是其内嵌的u-form
* 导致在u-form组件中拿不到对应的children数组从而校验无效所以这里每次调用u-form组件中的
* 对应方法的时候在小程序中都先将u--form的children赋值给u-form中的children
*/
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.validate()
},
validateField(value, callback, event) {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.validateField(value, callback, event)
},
resetFields() {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.resetFields()
},
clearValidate(props) {
// #ifdef MP-WEIXIN
this.setMpData()
// #endif
return this.$refs.uForm.clearValidate(props)
},
setMpData() {
this.$refs.uForm.children = this.children
}
},
}
</script>

View File

@ -0,0 +1,47 @@
<template>
<uvImage
:src="src"
:mode="mode"
:width="width"
:height="height"
:shape="shape"
:radius="radius"
:lazyLoad="lazyLoad"
:showMenuByLongpress="showMenuByLongpress"
:loadingIcon="loadingIcon"
:errorIcon="errorIcon"
:showLoading="showLoading"
:showError="showError"
:fade="fade"
:webp="webp"
:duration="duration"
:bgColor="bgColor"
:customStyle="customStyle"
@click="$emit('click')"
@error="$emit('error')"
@load="$emit('load')"
>
<template v-slot:loading>
<slot name="loading"></slot>
</template>
<template v-slot:error>
<slot name="error"></slot>
</template>
</uvImage>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u-image被uni-app官方占用了u-image在nvue中相当于image组件
* 所以在nvue下取名为u--image内部其实还是u-iamge.vue只不过做一层中转
*/
import uvImage from '../u-image/u-image.vue';
import props from '../u-image/props.js';
export default {
name: 'u--image',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvImage
},
}
</script>

View File

@ -0,0 +1,73 @@
<template>
<uvInput
:value="value"
:type="type"
:fixed="fixed"
:disabled="disabled"
:disabledColor="disabledColor"
:clearable="clearable"
:password="password"
:maxlength="maxlength"
:placeholder="placeholder"
:placeholderClass="placeholderClass"
:placeholderStyle="placeholderStyle"
:showWordLimit="showWordLimit"
:confirmType="confirmType"
:confirmHold="confirmHold"
:holdKeyboard="holdKeyboard"
:focus="focus"
:autoBlur="autoBlur"
:disableDefaultPadding="disableDefaultPadding"
:cursor="cursor"
:cursorSpacing="cursorSpacing"
:selectionStart="selectionStart"
:selectionEnd="selectionEnd"
:adjustPosition="adjustPosition"
:inputAlign="inputAlign"
:fontSize="fontSize"
:color="color"
:prefixIcon="prefixIcon"
:suffixIcon="suffixIcon"
:suffixIconStyle="suffixIconStyle"
:prefixIconStyle="prefixIconStyle"
:border="border"
:readonly="readonly"
:shape="shape"
:customStyle="customStyle"
:formatter="formatter"
:ignoreCompositionEvent="ignoreCompositionEvent"
@focus="$emit('focus')"
@blur="e => $emit('blur', e)"
@keyboardheightchange="$emit('keyboardheightchange')"
@change="e => $emit('change', e)"
@input="e => $emit('input', e)"
@confirm="e => $emit('confirm', e)"
@clear="$emit('clear')"
@click="$emit('click')"
>
<!-- #ifdef MP -->
<slot name="prefix"></slot>
<slot name="suffix"></slot>
<!-- #endif -->
<!-- #ifndef MP -->
<slot name="prefix" slot="prefix"></slot>
<slot name="suffix" slot="suffix"></slot>
<!-- #endif -->
</uvInput>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u-input被uni-app官方占用了u-input在nvue中相当于input组件
* 所以在nvue下取名为u--input内部其实还是u-input.vue只不过做一层中转
*/
import uvInput from '../u-input/u-input.vue';
import props from '../u-input/props.js'
export default {
name: 'u--input',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvInput
},
}
</script>

View File

@ -0,0 +1,44 @@
<template>
<uvText
:type="type"
:show="show"
:text="text"
:prefixIcon="prefixIcon"
:suffixIcon="suffixIcon"
:mode="mode"
:href="href"
:format="format"
:call="call"
:openType="openType"
:bold="bold"
:block="block"
:lines="lines"
:color="color"
:decoration="decoration"
:size="size"
:iconStyle="iconStyle"
:margin="margin"
:lineHeight="lineHeight"
:align="align"
:wordWrap="wordWrap"
:customStyle="customStyle"
@click="$emit('click')"
></uvText>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u-text被uni-app官方占用了u-text在nvue中相当于input组件
* 所以在nvue下取名为u--input内部其实还是u-text.vue只不过做一层中转
* 不使用v-bind="$attrs"而是分开独立写传参是因为微信小程序不支持此写法
*/
import uvText from "../u-text/u-text.vue";
import props from "../u-text/props.js";
export default {
name: "u--text",
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvText,
},
};
</script>

View File

@ -0,0 +1,48 @@
<template>
<uvTextarea
:value="value"
:placeholder="placeholder"
:height="height"
:confirmType="confirmType"
:disabled="disabled"
:count="count"
:focus="focus"
:autoHeight="autoHeight"
:fixed="fixed"
:cursorSpacing="cursorSpacing"
:cursor="cursor"
:showConfirmBar="showConfirmBar"
:selectionStart="selectionStart"
:selectionEnd="selectionEnd"
:adjustPosition="adjustPosition"
:disableDefaultPadding="disableDefaultPadding"
:holdKeyboard="holdKeyboard"
:maxlength="maxlength"
:border="border"
:customStyle="customStyle"
:formatter="formatter"
:ignoreCompositionEvent="ignoreCompositionEvent"
@focus="e => $emit('focus')"
@blur="e => $emit('blur')"
@linechange="e => $emit('linechange', e)"
@confirm="e => $emit('confirm')"
@input="e => $emit('input', e)"
@keyboardheightchange="e => $emit('keyboardheightchange')"
></uvTextarea>
</template>
<script>
/**
* 此组件存在的理由是在nvue下u--textarea被uni-app官方占用了u-textarea在nvue中相当于textarea组件
* 所以在nvue下取名为u--textarea内部其实还是u-textarea.vue只不过做一层中转
*/
import uvTextarea from '../u-textarea/u-textarea.vue';
import props from '../u-textarea/props.js'
export default {
name: 'u--textarea',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
components: {
uvTextarea
},
}
</script>

View File

@ -0,0 +1,54 @@
export default {
props: {
// 操作菜单是否展示 默认false
show: {
type: Boolean,
default: uni.$u.props.actionSheet.show
},
// 标题
title: {
type: String,
default: uni.$u.props.actionSheet.title
},
// 选项上方的描述信息
description: {
type: String,
default: uni.$u.props.actionSheet.description
},
// 数据
actions: {
type: Array,
default: uni.$u.props.actionSheet.actions
},
// 取消按钮的文字,不为空时显示按钮
cancelText: {
type: String,
default: uni.$u.props.actionSheet.cancelText
},
// 点击某个菜单项时是否关闭弹窗
closeOnClickAction: {
type: Boolean,
default: uni.$u.props.actionSheet.closeOnClickAction
},
// 处理底部安全区默认true
safeAreaInsetBottom: {
type: Boolean,
default: uni.$u.props.actionSheet.safeAreaInsetBottom
},
// 小程序的打开方式
openType: {
type: String,
default: uni.$u.props.actionSheet.openType
},
// 点击遮罩是否允许关闭 (默认true)
closeOnClickOverlay: {
type: Boolean,
default: uni.$u.props.actionSheet.closeOnClickOverlay
},
// 圆角值
round: {
type: [Boolean, String, Number],
default: uni.$u.props.actionSheet.round
}
}
}

View File

@ -0,0 +1,278 @@
<template>
<u-popup
:show="show"
mode="bottom"
@close="closeHandler"
:safeAreaInsetBottom="safeAreaInsetBottom"
:round="round"
>
<view class="u-action-sheet">
<view
class="u-action-sheet__header"
v-if="title"
>
<text class="u-action-sheet__header__title u-line-1">{{title}}</text>
<view
class="u-action-sheet__header__icon-wrap"
@tap.stop="cancel"
>
<u-icon
name="close"
size="17"
color="#c8c9cc"
bold
></u-icon>
</view>
</view>
<text
class="u-action-sheet__description"
:style="[{
marginTop: `${title && description ? 0 : '18px'}`
}]"
v-if="description"
>{{description}}</text>
<slot>
<u-line v-if="description"></u-line>
<view class="u-action-sheet__item-wrap">
<template v-for="(item, index) in actions">
<!-- #ifdef MP -->
<button
:key="index"
class="u-reset-button"
:openType="item.openType"
@getuserinfo="onGetUserInfo"
@contact="onContact"
@getphonenumber="onGetPhoneNumber"
@error="onError"
@launchapp="onLaunchApp"
@opensetting="onOpenSetting"
:lang="lang"
:session-from="sessionFrom"
:send-message-title="sendMessageTitle"
:send-message-path="sendMessagePath"
:send-message-img="sendMessageImg"
:show-message-card="showMessageCard"
:app-parameter="appParameter"
@tap="selectHandler(index)"
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
>
<!-- #endif -->
<view
class="u-action-sheet__item-wrap__item"
@tap.stop="selectHandler(index)"
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
:hover-stay-time="150"
>
<template v-if="!item.loading">
<text
class="u-action-sheet__item-wrap__item__name"
:style="[itemStyle(index)]"
>{{ item.name }}</text>
<text
v-if="item.subname"
class="u-action-sheet__item-wrap__item__subname"
>{{ item.subname }}</text>
</template>
<u-loading-icon
v-else
custom-class="van-action-sheet__loading"
size="18"
mode="circle"
/>
</view>
<!-- #ifdef MP -->
</button>
<!-- #endif -->
<u-line v-if="index !== actions.length - 1"></u-line>
</template>
</view>
</slot>
<u-gap
bgColor="#eaeaec"
height="6"
v-if="cancelText"
></u-gap>
<view hover-class="u-action-sheet--hover">
<text
@touchmove.stop.prevent
:hover-stay-time="150"
v-if="cancelText"
class="u-action-sheet__cancel-text"
@tap="cancel"
>{{cancelText}}</text>
</view>
</view>
</u-popup>
</template>
<script>
import openType from '../../libs/mixin/openType'
import button from '../../libs/mixin/button'
import props from './props.js';
/**
* ActionSheet 操作菜单
* @description 本组件用于从底部弹出一个操作菜单供用户选择并返回结果本组件功能类似于uni的uni.showActionSheetAPI配置更加灵活所有平台都表现一致
* @tutorial https://www.uviewui.com/components/actionSheet.html
*
* @property {Boolean} show 操作菜单是否展示 默认 false
* @property {String} title 操作菜单标题
* @property {String} description 选项上方的描述信息
* @property {Array<Object>} actions 按钮的文字数组见官方文档示例
* @property {String} cancelText 取消按钮的提示文字,不为空时显示按钮
* @property {Boolean} closeOnClickAction 点击某个菜单项时是否关闭弹窗 默认 true
* @property {Boolean} safeAreaInsetBottom 处理底部安全区 默认 true
* @property {String} openType 小程序的打开方式 (contact | launchApp | getUserInfo | openSetting getPhoneNumber error )
* @property {Boolean} closeOnClickOverlay 点击遮罩是否允许关闭 (默认 true )
* @property {Number|String} round 圆角值默认无圆角 (默认 0 )
* @property {String} lang 指定返回用户信息的语言zh_CN 简体中文zh_TW 繁体中文en 英文
* @property {String} sessionFrom 会话来源openType="contact"时有效
* @property {String} sendMessageTitle 会话内消息卡片标题openType="contact"时有效
* @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径openType="contact"时有效
* @property {String} sendMessageImg 会话内消息卡片图片openType="contact"时有效
* @property {Boolean} showMessageCard 是否显示会话内消息卡片设置此参数为 true用户进入客服会话会在右下角显示"可能要发送的小程序"提示用户点击后可以快速发送小程序消息openType="contact"时有效 默认 false
* @property {String} appParameter 打开 APP APP 传递的参数openType=launchApp 时有效
*
* @event {Function} select 点击ActionSheet列表项时触发
* @event {Function} close 点击取消按钮时触发
* @event {Function} getuserinfo 用户点击该按钮时会返回获取到的用户信息回调的 detail 数据与 wx.getUserInfo 返回的一致openType="getUserInfo"时有效
* @event {Function} contact 客服消息回调openType="contact"时有效
* @event {Function} getphonenumber 获取用户手机号回调openType="getPhoneNumber"时有效
* @event {Function} error 当使用开放能力时发生错误的回调openType="error"时有效
* @event {Function} launchapp 打开 APP 成功的回调openType="launchApp"时有效
* @event {Function} opensetting 在打开授权设置页后回调openType="openSetting"时有效
* @example <u-action-sheet :actions="list" :title="title" :show="show"></u-action-sheet>
*/
export default {
name: "u-action-sheet",
// propsmethodsmixin
mixins: [openType, button, uni.$u.mixin, props],
data() {
return {
}
},
computed: {
//
itemStyle() {
return (index) => {
let style = {};
if (this.actions[index].color) style.color = this.actions[index].color
if (this.actions[index].fontSize) style.fontSize = uni.$u.addUnit(this.actions[index].fontSize)
//
if (this.actions[index].disabled) style.color = '#c0c4cc'
return style;
}
},
},
methods: {
closeHandler() {
// close
if(this.closeOnClickOverlay) {
this.$emit('close')
}
},
//
cancel() {
this.$emit('close')
},
selectHandler(index) {
const item = this.actions[index]
if (item && !item.disabled && !item.loading) {
this.$emit('select', item)
if (this.closeOnClickAction) {
this.$emit('close')
}
}
},
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-action-sheet-reset-button-width:100% !default;
$u-action-sheet-title-font-size: 16px !default;
$u-action-sheet-title-padding: 12px 30px !default;
$u-action-sheet-title-color: $u-main-color !default;
$u-action-sheet-header-icon-wrap-right:15px !default;
$u-action-sheet-header-icon-wrap-top:15px !default;
$u-action-sheet-description-font-size:13px !default;
$u-action-sheet-description-color:14px !default;
$u-action-sheet-description-margin: 18px 15px !default;
$u-action-sheet-item-wrap-item-padding:15px !default;
$u-action-sheet-item-wrap-name-font-size:16px !default;
$u-action-sheet-item-wrap-subname-font-size:13px !default;
$u-action-sheet-item-wrap-subname-color: #c0c4cc !default;
$u-action-sheet-item-wrap-subname-margin-top:10px !default;
$u-action-sheet-cancel-text-font-size:16px !default;
$u-action-sheet-cancel-text-color:$u-content-color !default;
$u-action-sheet-cancel-text-font-size:15px !default;
$u-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default;
.u-reset-button {
width: $u-action-sheet-reset-button-width;
}
.u-action-sheet {
text-align: center;
&__header {
position: relative;
padding: $u-action-sheet-title-padding;
&__title {
font-size: $u-action-sheet-title-font-size;
color: $u-action-sheet-title-color;
font-weight: bold;
text-align: center;
}
&__icon-wrap {
position: absolute;
right: $u-action-sheet-header-icon-wrap-right;
top: $u-action-sheet-header-icon-wrap-top;
}
}
&__description {
font-size: $u-action-sheet-description-font-size;
color: $u-tips-color;
margin: $u-action-sheet-description-margin;
text-align: center;
}
&__item-wrap {
&__item {
padding: $u-action-sheet-item-wrap-item-padding;
@include flex;
align-items: center;
justify-content: center;
flex-direction: column;
&__name {
font-size: $u-action-sheet-item-wrap-name-font-size;
color: $u-main-color;
text-align: center;
}
&__subname {
font-size: $u-action-sheet-item-wrap-subname-font-size;
color: $u-action-sheet-item-wrap-subname-color;
margin-top: $u-action-sheet-item-wrap-subname-margin-top;
text-align: center;
}
}
}
&__cancel-text {
font-size: $u-action-sheet-cancel-text-font-size;
color: $u-action-sheet-cancel-text-color;
text-align: center;
padding: $u-action-sheet-cancel-text-font-size;
}
&--hover {
background-color: $u-action-sheet-cancel-text-hover-background-color;
}
}
</style>

View File

@ -0,0 +1,59 @@
export default {
props: {
// 图片地址Array<String>|Array<Object>形式
urls: {
type: Array,
default: uni.$u.props.album.urls
},
// 指定从数组的对象元素中读取哪个属性作为图片地址
keyName: {
type: String,
default: uni.$u.props.album.keyName
},
// 单图时,图片长边的长度
singleSize: {
type: [String, Number],
default: uni.$u.props.album.singleSize
},
// 多图时,图片边长
multipleSize: {
type: [String, Number],
default: uni.$u.props.album.multipleSize
},
// 多图时,图片水平和垂直之间的间隔
space: {
type: [String, Number],
default: uni.$u.props.album.space
},
// 单图时,图片缩放裁剪的模式
singleMode: {
type: String,
default: uni.$u.props.album.singleMode
},
// 多图时,图片缩放裁剪的模式
multipleMode: {
type: String,
default: uni.$u.props.album.multipleMode
},
// 最多展示的图片数量,超出时最后一个位置将会显示剩余图片数量
maxCount: {
type: [String, Number],
default: uni.$u.props.album.maxCount
},
// 是否可以预览图片
previewFullImage: {
type: Boolean,
default: uni.$u.props.album.previewFullImage
},
// 每行展示图片数量如设置singleSize和multipleSize将会无效
rowCount: {
type: [String, Number],
default: uni.$u.props.album.rowCount
},
// 超出maxCount时是否显示查看更多的提示
showMore: {
type: Boolean,
default: uni.$u.props.album.showMore
}
}
}

View File

@ -0,0 +1,259 @@
<template>
<view class="u-album">
<view
class="u-album__row"
ref="u-album__row"
v-for="(arr, index) in showUrls"
:forComputedUse="albumWidth"
:key="index"
>
<view
class="u-album__row__wrapper"
v-for="(item, index1) in arr"
:key="index1"
:style="[imageStyle(index + 1, index1 + 1)]"
@tap="previewFullImage ? onPreviewTap(getSrc(item)) : ''"
>
<image
:src="getSrc(item)"
:mode="
urls.length === 1
? imageHeight > 0
? singleMode
: 'widthFix'
: multipleMode
"
:style="[
{
width: imageWidth,
height: imageHeight
}
]"
></image>
<view
v-if="
showMore &&
urls.length > rowCount * showUrls.length &&
index === showUrls.length - 1 &&
index1 === showUrls[showUrls.length - 1].length - 1
"
class="u-album__row__wrapper__text"
>
<u--text
:text="`+${urls.length - maxCount}`"
color="#fff"
:size="multipleSize * 0.3"
align="center"
customStyle="justify-content: center"
></u--text>
</view>
</view>
</view>
</view>
</template>
<script>
import props from './props.js'
// #ifdef APP-NVUE
// weexKPIdom
const dom = uni.requireNativePlugin('dom')
// #endif
/**
* Album 相册
* @description 本组件提供一个类似相册的功能让开发者开发起来更加得心应手减少重复的模板代码
* @tutorial https://www.uviewui.com/components/album.html
*
* @property {Array} urls 图片地址列表 Array<String>|Array<Object>形式
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
* @property {String | Number} singleSize 单图时图片长边的长度 默认 180
* @property {String | Number} multipleSize 多图时图片边长 默认 70
* @property {String | Number} space 多图时图片水平和垂直之间的间隔 默认 6
* @property {String} singleMode 单图时图片缩放裁剪的模式 默认 'scaleToFill'
* @property {String} multipleMode 多图时图片缩放裁剪的模式 默认 'aspectFill'
* @property {String | Number} maxCount 取消按钮的提示文字 默认 9
* @property {Boolean} previewFullImage 是否可以预览图片 默认 true
* @property {String | Number} rowCount 每行展示图片数量如设置singleSize和multipleSize将会无效 默认 3
* @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 默认 true
*
* @event {Function} albumWidth 某些特殊的情况下需要让文字与相册的宽度相等这里事件的形式对外发送 回调参数 width
* @example <u-album :urls="urls2" @albumWidth="width => albumWidth = width" multipleSize="68" ></u-album>
*/
export default {
name: 'u-album',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
//
singleWidth: 0,
//
singleHeight: 0,
//
singlePercent: 0.6
}
},
watch: {
urls: {
immediate: true,
handler(newVal) {
if (newVal.length === 1) {
this.getImageRect()
}
}
}
},
computed: {
imageStyle() {
return (index1, index2) => {
const { space, rowCount, multipleSize, urls } = this,
{ addUnit, addStyle } = uni.$u,
rowLen = this.showUrls.length,
allLen = this.urls.length
const style = {
marginRight: addUnit(space),
marginBottom: addUnit(space)
}
//
if (index1 === rowLen) style.marginBottom = 0
//
if (
index2 === rowCount ||
(index1 === rowLen &&
index2 === this.showUrls[index1 - 1].length)
)
style.marginRight = 0
return style
}
},
//
showUrls() {
const arr = []
this.urls.map((item, index) => {
//
if (index + 1 <= this.maxCount) {
//
const itemIndex = Math.floor(index / this.rowCount)
//
if (!arr[itemIndex]) {
arr[itemIndex] = []
}
arr[itemIndex].push(item)
}
})
return arr
},
imageWidth() {
return uni.$u.addUnit(
this.urls.length === 1 ? this.singleWidth : this.multipleSize
)
},
imageHeight() {
return uni.$u.addUnit(
this.urls.length === 1 ? this.singleHeight : this.multipleSize
)
},
// computedurls
//
albumWidth() {
let width = 0
if (this.urls.length === 1) {
width = this.singleWidth
} else {
width =
this.showUrls[0].length * this.multipleSize +
this.space * (this.showUrls[0].length - 1)
}
this.$emit('albumWidth', width)
return width
}
},
methods: {
//
onPreviewTap(url) {
const urls = this.urls.map((item) => {
return this.getSrc(item)
})
uni.previewImage({
current: url,
urls
})
},
//
getSrc(item) {
return uni.$u.test.object(item)
? (this.keyName && item[this.keyName]) || item.src
: item
},
//
// download
// (singlePercent)
getImageRect() {
const src = this.getSrc(this.urls[0])
uni.getImageInfo({
src,
success: (res) => {
//
const isHorizotal = res.width >= res.height
this.singleWidth = isHorizotal
? this.singleSize
: (res.width / res.height) * this.singleSize
this.singleHeight = !isHorizotal
? this.singleSize
: (res.height / res.width) * this.singleWidth
},
fail: () => {
this.getComponentWidth()
}
})
},
//
async getComponentWidth() {
// dom
await uni.$u.sleep(30)
// #ifndef APP-NVUE
this.$uGetRect('.u-album__row').then((size) => {
this.singleWidth = size.width * this.singlePercent
})
// #endif
// #ifdef APP-NVUE
// ref="u-album__row"forthis.$refs['u-album__row']
const ref = this.$refs['u-album__row'][0]
ref &&
dom.getComponentRect(ref, (res) => {
this.singleWidth = res.size.width * this.singlePercent
})
// #endif
}
}
}
</script>
<style lang="scss" scoped>
@import '../../libs/css/components.scss';
.u-album {
@include flex(column);
&__row {
@include flex(row);
flex-wrap: wrap;
&__wrapper {
position: relative;
&__text {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
@include flex(row);
justify-content: center;
align-items: center;
}
}
}
}
</style>

View File

@ -0,0 +1,256 @@
<template>
<view class="u-alert-tips" v-if="show" :class="[
!show ? 'u-close-alert-tips': '',
type ? 'u-alert-tips--bg--' + type + '-light' : '',
type ? 'u-alert-tips--border--' + type + '-disabled' : '',
]" :style="{
backgroundColor: bgColor,
borderColor: borderColor
}">
<view class="u-icon-wrap">
<u-icon v-if="showIcon" :name="uIcon" :size="description ? 40 : 32" class="u-icon" :color="uIconType" :custom-style="iconStyle"></u-icon>
</view>
<view class="u-alert-content" @tap.stop="click">
<view class="u-alert-title" :style="[uTitleStyle]">
{{title}}
</view>
<view v-if="description" class="u-alert-desc" :style="[descStyle]">
{{description}}
</view>
</view>
<view class="u-icon-wrap">
<u-icon @click="close" v-if="closeAble && !closeText" hoverClass="u-type-error-hover-color" name="close" color="#c0c4cc"
:size="22" class="u-close-icon" :style="{
top: description ? '18rpx' : '24rpx'
}"></u-icon>
</view>
<text v-if="closeAble && closeText" class="u-close-text" :style="{
top: description ? '18rpx' : '24rpx'
}">{{closeText}}</text>
</view>
</template>
<script>
/**
* alertTips 警告提示
* @description 警告提示展现需要关注的信息
* @tutorial https://uviewui.com/components/alertTips.html
* @property {String} title 显示的标题文字
* @property {String} description 辅助性文字颜色比title浅一点字号也小一点可选
* @property {String} type 关闭按钮(默认为叉号icon图标)
* @property {String} icon 图标名称
* @property {Object} icon-style 图标的样式对象形式
* @property {Object} title-style 标题的样式对象形式
* @property {Object} desc-style 描述的样式对象形式
* @property {String} close-able 用文字替代关闭图标close-able为true时有效
* @property {Boolean} show-icon 是否显示左边的辅助图标
* @property {Boolean} show 显示或隐藏组件
* @event {Function} click 点击组件时触发
* @event {Function} close 点击关闭按钮时触发
*/
export default {
name: 'u-alert-tips',
props: {
//
title: {
type: String,
default: ''
},
// success/warning/info/error
type: {
type: String,
default: 'warning'
},
//
description: {
type: String,
default: ''
},
//
closeAble: {
type: Boolean,
default: false
},
//
closeText: {
type: String,
default: ''
},
//
showIcon: {
type: Boolean,
default: false
},
// coloricon
color: {
type: String,
default: ''
},
//
bgColor: {
type: String,
default: ''
},
//
borderColor: {
type: String,
default: ''
},
//
show: {
type: Boolean,
default: true
},
// icon
icon: {
type: String,
default: ''
},
// icon
iconStyle: {
type: Object,
default() {
return {}
}
},
//
titleStyle: {
type: Object,
default() {
return {}
}
},
//
descStyle: {
type: Object,
default() {
return {}
}
},
},
data() {
return {
}
},
computed: {
uTitleStyle() {
let style = {};
//
style.fontWeight = this.description ? 500 : 'normal';
// stylestyle
return this.$u.deepMerge(style, this.titleStyle);
},
uIcon() {
// icon使type
return this.icon ? this.icon : this.$u.type2icon(this.type);
},
uIconType() {
// 使type
return Object.keys(this.iconStyle).length ? '' : this.type;
}
},
methods: {
//
click() {
this.$emit('click');
},
//
close() {
this.$emit('close');
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/style.components.scss";
.u-alert-tips {
@include vue-flex;
align-items: center;
padding: 16rpx 30rpx;
border-radius: 8rpx;
position: relative;
transition: all 0.3s linear;
border: 1px solid #fff;
&--bg--primary-light {
background-color: $u-type-primary-light;
}
&--bg--info-light {
background-color: $u-type-info-light;
}
&--bg--success-light {
background-color: $u-type-success-light;
}
&--bg--warning-light {
background-color: $u-type-warning-light;
}
&--bg--error-light {
background-color: $u-type-error-light;
}
&--border--primary-disabled {
border-color: $u-type-primary-disabled;
}
&--border--success-disabled {
border-color: $u-type-success-disabled;
}
&--border--error-disabled {
border-color: $u-type-error-disabled;
}
&--border--warning-disabled {
border-color: $u-type-warning-disabled;
}
&--border--info-disabled {
border-color: $u-type-info-disabled;
}
}
.u-close-alert-tips {
opacity: 0;
visibility: hidden;
}
.u-icon {
margin-right: 16rpx;
}
.u-alert-title {
font-size: 28rpx;
color: $u-main-color;
}
.u-alert-desc {
font-size: 26rpx;
text-align: left;
color: $u-content-color;
}
.u-close-icon {
position: absolute;
top: 20rpx;
right: 20rpx;
}
.u-close-hover {
color: red;
}
.u-close-text {
font-size: 24rpx;
color: $u-tips-color;
position: absolute;
top: 20rpx;
right: 20rpx;
line-height: 1;
}
</style>

View File

@ -0,0 +1,44 @@
export default {
props: {
// 显示文字
title: {
type: String,
default: uni.$u.props.alert.title
},
// 主题success/warning/info/error
type: {
type: String,
default: uni.$u.props.alert.type
},
// 辅助性文字
description: {
type: String,
default: uni.$u.props.alert.description
},
// 是否可关闭
closable: {
type: Boolean,
default: uni.$u.props.alert.closable
},
// 是否显示图标
showIcon: {
type: Boolean,
default: uni.$u.props.alert.showIcon
},
// 浅或深色调light-浅色dark-深色
effect: {
type: String,
default: uni.$u.props.alert.effect
},
// 文字是否居中
center: {
type: Boolean,
default: uni.$u.props.alert.center
},
// 字体大小
fontSize: {
type: [String, Number],
default: uni.$u.props.alert.fontSize
}
}
}

View File

@ -0,0 +1,243 @@
<template>
<u-transition
mode="fade"
:show="show"
>
<view
class="u-alert"
:class="[`u-alert--${type}--${effect}`]"
@tap.stop="clickHandler"
:style="[$u.addStyle(customStyle)]"
>
<view
class="u-alert__icon"
v-if="showIcon"
>
<u-icon
:name="iconName"
size="18"
:color="iconColor"
></u-icon>
</view>
<view
class="u-alert__content"
:style="[{
paddingRight: closable ? '20px' : 0
}]"
>
<text
class="u-alert__content__title"
v-if="title"
:style="[{
fontSize: $u.addUnit(fontSize),
textAlign: center ? 'center' : 'left'
}]"
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
>{{ title }}</text>
<text
class="u-alert__content__desc"
v-if="description"
:style="[{
fontSize: $u.addUnit(fontSize),
textAlign: center ? 'center' : 'left'
}]"
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
>{{ description }}</text>
</view>
<view
class="u-alert__close"
v-if="closable"
@tap.stop="closeHandler"
>
<u-icon
name="close"
:color="iconColor"
size="15"
></u-icon>
</view>
</view>
</u-transition>
</template>
<script>
import props from './props.js';
/**
* Alert 警告提示
* @description 警告提示展现需要关注的信息
* @tutorial https://www.uviewui.com/components/alertTips.html
*
* @property {String} title 显示的文字
* @property {String} type 使用预设的颜色 默认 'warning'
* @property {String} description 辅助性文字颜色比title浅一点字号也小一点可选
* @property {Boolean} closable 关闭按钮(默认为叉号icon图标) 默认 false
* @property {Boolean} showIcon 是否显示左边的辅助图标 默认 false
* @property {String} effect 多图时图片缩放裁剪的模式 默认 'light'
* @property {Boolean} center 文字是否居中 默认 false
* @property {String | Number} fontSize 字体大小 默认 14
* @property {Object} customStyle 定义需要用到的外部样式
* @event {Function} click 点击组件时触发
* @example <u-alert :title="title" type = "warning" :closable="closable" :description = "description"></u-alert>
*/
export default {
name: 'u-alert',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
show: true
}
},
computed: {
iconColor() {
return this.effect === 'light' ? this.type : '#fff'
},
//
iconName() {
switch (this.type) {
case 'success':
return 'checkmark-circle-fill';
break;
case 'error':
return 'close-circle-fill';
break;
case 'warning':
return 'error-circle-fill';
break;
case 'info':
return 'info-circle-fill';
break;
case 'primary':
return 'more-circle-fill';
break;
default:
return 'error-circle-fill';
}
}
},
methods: {
//
clickHandler() {
this.$emit('click')
},
//
closeHandler() {
this.show = false
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-alert {
position: relative;
background-color: $u-primary;
padding: 8px 10px;
@include flex(row);
align-items: center;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
&--primary--dark {
background-color: $u-primary;
}
&--primary--light {
background-color: #ecf5ff;
}
&--error--dark {
background-color: $u-error;
}
&--error--light {
background-color: #FEF0F0;
}
&--success--dark {
background-color: $u-success;
}
&--success--light {
background-color: #f5fff0;
}
&--warning--dark {
background-color: $u-warning;
}
&--warning--light {
background-color: #FDF6EC;
}
&--info--dark {
background-color: $u-info;
}
&--info--light {
background-color: #f4f4f5;
}
&__icon {
margin-right: 5px;
}
&__content {
@include flex(column);
flex: 1;
&__title {
color: $u-main-color;
font-size: 14px;
font-weight: bold;
color: #fff;
margin-bottom: 2px;
}
&__desc {
color: $u-main-color;
font-size: 14px;
flex-wrap: wrap;
color: #fff;
}
}
&__title--dark,
&__desc--dark {
color: #FFFFFF;
}
&__text--primary--light,
&__text--primary--light {
color: $u-primary;
}
&__text--success--light,
&__text--success--light {
color: $u-success;
}
&__text--warning--light,
&__text--warning--light {
color: $u-warning;
}
&__text--error--light,
&__text--error--light {
color: $u-error;
}
&__text--info--light,
&__text--info--light {
color: $u-info;
}
&__close {
position: absolute;
top: 11px;
right: 10px;
}
}
</style>

View File

@ -0,0 +1,290 @@
<template>
<view class="content">
<view class="cropper-wrapper" :style="{ height: cropperOpt.height + 'px' }">
<canvas
class="cropper"
:disable-scroll="true"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
:style="{ width: cropperOpt.width, height: cropperOpt.height, backgroundColor: 'rgba(0, 0, 0, 0.8)' }"
canvas-id="cropper"
id="cropper"
></canvas>
<canvas
class="cropper"
:disable-scroll="true"
:style="{
position: 'fixed',
top: `-${cropperOpt.width * cropperOpt.pixelRatio}px`,
left: `-${cropperOpt.height * cropperOpt.pixelRatio}px`,
width: `${cropperOpt.width * cropperOpt.pixelRatio}px`,
height: `${cropperOpt.height * cropperOpt.pixelRatio}`
}"
canvas-id="targetId"
id="targetId"
></canvas>
</view>
<view class="cropper-buttons safe-area-padding" :style="{ height: bottomNavHeight + 'px' }">
<!-- #ifdef H5 -->
<view class="upload" @tap="uploadTap"></view>
<!-- #endif -->
<!-- #ifndef H5 -->
<view class="upload" @tap="uploadTap"></view>
<!-- #endif -->
<view class="getCropperImage" @tap="getCropperImage(false)"></view>
</view>
</view>
</template>
<script>
import WeCropper from './weCropper.js';
export default {
props: {
// lineWidth-(rpx)color:
// mask-rgba"rgba(0, 0, 0, 0.35)"
boundStyle: {
type: Object,
default() {
return {
lineWidth: 4,
borderColor: 'rgb(245, 245, 245)',
mask: 'rgba(0, 0, 0, 0.35)'
};
}
}
// // rpx
// rectWidth: {
// type: [String, Number],
// default: 400
// },
// // rpx
// rectHeight: {
// type: [String, Number],
// default: 400
// },
// // rpx
// destWidth: {
// type: [String, Number],
// default: 400
// },
// // rpx
// destHeight: {
// type: [String, Number],
// default: 400
// },
// // "png""jpg"
// fileType: {
// type: String,
// default: 'jpg',
// },
// //
// // H5使
// quality: {
// type: [Number, String],
// default: 1
// }
},
data() {
return {
//
bottomNavHeight: 50,
originWidth: 200,
width: 0,
height: 0,
cropperOpt: {
id: 'cropper',
targetId: 'targetCropper',
pixelRatio: 1,
width: 0,
height: 0,
scale: 2.5,
zoom: 8,
cut: {
x: (this.width - this.originWidth) / 2,
y: (this.height - this.originWidth) / 2,
width: this.originWidth,
height: this.originWidth
},
boundStyle: {
lineWidth: uni.upx2px(this.boundStyle.lineWidth),
mask: this.boundStyle.mask,
color: this.boundStyle.borderColor
}
},
//
// px
destWidth: 200,
// px
rectWidth: 200,
// 'png'"jpg"
fileType: 'jpg',
src: '', //
};
},
onLoad(option) {
let rectInfo = uni.getSystemInfoSync();
this.width = rectInfo.windowWidth;
this.height = rectInfo.windowHeight - this.bottomNavHeight;
this.cropperOpt.width = this.width;
this.cropperOpt.height = this.height;
this.cropperOpt.pixelRatio = rectInfo.pixelRatio;
if (option.destWidth) this.destWidth = option.destWidth;
if (option.rectWidth) {
let rectWidth = Number(option.rectWidth);
this.cropperOpt.cut = {
x: (this.width - rectWidth) / 2,
y: (this.height - rectWidth) / 2,
width: rectWidth,
height: rectWidth
};
}
this.rectWidth = option.rectWidth;
if (option.fileType) this.fileType = option.fileType;
//
this.cropper = new WeCropper(this.cropperOpt)
.on('ready', ctx => {
// wecropper is ready for work!
})
.on('beforeImageLoad', ctx => {
// before picture loaded, i can do something
})
.on('imageLoad', ctx => {
// picture loaded
})
.on('beforeDraw', (ctx, instance) => {
// before canvas draw,i can do something
});
// page.json
uni.setNavigationBarColor({
frontColor: '#ffffff',
backgroundColor: '#000000'
});
uni.chooseImage({
count: 1, // 9
sizeType: ['compressed'], //
sourceType: ['album', 'camera'], //
success: res => {
this.src = res.tempFilePaths[0];
// datasrc
this.cropper.pushOrign(this.src);
}
});
},
methods: {
touchStart(e) {
this.cropper.touchStart(e);
},
touchMove(e) {
this.cropper.touchMove(e);
},
touchEnd(e) {
this.cropper.touchEnd(e);
},
getCropperImage(isPre = false) {
if(!this.src) return this.$u.toast('请先选择图片再裁剪');
let cropper_opt = {
destHeight: Number(this.destWidth), // uni.canvasToTempFilePath
destWidth: Number(this.destWidth),
fileType: this.fileType
};
this.cropper.getCropperImage(cropper_opt, (path, err) => {
if (err) {
uni.showModal({
title: '温馨提示',
content: err.message
});
} else {
if (isPre) {
uni.previewImage({
current: '', // http
urls: [path] // http
});
} else {
uni.$emit('uAvatarCropper', path);
this.$u.route({
type: 'back'
});
}
}
});
},
uploadTap() {
const self = this;
uni.chooseImage({
count: 1, // 9
sizeType: ['original', 'compressed'], //
sourceType: ['album', 'camera'], //
success: (res) => {
self.src = res.tempFilePaths[0];
// datasrc
self.cropper.pushOrign(this.src);
}
});
}
}
};
</script>
<style scoped lang="scss">
@import '../../libs/css/style.components.scss';
.content {
background: rgba(255, 255, 255, 1);
}
.cropper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 11;
}
.cropper-buttons {
background-color: #000000;
color: #eee;
}
.cropper-wrapper {
position: relative;
@include vue-flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
width: 100%;
background-color: #000;
}
.cropper-buttons {
width: 100vw;
@include vue-flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
position: fixed;
bottom: 0;
left: 0;
font-size: 28rpx;
}
.cropper-buttons .upload,
.cropper-buttons .getCropperImage {
width: 50%;
text-align: center;
}
.cropper-buttons .upload {
text-align: left;
padding-left: 50rpx;
}
.cropper-buttons .getCropperImage {
text-align: right;
padding-right: 50rpx;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
export default {
props: {
// 头像图片组
urls: {
type: Array,
default: uni.$u.props.avatarGroup.urls
},
// 最多展示的头像数量
maxCount: {
type: [String, Number],
default: uni.$u.props.avatarGroup.maxCount
},
// 头像形状
shape: {
type: String,
default: uni.$u.props.avatarGroup.shape
},
// 图片裁剪模式
mode: {
type: String,
default: uni.$u.props.avatarGroup.mode
},
// 超出maxCount时是否显示查看更多的提示
showMore: {
type: Boolean,
default: uni.$u.props.avatarGroup.showMore
},
// 头像大小
size: {
type: [String, Number],
default: uni.$u.props.avatarGroup.size
},
// 指定从数组的对象元素中读取哪个属性作为图片地址
keyName: {
type: String,
default: uni.$u.props.avatarGroup.keyName
},
// 头像之间的遮挡比例
gap: {
type: [String, Number],
validator(value) {
return value >= 0 && value <= 1
},
default: uni.$u.props.avatarGroup.gap
},
// 需额外显示的值
extraValue: {
type: [Number, String],
default: uni.$u.props.avatarGroup.extraValue
}
}
}

View File

@ -0,0 +1,103 @@
<template>
<view class="u-avatar-group">
<view
class="u-avatar-group__item"
v-for="(item, index) in showUrl"
:key="index"
:style="{
marginLeft: index === 0 ? 0 : $u.addUnit(-size * gap)
}"
>
<u-avatar
:size="size"
:shape="shape"
:mode="mode"
:src="$u.test.object(item) ? keyName && item[keyName] || item.url : item"
></u-avatar>
<view
class="u-avatar-group__item__show-more"
v-if="showMore && index === showUrl.length - 1 && (urls.length > maxCount || extraValue > 0)"
@tap="clickHandler"
>
<u--text
color="#ffffff"
:size="size * 0.4"
:text="`+${extraValue || urls.length - showUrl.length}`"
align="center"
customStyle="justify-content: center"
></u--text>
</view>
</view>
</view>
</template>
<script>
import props from './props.js';
/**
* AvatarGroup 头像组
* @description 本组件一般用于展示头像的地方如个人中心或者评论列表页的用户头像展示等场所
* @tutorial https://www.uviewui.com/components/avatar.html
*
* @property {Array} urls 头像图片组 默认 []
* @property {String | Number} maxCount 最多展示的头像数量 默认 5
* @property {String} shape 头像形状 'circle' (默认) | 'square'
* @property {String} mode 图片裁剪模式默认 'scaleToFill'
* @property {Boolean} showMore 超出maxCount时是否显示查看更多的提示 默认 true
* @property {String | Number} size 头像大小 默认 40
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
* @property {String | Number} gap 头像之间的遮挡比例0.4代表遮挡40% 默认 0.5
* @property {String | Number} extraValue 需额外显示的值
* @event {Function} showMore 头像组更多点击
* @example <u-avatar-group:urls="urls" size="35" gap="0.4" ></u-avatar-group:urls=>
*/
export default {
name: 'u-avatar-group',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
}
},
computed: {
showUrl() {
return this.urls.slice(0, this.maxCount)
}
},
methods: {
clickHandler() {
this.$emit('showMore')
}
},
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-avatar-group {
@include flex;
&__item {
margin-left: -10px;
position: relative;
&--no-indent {
// 使:first-childnvue
margin-left: 0;
}
&__show-more {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.3);
@include flex;
align-items: center;
justify-content: center;
border-radius: 100px;
}
}
}
</style>

View File

@ -0,0 +1,78 @@
export default {
props: {
// 头像图片路径(不能为相对路径)
src: {
type: String,
default: uni.$u.props.avatar.src
},
// 头像形状circle-圆形square-方形
shape: {
type: String,
default: uni.$u.props.avatar.shape
},
// 头像尺寸
size: {
type: [String, Number],
default: uni.$u.props.avatar.size
},
// 裁剪模式
mode: {
type: String,
default: uni.$u.props.avatar.mode
},
// 显示的文字
text: {
type: String,
default: uni.$u.props.avatar.text
},
// 背景色
bgColor: {
type: String,
default: uni.$u.props.avatar.bgColor
},
// 文字颜色
color: {
type: String,
default: uni.$u.props.avatar.color
},
// 文字大小
fontSize: {
type: [String, Number],
default: uni.$u.props.avatar.fontSize
},
// 显示的图标
icon: {
type: String,
default: uni.$u.props.avatar.icon
},
// 显示小程序头像只对百度微信QQ小程序有效
mpAvatar: {
type: Boolean,
default: uni.$u.props.avatar.mpAvatar
},
// 是否使用随机背景色
randomBgColor: {
type: Boolean,
default: uni.$u.props.avatar.randomBgColor
},
// 加载失败的默认头像(组件有内置默认图片)
defaultUrl: {
type: String,
default: uni.$u.props.avatar.defaultUrl
},
// 如果配置了randomBgColor为true且配置了此值则从默认的背景色数组中取出对应索引的颜色值取值0-19之间
colorIndex: {
type: [String, Number],
// 校验参数规则索引在0-19之间
validator(n) {
return uni.$u.test.range(n, [0, 19]) || n === ''
},
default: uni.$u.props.avatar.colorIndex
},
// 组件标识符
name: {
type: String,
default: uni.$u.props.avatar.name
}
}
}

View File

@ -0,0 +1,173 @@
<template>
<view
class="u-avatar"
:class="[`u-avatar--${shape}`]"
:style="[{
backgroundColor: (text || icon) ? (randomBgColor ? colors[colorIndex !== '' ? colorIndex : $u.random(0, 19)] : bgColor) : 'transparent',
width: $u.addUnit(size),
height: $u.addUnit(size),
}, $u.addStyle(customStyle)]"
@tap="clickHandler"
>
<slot>
<!-- #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU -->
<open-data
v-if="mpAvatar && allowMp"
type="userAvatarUrl"
:style="[{
width: $u.addUnit(size),
height: $u.addUnit(size)
}]"
/>
<!-- #endif -->
<!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU -->
<template v-if="mpAvatar && allowMp"></template>
<!-- #endif -->
<u-icon
v-else-if="icon"
:name="icon"
:size="fontSize"
:color="color"
></u-icon>
<u--text
v-else-if="text"
:text="text"
:size="fontSize"
:color="color"
align="center"
customStyle="justify-content: center"
></u--text>
<image
class="u-avatar__image"
v-else
:class="[`u-avatar__image--${shape}`]"
:src="avatarUrl || defaultUrl"
:mode="mode"
@error="errorHandler"
:style="[{
width: $u.addUnit(size),
height: $u.addUnit(size)
}]"
></image>
</slot>
</view>
</template>
<script>
import props from './props.js';
const base64Avatar =
"data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYGCAsMCgoLCgoMEAwMDAwMDBAMDg8QDw4MExMUFBMTHBsbGxwfHx8fHx8fHx8fAQcHBw0MDRgQEBgaFREVGh8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx//wAARCADIAMgDAREAAhEBAxEB/8QAcQABAQEAAwEBAAAAAAAAAAAAAAUEAQMGAgcBAQAAAAAAAAAAAAAAAAAAAAAQAAIBAwICBgkDBQAAAAAAAAABAhEDBCEFMVFBYXGREiKBscHRMkJSEyOh4XLxYjNDFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHbHFyZ/Dam+yLA+Z2L0Pjtyj2poD4AAAAAAAAAAAAAAAAAAAAAAAAKWFs9y6lcvvwQeqj8z9wFaziY1n/HbUX9XF97A7QAGXI23EvJ1goyfzR0YEfN269jeZ+a03pNe0DIAAAAAAAAAAAAAAAAAAAACvtO3RcVkXlWutuL9YFYAAAAAOJRjKLjJVi9GmB5/csH/mu1h/in8PU+QGMAAAAAAAAAAAAAAAAAAaMDG/6MmMH8C80+xAelSSVFolwQAAAAAAAHVlWI37ErUulaPk+hgeYnCUJuElSUXRrrQHAAAAAAAAAAAAAAAAABa2Oz4bM7r4zdF2ICmAAAAAAAAAg7zZ8GX41wuJP0rRgYAAAAAAAAAAAAAAAAAD0m2R8ODaXU33tsDSAAAAAAAAAlb9HyWZcnJd9PcBHAAAAAAAAAAAAAAAAAPS7e64Vn+KA0AAAAAAAAAJm+v8Ftf3ewCKAAAAAAAAAAAAAAAAAX9muqeGo9NttP06+0DcAAAAAAAAAjb7dTu2ra+VOT9P8AQCWAAAAAAAAAAAAAAAAAUNmyPt5Ltv4bui/kuAF0AAAAAAADiUlGLlJ0SVW+oDzOXfd/Ind6JPRdS0QHSAAAAAAAAAAAAAAAAAE2nVaNcGB6Lbs6OTao9LsF51z60BrAAAAAABJ3jOVHjW3r/sa9QEgAAAAAAAAAAAAAAAAAAAPu1duWriuW34ZR4MC9hbnZyEoy8l36XwfYBsAAADaSq9EuLAlZ+7xSdrGdW9Hc5dgEdtt1erfFgAAAAAAAAAAAAAAAAADVjbblX6NR8MH80tEBRs7HYivyzlN8lovaBPzduvY0m6eK10TXtAyAarO55lpJK54orolr+4GqO/Xaea1FvqbXvA+Z77kNeW3GPbV+4DJfzcm/pcm3H6Vou5AdAFLC2ed2Pjv1txa8sV8T6wOL+yZEKu1JXFy4MDBOE4ScZxcZLinoB8gAAAAAAAAAAAB242LeyJ+C3GvN9C7QLmJtePYpKS+5c+p8F2IDYAANJqj1T4oCfk7Nj3G5Wn9qXJax7gJ93Z82D8sVNc4v30A6Xg5i42Z+iLfqARwcyT0sz9MWvWBps7LlTf5Grce9/oBTxdtxseklHxT+uWr9AGoAB138ezfj4bsFJdD6V2MCPm7RdtJzs1uW1xXzL3gTgAAAAAAAAADRhYc8q74I6RWs5ckB6GxYtWLat21SK731sDsAAAAAAAAAAAAAAAASt021NO/YjrxuQXT1oCOAAAAAAABzGLlJRSq26JAelwsWONYjbXxcZvmwO8AAAAAAAAAAAAAAAAAAef3TEWPkVivx3NY9T6UBiAAAAAABo2+VmGXblddIJ8eivRUD0oAAAAAAAAAAAAAAAAAAAYt4tKeFKVNYNSXfRgefAAAAAAAAr7VuSSWPedKaW5v1MCsAAAAAAAAAAAAAAAAAAIe6bj96Ts2n+JPzSXzP3ATgAAAAAAAAFbbt1UUrOQ9FpC4/UwK6aaqtU+DAAAAAAAAAAAAAAA4lKMIuUmoxWrb4ARNx3R3q2rLpa4Sl0y/YCcAAAAAAAAAAANmFud7G8r89r6X0dgFvGzLGRGtuWvTF6NAdwAAAAAAAAAAAy5W442PVN+K59EePp5ARMvOv5MvO6QXCC4AZwAAAAAAAAAAAAAcxlKLUotprg1owN+PvORborq+7Hnwl3gUbO74VzRydt8pKn68ANcJwmqwkpLmnUDkAAAAfNy9atqtyagut0AxXt5xIV8Fbj6lRd7Am5G65V6qUvtwfyx94GMAAAAAAAAAAAAAAAAAAAOU2nVOj5gdsc3LiqRvTpyqwOxbnnrhdfpSfrQB7pnv/AGvuS9gHXPMy5/Fem1yq0v0A6W29XqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//Z";
/**
* Avatar 头像
* @description 本组件一般用于展示头像的地方如个人中心或者评论列表页的用户头像展示等场所
* @tutorial https://www.uviewui.com/components/avatar.html
*
* @property {String} src 头像路径如加载失败将会显示默认头像(不能为相对路径)
* @property {String} shape 头像形状 circle (默认) | square
* @property {String | Number} size 头像尺寸可以为指定字符串(large, default, mini)或者数值 默认 40
* @property {String} mode 头像图片的裁剪类型与uni的image组件的mode参数一致如效果达不到需求可尝试传widthFix值 默认 'scaleToFill'
* @property {String} text 用文字替代图片级别优先于src
* @property {String} bgColor 背景颜色一般显示文字时用 默认 '#c0c4cc'
* @property {String} color 文字颜色 默认 '#ffffff'
* @property {String | Number} fontSize 文字大小 默认 18
* @property {String} icon 显示的图标
* @property {Boolean} mpAvatar 显示小程序头像只对百度微信QQ小程序有效 默认 false
* @property {Boolean} randomBgColor 是否使用随机背景色 默认 false
* @property {String} defaultUrl 加载失败的默认头像(组件有内置默认图片)
* @property {String | Number} colorIndex 如果配置了randomBgColor为true且配置了此值则从默认的背景色数组中取出对应索引的颜色值取值0-19之间
* @property {String} name 组件标识符 默认 'level'
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} click 点击组件时触发 index: 用户传递的标识符
* @example <u-avatar :src="src" mode="square"></u-avatar>
*/
export default {
name: 'u-avatar',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
// randomBgColortrue
colors: ['#ffb34b', '#f2bba9', '#f7a196', '#f18080', '#88a867', '#bfbf39', '#89c152', '#94d554', '#f19ec2',
'#afaae4', '#e1b0df', '#c38cc1', '#72dcdc', '#9acdcb', '#77b1cc', '#448aca', '#86cefa', '#98d1ee',
'#73d1f1',
'#80a7dc'
],
avatarUrl: this.src,
allowMp: false
}
},
watch: {
// srcavatarUrlsrc
// props
src: {
immediate: true,
handler(newVal) {
this.avatarUrl = newVal
// srcerrorsrc''
if(!newVal) {
this.errorHandler()
}
}
}
},
computed: {
imageStyle() {
const style = {}
return style
}
},
created() {
this.init()
},
methods: {
init() {
// open-data
// uni.getUserInfo()
//
// #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU
this.allowMp = true
// #endif
},
// name"/"
isImg() {
return this.src.indexOf('/') !== -1
},
//
errorHandler() {
this.avatarUrl = this.defaultUrl || base64Avatar
},
clickHandler() {
this.$emit('click', this.name)
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-avatar {
@include flex;
align-items: center;
justify-content: center;
&--circle {
border-radius: 100px;
}
&--square {
border-radius: 4px;
}
&__image {
&--circle {
border-radius: 100px;
overflow: hidden;
}
&--square {
border-radius: 4px;
}
}
}
</style>

View File

@ -0,0 +1,54 @@
export default {
props: {
// 返回顶部的形状circle-圆形square-方形
mode: {
type: String,
default: uni.$u.props.backtop.mode
},
// 自定义图标
icon: {
type: String,
default: uni.$u.props.backtop.icon
},
// 提示文字
text: {
type: String,
default: uni.$u.props.backtop.text
},
// 返回顶部滚动时间
duration: {
type: [String, Number],
default: uni.$u.props.backtop.duration
},
// 滚动距离
scrollTop: {
type: [String, Number],
default: uni.$u.props.backtop.scrollTop
},
// 距离顶部多少距离显示单位px
top: {
type: [String, Number],
default: uni.$u.props.backtop.top
},
// 返回顶部按钮到底部的距离单位px
bottom: {
type: [String, Number],
default: uni.$u.props.backtop.bottom
},
// 返回顶部按钮到右边的距离单位px
right: {
type: [String, Number],
default: uni.$u.props.backtop.right
},
// 层级
zIndex: {
type: [String, Number],
default: uni.$u.props.backtop.zIndex
},
// 图标的样式,对象形式
iconStyle: {
type: Object,
default: uni.$u.props.backtop.iconStyle
}
}
}

View File

@ -0,0 +1,129 @@
<template>
<u-transition
mode="fade"
:customStyle="backTopStyle"
:show="show"
>
<view
class="u-back-top"
:style="[contentStyle]"
v-if="!$slots.default && !$slots.$default"
@click="backToTop"
>
<u-icon
:name="icon"
:custom-style="iconStyle"
></u-icon>
<text
v-if="text"
class="u-back-top__text"
>{{text}}</text>
</view>
<slot v-else />
</u-transition>
</template>
<script>
import props from './props.js';
// #ifdef APP-NVUE
const dom = weex.requireModule('dom')
// #endif
/**
* backTop 返回顶部
* @description 本组件一个用于长页面滑动一定距离后出现返回顶部按钮方便快速返回顶部的场景
* @tutorial https://uviewui.com/components/backTop.html
*
* @property {String} mode 返回顶部的形状circle-圆形square-方形 默认 'circle'
* @property {String} icon 自定义图标 默认 'arrow-upward' 见官方文档示例
* @property {String} text 提示文字
* @property {String | Number} duration 返回顶部滚动时间 默认 100
* @property {String | Number} scrollTop 滚动距离 默认 0
* @property {String | Number} top 距离顶部多少距离显示单位px 默认 400
* @property {String | Number} bottom 返回顶部按钮到底部的距离单位px 默认 100
* @property {String | Number} right 返回顶部按钮到右边的距离单位px 默认 20
* @property {String | Number} zIndex 层级 默认 9
* @property {Object<Object>} iconStyle 图标的样式对象形式 默认 {color: '#909399',fontSize: '19px'}
* @property {Object} customStyle 定义需要用到的外部样式
*
* @example <u-back-top :scrollTop="scrollTop"></u-back-top>
*/
export default {
name: 'u-back-top',
mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
computed: {
backTopStyle() {
//
const style = {
bottom: uni.$u.addUnit(this.bottom),
right: uni.$u.addUnit(this.right),
width: '40px',
height: '40px',
position: 'fixed',
zIndex: 10,
}
return style
},
show() {
return uni.$u.getPx(this.scrollTop) > uni.$u.getPx(this.top)
},
contentStyle() {
const style = {}
let radius = 0
//
if(this.mode === 'circle') {
radius = '100px'
} else {
radius = '4px'
}
// nvue
style.borderTopLeftRadius = radius
style.borderTopRightRadius = radius
style.borderBottomLeftRadius = radius
style.borderBottomRightRadius = radius
return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
}
},
methods: {
backToTop() {
// #ifdef APP-NVUE
if (!this.$parent.$refs['u-back-top']) {
uni.$u.error(`nvue页面需要给页面最外层元素设置"ref='u-back-top'`)
}
dom.scrollToElement(this.$parent.$refs['u-back-top'], {
offset: 0
})
// #endif
// #ifndef APP-NVUE
uni.pageScrollTo({
scrollTop: 0,
duration: this.duration
});
// #endif
this.$emit('click')
}
}
}
</script>
<style lang="scss" scoped>
@import '../../libs/css/components.scss';
$u-back-top-flex:1 !default;
$u-back-top-height:100% !default;
$u-back-top-background-color:#E1E1E1 !default;
$u-back-top-tips-font-size:12px !default;
.u-back-top {
@include flex;
flex-direction: column;
align-items: center;
flex:$u-back-top-flex;
height: $u-back-top-height;
justify-content: center;
background-color: $u-back-top-background-color;
&__tips {
font-size:$u-back-top-tips-font-size;
transform: scale(0.8);
}
}
</style>

View File

@ -0,0 +1,72 @@
export default {
props: {
// 是否显示圆点
isDot: {
type: Boolean,
default: uni.$u.props.badge.isDot
},
// 显示的内容
value: {
type: [Number, String],
default: uni.$u.props.badge.value
},
// 是否显示
show: {
type: Boolean,
default: uni.$u.props.badge.show
},
// 最大值,超过最大值会显示 '{max}+'
max: {
type: [Number, String],
default: uni.$u.props.badge.max
},
// 主题类型error|warning|success|primary
type: {
type: String,
default: uni.$u.props.badge.type
},
// 当数值为 0 时,是否展示 Badge
showZero: {
type: Boolean,
default: uni.$u.props.badge.showZero
},
// 背景颜色优先级比type高如设置type参数会失效
bgColor: {
type: [String, null],
default: uni.$u.props.badge.bgColor
},
// 字体颜色
color: {
type: [String, null],
default: uni.$u.props.badge.color
},
// 徽标形状circle-四角均为圆角horn-左下角为直角
shape: {
type: String,
default: uni.$u.props.badge.shape
},
// 设置数字的显示方式overflow|ellipsis|limit
// overflow会根据max字段判断超出显示`${max}+`
// ellipsis会根据max判断超出显示`${max}...`
// limit会依据1000作为判断条件超出1000显示`${value/1000}K`比如2.2k、3.34w最多保留2位小数
numberType: {
type: String,
default: uni.$u.props.badge.numberType
},
// 设置badge的位置偏移格式为 [x, y]也即设置的为top和right的值absolute为true时有效
offset: {
type: Array,
default: uni.$u.props.badge.offset
},
// 是否反转背景和字体颜色
inverted: {
type: Boolean,
default: uni.$u.props.badge.inverted
},
// 是否绝对定位
absolute: {
type: Boolean,
default: uni.$u.props.badge.absolute
}
}
}

View File

@ -0,0 +1,171 @@
<template>
<text
v-if="show && ((Number(value) === 0 ? showZero : true) || isDot)"
:class="[isDot ? 'u-badge--dot' : 'u-badge--not-dot', inverted && 'u-badge--inverted', shape === 'horn' && 'u-badge--horn', `u-badge--${type}${inverted ? '--inverted' : ''}`]"
:style="[$u.addStyle(customStyle), badgeStyle]"
class="u-badge"
>{{ isDot ? '' :showValue }}</text>
</template>
<script>
import props from './props.js';
/**
* badge 徽标数
* @description 该组件一般用于图标右上角显示未读的消息数量提示用户点击有圆点和圆包含文字两种形式
* @tutorial https://uviewui.com/components/badge.html
*
* @property {Boolean} isDot 是否显示圆点 默认 false
* @property {String | Number} value 显示的内容
* @property {Boolean} show 是否显示 默认 true
* @property {String | Number} max 最大值超过最大值会显示 '{max}+' 默认999
* @property {String} type 主题类型error|warning|success|primary 默认 'error'
* @property {Boolean} showZero 当数值为 0 是否展示 Badge 默认 false
* @property {String} bgColor 背景颜色优先级比type高如设置type参数会失效
* @property {String} color 字体颜色 默认 '#ffffff'
* @property {String} shape 徽标形状circle-四角均为圆角horn-左下角为直角 默认 'circle'
* @property {String} numberType 设置数字的显示方式overflow|ellipsis|limit 默认 'overflow'
* @property {Array}} offset 设置badge的位置偏移格式为 [x, y]也即设置的为top和right的值absolute为true时有效
* @property {Boolean} inverted 是否反转背景和字体颜色默认 false
* @property {Boolean} absolute 是否绝对定位默认 false
* @property {Object} customStyle 定义需要用到的外部样式
* @example <u-badge :type="type" :count="count"></u-badge>
*/
export default {
name: 'u-badge',
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
computed: {
// badge
boxStyle() {
let style = {};
return style;
},
//
badgeStyle() {
const style = {}
if(this.color) {
style.color = this.color
}
if (this.bgColor && !this.inverted) {
style.backgroundColor = this.bgColor
}
if (this.absolute) {
style.position = 'absolute'
// offset
if(this.offset.length) {
// toprightoffsetrighttop
const top = this.offset[0]
const right = this.offset[1] || top
style.top = uni.$u.addUnit(top)
style.right = uni.$u.addUnit(right)
}
}
return style
},
showValue() {
switch (this.numberType) {
case "overflow":
return Number(this.value) > Number(this.max) ? this.max + "+" : this.value
break;
case "ellipsis":
return Number(this.value) > Number(this.max) ? "..." : this.value
break;
case "limit":
return Number(this.value) > 999 ? Number(this.value) >= 9999 ?
Math.floor(this.value / 1e4 * 100) / 100 + "w" : Math.floor(this.value /
1e3 * 100) / 100 + "k" : this.value
break;
default:
return Number(this.value)
}
},
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-badge-primary: $u-primary !default;
$u-badge-error: $u-error !default;
$u-badge-success: $u-success !default;
$u-badge-info: $u-info !default;
$u-badge-warning: $u-warning !default;
$u-badge-dot-radius: 100px !default;
$u-badge-dot-size: 8px !default;
$u-badge-dot-right: 4px !default;
$u-badge-dot-top: 0 !default;
$u-badge-text-font-size: 11px !default;
$u-badge-text-right: 10px !default;
$u-badge-text-padding: 2px 5px !default;
$u-badge-text-align: center !default;
$u-badge-text-color: #FFFFFF !default;
.u-badge {
border-top-right-radius: $u-badge-dot-radius;
border-top-left-radius: $u-badge-dot-radius;
border-bottom-left-radius: $u-badge-dot-radius;
border-bottom-right-radius: $u-badge-dot-radius;
@include flex;
line-height: $u-badge-text-font-size;
text-align: $u-badge-text-align;
font-size: $u-badge-text-font-size;
color: $u-badge-text-color;
&--dot {
height: $u-badge-dot-size;
width: $u-badge-dot-size;
}
&--inverted {
font-size: 13px;
}
&--not-dot {
padding: $u-badge-text-padding;
}
&--horn {
border-bottom-left-radius: 0;
}
&--primary {
background-color: $u-badge-primary;
}
&--primary--inverted {
color: $u-badge-primary;
}
&--error {
background-color: $u-badge-error;
}
&--error--inverted {
color: $u-badge-error;
}
&--success {
background-color: $u-badge-success;
}
&--success--inverted {
color: $u-badge-success;
}
&--info {
background-color: $u-badge-info;
}
&--info--inverted {
color: $u-badge-info;
}
&--warning {
background-color: $u-badge-warning;
}
&--warning--inverted {
color: $u-badge-warning;
}
}
</style>

View File

@ -0,0 +1,46 @@
$u-button-active-opacity:0.75 !default;
$u-button-loading-text-margin-left:4px !default;
$u-button-text-color: #FFFFFF !default;
$u-button-text-plain-error-color:$u-error !default;
$u-button-text-plain-warning-color:$u-warning !default;
$u-button-text-plain-success-color:$u-success !default;
$u-button-text-plain-info-color:$u-info !default;
$u-button-text-plain-primary-color:$u-primary !default;
.u-button {
&--active {
opacity: $u-button-active-opacity;
}
&--active--plain {
background-color: rgb(217, 217, 217);
}
&__loading-text {
margin-left:$u-button-loading-text-margin-left;
}
&__text,
&__loading-text {
color:$u-button-text-color;
}
&__text--plain--error {
color:$u-button-text-plain-error-color;
}
&__text--plain--warning {
color:$u-button-text-plain-warning-color;
}
&__text--plain--success{
color:$u-button-text-plain-success-color;
}
&__text--plain--info {
color:$u-button-text-plain-info-color;
}
&__text--plain--primary {
color:$u-button-text-plain-primary-color;
}
}

View File

@ -0,0 +1,161 @@
/*
* @Author : LQ
* @Description :
* @version : 1.0
* @Date : 2021-08-16 10:04:04
* @LastAuthor : LQ
* @lastTime : 2021-08-16 10:04:24
* @FilePath : /u-view2.0/uview-ui/components/u-button/props.js
*/
export default {
props: {
// 是否细边框
hairline: {
type: Boolean,
default: uni.$u.props.button.hairline
},
// 按钮的预置样式infoprimaryerrorwarningsuccess
type: {
type: String,
default: uni.$u.props.button.type
},
// 按钮尺寸largenormalsmallmini
size: {
type: String,
default: uni.$u.props.button.size
},
// 按钮形状circle两边为半圆square带圆角
shape: {
type: String,
default: uni.$u.props.button.shape
},
// 按钮是否镂空
plain: {
type: Boolean,
default: uni.$u.props.button.plain
},
// 是否禁止状态
disabled: {
type: Boolean,
default: uni.$u.props.button.disabled
},
// 是否加载中
loading: {
type: Boolean,
default: uni.$u.props.button.loading
},
// 加载中提示文字
loadingText: {
type: [String, Number],
default: uni.$u.props.button.loadingText
},
// 加载状态图标类型
loadingMode: {
type: String,
default: uni.$u.props.button.loadingMode
},
// 加载图标大小
loadingSize: {
type: [String, Number],
default: uni.$u.props.button.loadingSize
},
// 开放能力具体请看uniapp稳定关于button组件部分说明
// https://uniapp.dcloud.io/component/button
openType: {
type: String,
default: uni.$u.props.button.openType
},
// 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
// 取值为submit提交表单reset重置表单
formType: {
type: String,
default: uni.$u.props.button.formType
},
// 打开 APP 时,向 APP 传递的参数open-type=launchApp时有效
// 只微信小程序、QQ小程序有效
appParameter: {
type: String,
default: uni.$u.props.button.appParameter
},
// 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
hoverStopPropagation: {
type: Boolean,
default: uni.$u.props.button.hoverStopPropagation
},
// 指定返回用户信息的语言zh_CN 简体中文zh_TW 繁体中文en 英文。只微信小程序有效
lang: {
type: String,
default: uni.$u.props.button.lang
},
// 会话来源open-type="contact"时有效。只微信小程序有效
sessionFrom: {
type: String,
default: uni.$u.props.button.sessionFrom
},
// 会话内消息卡片标题open-type="contact"时有效
// 默认当前标题,只微信小程序有效
sendMessageTitle: {
type: String,
default: uni.$u.props.button.sendMessageTitle
},
// 会话内消息卡片点击跳转小程序路径open-type="contact"时有效
// 默认当前分享路径,只微信小程序有效
sendMessagePath: {
type: String,
default: uni.$u.props.button.sendMessagePath
},
// 会话内消息卡片图片open-type="contact"时有效
// 默认当前页面截图,只微信小程序有效
sendMessageImg: {
type: String,
default: uni.$u.props.button.sendMessageImg
},
// 是否显示会话内消息卡片,设置此参数为 true用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
// 用户点击后可以快速发送小程序消息open-type="contact"时有效
showMessageCard: {
type: Boolean,
default: uni.$u.props.button.showMessageCard
},
// 额外传参参数用于小程序的data-xxx属性通过target.dataset.name获取
dataName: {
type: String,
default: uni.$u.props.button.dataName
},
// 节流,一定时间内只能触发一次
throttleTime: {
type: [String, Number],
default: uni.$u.props.button.throttleTime
},
// 按住后多久出现点击态,单位毫秒
hoverStartTime: {
type: [String, Number],
default: uni.$u.props.button.hoverStartTime
},
// 手指松开后点击态保留时间,单位毫秒
hoverStayTime: {
type: [String, Number],
default: uni.$u.props.button.hoverStayTime
},
// 按钮文字之所以通过props传入是因为slot传入的话
// nvue中无法控制文字的样式
text: {
type: [String, Number],
default: uni.$u.props.button.text
},
// 按钮图标
icon: {
type: String,
default: uni.$u.props.button.icon
},
// 按钮图标
iconColor: {
type: String,
default: uni.$u.props.button.icon
},
// 按钮颜色支持传入linear-gradient渐变色
color: {
type: String,
default: uni.$u.props.button.color
}
}
}

View File

@ -0,0 +1,495 @@
<template>
<!-- #ifndef APP-NVUE -->
<button
:hover-start-time="Number(hoverStartTime)"
:hover-stay-time="Number(hoverStayTime)"
:form-type="formType"
:open-type="openType"
:app-parameter="appParameter"
:hover-stop-propagation="hoverStopPropagation"
:send-message-title="sendMessageTitle"
:send-message-path="sendMessagePath"
:lang="lang"
:data-name="dataName"
:session-from="sessionFrom"
:send-message-img="sendMessageImg"
:show-message-card="showMessageCard"
@getphonenumber="getphonenumber"
@getuserinfo="getuserinfo"
@error="error"
@opensetting="opensetting"
@launchapp="launchapp"
@agreeprivacyauthorization="agreeprivacyauthorization"
:hover-class="!disabled && !loading ? 'u-button--active' : ''"
class="u-button u-reset-button"
:style="[baseColor, $u.addStyle(customStyle)]"
@tap="clickHandler"
:class="bemClass"
>
<template v-if="loading">
<u-loading-icon
:mode="loadingMode"
:size="loadingSize * 1.15"
:color="loadingColor"
></u-loading-icon>
<text
class="u-button__loading-text"
:style="[{ fontSize: textSize + 'px' }]"
>{{ loadingText || text }}</text
>
</template>
<template v-else>
<u-icon
v-if="icon"
:name="icon"
:color="iconColorCom"
:size="textSize * 1.35"
:customStyle="{ marginRight: '2px' }"
></u-icon>
<slot>
<text
class="u-button__text"
:style="[{ fontSize: textSize + 'px' }]"
>{{ text }}</text
>
</slot>
</template>
</button>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<view
:hover-start-time="Number(hoverStartTime)"
:hover-stay-time="Number(hoverStayTime)"
class="u-button"
:hover-class="
!disabled && !loading && !color && (plain || type === 'info')
? 'u-button--active--plain'
: !disabled && !loading && !plain
? 'u-button--active'
: ''
"
@tap="clickHandler"
:class="bemClass"
:style="[baseColor, $u.addStyle(customStyle)]"
>
<template v-if="loading">
<u-loading-icon
:mode="loadingMode"
:size="loadingSize * 1.15"
:color="loadingColor"
></u-loading-icon>
<text
class="u-button__loading-text"
:style="[nvueTextStyle]"
:class="[plain && `u-button__text--plain--${type}`]"
>{{ loadingText || text }}</text
>
</template>
<template v-else>
<u-icon
v-if="icon"
:name="icon"
:color="iconColorCom"
:size="textSize * 1.35"
></u-icon>
<text
class="u-button__text"
:style="[
{
marginLeft: icon ? '2px' : 0,
},
nvueTextStyle,
]"
:class="[plain && `u-button__text--plain--${type}`]"
>{{ text }}</text
>
</template>
</view>
<!-- #endif -->
</template>
<script>
import button from "../../libs/mixin/button.js";
import openType from "../../libs/mixin/openType.js";
import props from "./props.js";
/**
* button 按钮
* @description Button 按钮
* @tutorial https://www.uviewui.com/components/button.html
*
* @property {Boolean} hairline 是否显示按钮的细边框 (默认 true )
* @property {String} type 按钮的预置样式infoprimaryerrorwarningsuccess (默认 'info' )
* @property {String} size 按钮尺寸largenormalmini 默认 normal
* @property {String} shape 按钮形状circle两边为半圆square带圆角 默认 'square'
* @property {Boolean} plain 按钮是否镂空背景色透明 默认 false
* @property {Boolean} disabled 是否禁用 默认 false
* @property {Boolean} loading 按钮名称前是否带 loading 图标(App-nvue 平台 ios 上为雪花Android上为圆圈) 默认 false
* @property {String | Number} loadingText 加载中提示文字
* @property {String} loadingMode 加载状态图标类型 默认 'spinner'
* @property {String | Number} loadingSize 加载图标大小 默认 15
* @property {String} openType 开放能力具体请看uniapp稳定关于button组件部分说明
* @property {String} formType 用于 <form> 组件点击分别会触发 <form> 组件的 submit/reset 事件
* @property {String} appParameter 打开 APP APP 传递的参数open-type=launchApp时有效 只微信小程序QQ小程序有效
* @property {Boolean} hoverStopPropagation 指定是否阻止本节点的祖先节点出现点击态微信小程序有效默认 true
* @property {String} lang 指定返回用户信息的语言zh_CN 简体中文zh_TW 繁体中文en 英文默认 en
* @property {String} sessionFrom 会话来源openType="contact"时有效
* @property {String} sendMessageTitle 会话内消息卡片标题openType="contact"时有效
* @property {String} sendMessagePath 会话内消息卡片点击跳转小程序路径openType="contact"时有效
* @property {String} sendMessageImg 会话内消息卡片图片openType="contact"时有效
* @property {Boolean} showMessageCard 是否显示会话内消息卡片设置此参数为 true用户进入客服会话会在右下角显示"可能要发送的小程序"提示用户点击后可以快速发送小程序消息openType="contact"时有效默认false
* @property {String} dataName 额外传参参数用于小程序的data-xxx属性通过target.dataset.name获取
* @property {String | Number} throttleTime 节流一定时间内只能触发一次 默认 0 )
* @property {String | Number} hoverStartTime 按住后多久出现点击态单位毫秒 默认 0 )
* @property {String | Number} hoverStayTime 手指松开后点击态保留时间单位毫秒 默认 200 )
* @property {String | Number} text 按钮文字之所以通过props传入是因为slot传入的话nvue中无法控制文字的样式
* @property {String} icon 按钮图标
* @property {String} iconColor 按钮图标颜色
* @property {String} color 按钮颜色支持传入linear-gradient渐变色
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} click 非禁止并且非加载中才能点击
* @event {Function} getphonenumber open-type="getPhoneNumber"时有效
* @event {Function} getuserinfo 用户点击该按钮时会返回获取到的用户信息从返回参数的detail中获取到的值同uni.getUserInfo
* @event {Function} error 当使用开放能力时发生错误的回调
* @event {Function} opensetting 在打开授权设置页并关闭后回调
* @event {Function} launchapp 打开 APP 成功的回调
* @event {Function} agreeprivacyauthorization 用户同意隐私协议事件回调
* @example <u-button>月落</u-button>
*/
export default {
name: "u-button",
// #ifdef MP
mixins: [uni.$u.mpMixin, uni.$u.mixin, button, openType, props],
// #endif
// #ifndef MP
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
// #endif
data() {
return {};
},
computed: {
// bem
bemClass() {
// this.bemcomputedmixin
if (!this.color) {
return this.bem(
"button",
["type", "shape", "size"],
["disabled", "plain", "hairline"]
);
} else {
// nvuecolortypetype
return this.bem(
"button",
["shape", "size"],
["disabled", "plain", "hairline"]
);
}
},
loadingColor() {
if (this.plain) {
// colorcolor使type
return this.color
? this.color
: uni.$u.config.color[`u-${this.type}`];
}
if (this.type === "info") {
return "#c9c9c9";
}
return "rgb(200, 200, 200)";
},
iconColorCom() {
// colorcolor使
// u-iconcolor
if (this.iconColor) return this.iconColor;
if (this.plain) {
return this.color ? this.color : this.type;
} else {
return this.type === "info" ? "#000000" : "#ffffff";
}
},
baseColor() {
let style = {};
if (this.color) {
// color
style.color = this.plain ? this.color : "white";
if (!this.plain) {
// 使
style["background-color"] = this.color;
}
if (this.color.indexOf("gradient") !== -1) {
// backgroundImage
// weexborderWidth
// weex西
style.borderTopWidth = 0;
style.borderRightWidth = 0;
style.borderBottomWidth = 0;
style.borderLeftWidth = 0;
if (!this.plain) {
style.backgroundImage = this.color;
}
} else {
//
style.borderColor = this.color;
style.borderWidth = "1px";
style.borderStyle = "solid";
}
}
return style;
},
// nvuetext
nvueTextStyle() {
let style = {};
// color
if (this.type === "info") {
style.color = "#323233";
}
if (this.color) {
style.color = this.plain ? this.color : "white";
}
style.fontSize = this.textSize + "px";
return style;
},
//
textSize() {
let fontSize = 14,
{ size } = this;
if (size === "large") fontSize = 16;
if (size === "normal") fontSize = 14;
if (size === "small") fontSize = 12;
if (size === "mini") fontSize = 10;
return fontSize;
},
},
methods: {
clickHandler() {
//
if (!this.disabled && !this.loading) {
// this.throttle
uni.$u.throttle(() => {
this.$emit("click");
}, this.throttleTime);
}
},
// uniapp
getphonenumber(res) {
this.$emit("getphonenumber", res);
},
getuserinfo(res) {
this.$emit("getuserinfo", res);
},
error(res) {
this.$emit("error", res);
},
opensetting(res) {
this.$emit("opensetting", res);
},
launchapp(res) {
this.$emit("launchapp", res);
},
agreeprivacyauthorization(res) {
this.$emit("agreeprivacyauthorization", res);
},
},
};
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
/* #ifndef APP-NVUE */
@import "./vue.scss";
/* #endif */
/* #ifdef APP-NVUE */
@import "./nvue.scss";
/* #endif */
$u-button-u-button-height: 40px !default;
$u-button-text-font-size: 15px !default;
$u-button-loading-text-font-size: 15px !default;
$u-button-loading-text-margin-left: 4px !default;
$u-button-large-width: 100% !default;
$u-button-large-height: 50px !default;
$u-button-normal-padding: 0 12px !default;
$u-button-large-padding: 0 15px !default;
$u-button-normal-font-size: 14px !default;
$u-button-small-min-width: 60px !default;
$u-button-small-height: 30px !default;
$u-button-small-padding: 0px 8px !default;
$u-button-mini-padding: 0px 8px !default;
$u-button-small-font-size: 12px !default;
$u-button-mini-height: 22px !default;
$u-button-mini-font-size: 10px !default;
$u-button-mini-min-width: 50px !default;
$u-button-disabled-opacity: 0.5 !default;
$u-button-info-color: #323233 !default;
$u-button-info-background-color: #fff !default;
$u-button-info-border-color: #ebedf0 !default;
$u-button-info-border-width: 1px !default;
$u-button-info-border-style: solid !default;
$u-button-success-color: #fff !default;
$u-button-success-background-color: $u-success !default;
$u-button-success-border-color: $u-button-success-background-color !default;
$u-button-success-border-width: 1px !default;
$u-button-success-border-style: solid !default;
$u-button-primary-color: #fff !default;
$u-button-primary-background-color: $u-primary !default;
$u-button-primary-border-color: $u-button-primary-background-color !default;
$u-button-primary-border-width: 1px !default;
$u-button-primary-border-style: solid !default;
$u-button-error-color: #fff !default;
$u-button-error-background-color: $u-error !default;
$u-button-error-border-color: $u-button-error-background-color !default;
$u-button-error-border-width: 1px !default;
$u-button-error-border-style: solid !default;
$u-button-warning-color: #fff !default;
$u-button-warning-background-color: $u-warning !default;
$u-button-warning-border-color: $u-button-warning-background-color !default;
$u-button-warning-border-width: 1px !default;
$u-button-warning-border-style: solid !default;
$u-button-block-width: 100% !default;
$u-button-circle-border-top-right-radius: 100px !default;
$u-button-circle-border-top-left-radius: 100px !default;
$u-button-circle-border-bottom-left-radius: 100px !default;
$u-button-circle-border-bottom-right-radius: 100px !default;
$u-button-square-border-top-right-radius: 3px !default;
$u-button-square-border-top-left-radius: 3px !default;
$u-button-square-border-bottom-left-radius: 3px !default;
$u-button-square-border-bottom-right-radius: 3px !default;
$u-button-icon-min-width: 1em !default;
$u-button-plain-background-color: #fff !default;
$u-button-hairline-border-width: 0.5px !default;
.u-button {
height: $u-button-u-button-height;
position: relative;
align-items: center;
justify-content: center;
@include flex;
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
flex-direction: row;
&__text {
font-size: $u-button-text-font-size;
}
&__loading-text {
font-size: $u-button-loading-text-font-size;
margin-left: $u-button-loading-text-margin-left;
}
&--large {
/* #ifndef APP-NVUE */
width: $u-button-large-width;
/* #endif */
height: $u-button-large-height;
padding: $u-button-large-padding;
}
&--normal {
padding: $u-button-normal-padding;
font-size: $u-button-normal-font-size;
}
&--small {
/* #ifndef APP-NVUE */
min-width: $u-button-small-min-width;
/* #endif */
height: $u-button-small-height;
padding: $u-button-small-padding;
font-size: $u-button-small-font-size;
}
&--mini {
height: $u-button-mini-height;
font-size: $u-button-mini-font-size;
/* #ifndef APP-NVUE */
min-width: $u-button-mini-min-width;
/* #endif */
padding: $u-button-mini-padding;
}
&--disabled {
opacity: $u-button-disabled-opacity;
}
&--info {
color: $u-button-info-color;
background-color: $u-button-info-background-color;
border-color: $u-button-info-border-color;
border-width: $u-button-info-border-width;
border-style: $u-button-info-border-style;
}
&--success {
color: $u-button-success-color;
background-color: $u-button-success-background-color;
border-color: $u-button-success-border-color;
border-width: $u-button-success-border-width;
border-style: $u-button-success-border-style;
}
&--primary {
color: $u-button-primary-color;
background-color: $u-button-primary-background-color;
border-color: $u-button-primary-border-color;
border-width: $u-button-primary-border-width;
border-style: $u-button-primary-border-style;
}
&--error {
color: $u-button-error-color;
background-color: $u-button-error-background-color;
border-color: $u-button-error-border-color;
border-width: $u-button-error-border-width;
border-style: $u-button-error-border-style;
}
&--warning {
color: $u-button-warning-color;
background-color: $u-button-warning-background-color;
border-color: $u-button-warning-border-color;
border-width: $u-button-warning-border-width;
border-style: $u-button-warning-border-style;
}
&--block {
@include flex;
width: $u-button-block-width;
}
&--circle {
border-top-right-radius: $u-button-circle-border-top-right-radius;
border-top-left-radius: $u-button-circle-border-top-left-radius;
border-bottom-left-radius: $u-button-circle-border-bottom-left-radius;
border-bottom-right-radius: $u-button-circle-border-bottom-right-radius;
}
&--square {
border-bottom-left-radius: $u-button-square-border-top-right-radius;
border-bottom-right-radius: $u-button-square-border-top-left-radius;
border-top-left-radius: $u-button-square-border-bottom-left-radius;
border-top-right-radius: $u-button-square-border-bottom-right-radius;
}
&__icon {
/* #ifndef APP-NVUE */
min-width: $u-button-icon-min-width;
line-height: inherit !important;
vertical-align: top;
/* #endif */
}
&--plain {
background-color: $u-button-plain-background-color;
}
&--hairline {
border-width: $u-button-hairline-border-width !important;
}
}
</style>

View File

@ -0,0 +1,80 @@
// nvuehover-class
$u-button-before-top:50% !default;
$u-button-before-left:50% !default;
$u-button-before-width:100% !default;
$u-button-before-height:100% !default;
$u-button-before-transform:translate(-50%, -50%) !default;
$u-button-before-opacity:0 !default;
$u-button-before-background-color:#000 !default;
$u-button-before-border-color:#000 !default;
$u-button-active-before-opacity:.15 !default;
$u-button-icon-margin-left:4px !default;
$u-button-plain-u-button-info-color:$u-info;
$u-button-plain-u-button-success-color:$u-success;
$u-button-plain-u-button-error-color:$u-error;
$u-button-plain-u-button-warning-color:$u-error;
.u-button {
width: 100%;
&__text {
white-space: nowrap;
line-height: 1;
}
&:before {
position: absolute;
top:$u-button-before-top;
left:$u-button-before-left;
width:$u-button-before-width;
height:$u-button-before-height;
border: inherit;
border-radius: inherit;
transform:$u-button-before-transform;
opacity:$u-button-before-opacity;
content: " ";
background-color:$u-button-before-background-color;
border-color:$u-button-before-border-color;
}
&--active {
&:before {
opacity: .15
}
}
&__icon+&__text:not(:empty),
&__loading-text {
margin-left:$u-button-icon-margin-left;
}
&--plain {
&.u-button--primary {
color: $u-primary;
}
}
&--plain {
&.u-button--info {
color:$u-button-plain-u-button-info-color;
}
}
&--plain {
&.u-button--success {
color:$u-button-plain-u-button-success-color;
}
}
&--plain {
&.u-button--error {
color:$u-button-plain-u-button-error-color;
}
}
&--plain {
&.u-button--warning {
color:$u-button-plain-u-button-warning-color;
}
}
}

View File

@ -0,0 +1,99 @@
<template>
<view class="u-calendar-header u-border-bottom">
<text
class="u-calendar-header__title"
v-if="showTitle"
>{{ title }}</text>
<text
class="u-calendar-header__subtitle"
v-if="showSubtitle"
>{{ subtitle }}</text>
<view class="u-calendar-header__weekdays">
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
<text class="u-calendar-header__weekdays__weekday"></text>
</view>
</view>
</template>
<script>
export default {
name: 'u-calendar-header',
mixins: [uni.$u.mpMixin, uni.$u.mixin],
props: {
//
title: {
type: String,
default: ''
},
//
subtitle: {
type: String,
default: ''
},
//
showTitle: {
type: Boolean,
default: true
},
//
showSubtitle: {
type: Boolean,
default: true
},
},
data() {
return {
}
},
methods: {
name() {
}
},
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-calendar-header {
padding-bottom: 4px;
&__title {
font-size: 16px;
color: $u-main-color;
text-align: center;
height: 42px;
line-height: 42px;
font-weight: bold;
}
&__subtitle {
font-size: 14px;
color: $u-main-color;
height: 40px;
text-align: center;
line-height: 40px;
font-weight: bold;
}
&__weekdays {
@include flex;
justify-content: space-between;
&__weekday {
font-size: 13px;
color: $u-main-color;
line-height: 30px;
flex: 1;
text-align: center;
}
}
}
</style>

View File

@ -0,0 +1,579 @@
<template>
<view class="u-calendar-month-wrapper" ref="u-calendar-month-wrapper">
<view v-for="(item, index) in months" :key="index" :class="[`u-calendar-month-${index}`]"
:ref="`u-calendar-month-${index}`" :id="`month-${index}`">
<text v-if="index !== 0" class="u-calendar-month__title">{{ item.year }}{{ item.month }}</text>
<view class="u-calendar-month__days">
<view v-if="showMark" class="u-calendar-month__days__month-mark-wrapper">
<text class="u-calendar-month__days__month-mark-wrapper__text">{{ item.month }}</text>
</view>
<view class="u-calendar-month__days__day" v-for="(item1, index1) in item.date" :key="index1"
:style="[dayStyle(index, index1, item1)]" @tap="clickHandler(index, index1, item1)"
:class="[item1.selected && 'u-calendar-month__days__day__select--selected']">
<view class="u-calendar-month__days__day__select" :style="[daySelectStyle(index, index1, item1)]">
<text class="u-calendar-month__days__day__select__info"
:class="[item1.disabled && 'u-calendar-month__days__day__select__info--disabled']"
:style="[textStyle(item1)]">{{ item1.day }}</text>
<text v-if="getBottomInfo(index, index1, item1)"
class="u-calendar-month__days__day__select__buttom-info"
:class="[item1.disabled && 'u-calendar-month__days__day__select__buttom-info--disabled']"
:style="[textStyle(item1)]">{{ getBottomInfo(index, index1, item1) }}</text>
<text v-if="item1.dot" class="u-calendar-month__days__day__select__dot"></text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
// #ifdef APP-NVUE
// nvue
const dom = uni.requireNativePlugin('dom')
// #endif
import dayjs from '../../libs/util/dayjs.js';
export default {
name: 'u-calendar-month',
mixins: [uni.$u.mpMixin, uni.$u.mixin],
props: {
//
showMark: {
type: Boolean,
default: true
},
//
color: {
type: String,
default: '#3c9cff'
},
//
months: {
type: Array,
default: () => []
},
//
mode: {
type: String,
default: 'single'
},
//
rowHeight: {
type: [String, Number],
default: 58
},
// mode=multiple
maxCount: {
type: [String, Number],
default: Infinity
},
// mode=range
startText: {
type: String,
default: '开始'
},
// mode=range
endText: {
type: String,
default: '结束'
},
// modemultiplerange
defaultDate: {
type: [Array, String, Date],
default: null
},
//
minDate: {
type: [String, Number],
default: 0
},
//
maxDate: {
type: [String, Number],
default: 0
},
// maxDate
maxMonth: {
type: [String, Number],
default: 2
},
//
readonly: {
type: Boolean,
default: uni.$u.props.calendar.readonly
},
// mode = range
maxRange: {
type: [Number, String],
default: Infinity
},
// mode = range
rangePrompt: {
type: String,
default: ''
},
// mode = range
showRangePrompt: {
type: Boolean,
default: true
},
// mode = range
allowSameDay: {
type: Boolean,
default: false
}
},
data() {
return {
//
width: 0,
// item
item: {},
selected: []
}
},
watch: {
selectedChange: {
immediate: true,
handler(n) {
this.setDefaultDate()
}
}
},
computed: {
//
selectedChange() {
return [this.minDate, this.maxDate, this.defaultDate]
},
dayStyle(index1, index2, item) {
return (index1, index2, item) => {
const style = {}
let week = item.week
// 2
const dayWidth = Number(parseFloat(this.width / 7).toFixed(3).slice(0, -1))
//
// #ifdef APP-NVUE
style.width = uni.$u.addUnit(dayWidth)
// #endif
style.height = uni.$u.addUnit(this.rowHeight)
if (index2 === 0) {
// 0item
week = (week === 0 ? 7 : week) - 1
style.marginLeft = uni.$u.addUnit(week * dayWidth)
}
if (this.mode === 'range') {
// DCloudiOSbug
style.paddingLeft = 0
style.paddingRight = 0
style.paddingBottom = 0
style.paddingTop = 0
}
return style
}
},
daySelectStyle() {
return (index1, index2, item) => {
let date = dayjs(item.date).format("YYYY-MM-DD"),
style = {}
// dateselected0使dateSameincludes
if (this.selected.some(item => this.dateSame(item, date))) {
style.backgroundColor = this.color
}
if (this.mode === 'single') {
if (date === this.selected[0]) {
// nvue
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
style.borderTopRightRadius = '3px'
style.borderBottomRightRadius = '3px'
}
} else if (this.mode === 'range') {
if (this.selected.length >= 2) {
const len = this.selected.length - 1
//
if (this.dateSame(date, this.selected[0])) {
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
}
//
if (this.dateSame(date, this.selected[len])) {
style.borderTopRightRadius = '3px'
style.borderBottomRightRadius = '3px'
}
//
if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
.selected[len]))) {
style.backgroundColor = uni.$u.colorGradient(this.color, '#ffffff', 100)[90]
// mark
style.opacity = 0.7
}
} else if (this.selected.length === 1) {
// DCloudiOSbug
// nvueiOSuni-appbug
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
}
} else {
if (this.selected.some(item => this.dateSame(item, date))) {
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
style.borderTopRightRadius = '3px'
style.borderBottomRightRadius = '3px'
}
}
return style
}
},
//
textStyle() {
return (item) => {
const date = dayjs(item.date).format("YYYY-MM-DD"),
style = {}
//
if (this.selected.some(item => this.dateSame(item, date))) {
style.color = '#ffffff'
}
if (this.mode === 'range') {
const len = this.selected.length - 1
//
if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
.selected[len]))) {
style.color = this.color
}
}
return style
}
},
//
getBottomInfo() {
return (index1, index2, item) => {
const date = dayjs(item.date).format("YYYY-MM-DD")
const bottomInfo = item.bottomInfo
// 0
if (this.mode === 'range' && this.selected.length > 0) {
if (this.selected.length === 1) {
//
if (this.dateSame(date, this.selected[0])) return this.startText
else return bottomInfo
} else {
const len = this.selected.length - 1
// 2
if (this.dateSame(date, this.selected[0]) && this.dateSame(date, this.selected[1]) &&
len === 1) {
// 2item
return `${this.startText}/${this.endText}`
} else if (this.dateSame(date, this.selected[0])) {
return this.startText
} else if (this.dateSame(date, this.selected[len])) {
return this.endText
} else {
return bottomInfo
}
}
} else {
return bottomInfo
}
}
}
},
mounted() {
this.init()
},
methods: {
init() {
//
this.$emit('monthSelected', this.selected)
this.$nextTick(() => {
//
// nvue$nextTick100%
uni.$u.sleep(10).then(() => {
this.getWrapperWidth()
this.getMonthRect()
})
})
},
//
dateSame(date1, date2) {
return dayjs(date1).isSame(dayjs(date2))
},
// nvuecssitem
getWrapperWidth() {
// #ifdef APP-NVUE
dom.getComponentRect(this.$refs['u-calendar-month-wrapper'], res => {
this.width = res.size.width
})
// #endif
// #ifndef APP-NVUE
this.$uGetRect('.u-calendar-month-wrapper').then(size => {
this.width = size.width
})
// #endif
},
getMonthRect() {
// scroll-view
const promiseAllArr = this.months.map((item, index) => this.getMonthRectByPromise(
`u-calendar-month-${index}`))
//
Promise.all(promiseAllArr).then(
sizes => {
let height = 1
const topArr = []
for (let i = 0; i < this.months.length; i++) {
// monthsscroll-view
topArr[i] = height
height += sizes[i].height
}
// this.months[i].top()monthtop使
this.$emit('updateMonthTop', topArr)
})
},
//
getMonthRectByPromise(el) {
// #ifndef APP-NVUE
// $uGetRectuViewhttps://www.uviewui.com/js/getRect.html
// this.$uGetRectuni.$u.getRect
return new Promise(resolve => {
this.$uGetRect(`.${el}`).then(size => {
resolve(size)
})
})
// #endif
// #ifdef APP-NVUE
// nvue使dom
// promise使then
return new Promise(resolve => {
dom.getComponentRect(this.$refs[el][0], res => {
resolve(res.size)
})
})
// #endif
},
//
clickHandler(index1, index2, item) {
if (this.readonly) {
return;
}
this.item = item
const date = dayjs(item.date).format("YYYY-MM-DD")
if (item.disabled) return
//
let selected = uni.$u.deepClone(this.selected)
if (this.mode === 'single') {
//
selected = [date]
} else if (this.mode === 'multiple') {
if (selected.some(item => this.dateSame(item, date))) {
//
const itemIndex = selected.findIndex(item => item === date)
selected.splice(itemIndex, 1)
} else {
//
if (selected.length < this.maxCount) selected.push(date)
}
} else {
//
if (selected.length === 0 || selected.length >= 2) {
// 02
selected = [date]
} else if (selected.length === 1) {
//
const existsDate = selected[0]
//
if (dayjs(date).isBefore(existsDate)) {
selected = [date]
} else if (dayjs(date).isAfter(existsDate)) {
//
if(dayjs(dayjs(date).subtract(this.maxRange, 'day')).isAfter(dayjs(selected[0])) && this.showRangePrompt) {
if(this.rangePrompt) {
uni.$u.toast(this.rangePrompt)
} else {
uni.$u.toast(`选择天数不能超过 ${this.maxRange}`)
}
return
}
//
selected.push(date)
const startDate = selected[0]
const endDate = selected[1]
const arr = []
let i = 0
do {
//
arr.push(dayjs(startDate).add(i, 'day').format("YYYY-MM-DD"))
i++
//
} while (dayjs(startDate).add(i, 'day').isBefore(dayjs(endDate)))
// computedarr
arr.push(endDate)
selected = arr
} else {
//
if (selected[0] === date && !this.allowSameDay) return
selected.push(date)
}
}
}
this.setSelected(selected)
},
//
setDefaultDate() {
if (!this.defaultDate) {
//
const selected = [dayjs().format("YYYY-MM-DD")]
return this.setSelected(selected, false)
}
let defaultDate = []
const minDate = this.minDate || dayjs().format("YYYY-MM-DD")
const maxDate = this.maxDate || dayjs(minDate).add(this.maxMonth - 1, 'month').format("YYYY-MM-DD")
if (this.mode === 'single') {
// Date
if (!uni.$u.test.array(this.defaultDate)) {
defaultDate = [dayjs(this.defaultDate).format("YYYY-MM-DD")]
} else {
defaultDate = [this.defaultDate[0]]
}
} else {
//
if (!uni.$u.test.array(this.defaultDate)) return
defaultDate = this.defaultDate
}
//
defaultDate = defaultDate.filter(item => {
return dayjs(item).isAfter(dayjs(minDate).subtract(1, 'day')) && dayjs(item).isBefore(dayjs(
maxDate).add(1, 'day'))
})
this.setSelected(defaultDate, false)
},
setSelected(selected, event = true) {
this.selected = selected
event && this.$emit('monthSelected', this.selected)
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-calendar-month-wrapper {
margin-top: 4px;
}
.u-calendar-month {
&__title {
font-size: 14px;
line-height: 42px;
height: 42px;
color: $u-main-color;
text-align: center;
font-weight: bold;
}
&__days {
position: relative;
@include flex;
flex-wrap: wrap;
&__month-mark-wrapper {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
@include flex;
justify-content: center;
align-items: center;
&__text {
font-size: 155px;
color: rgba(231, 232, 234, 0.83);
}
}
&__day {
@include flex;
padding: 2px;
/* #ifndef APP-NVUE */
// vue使cssjs
width: calc(100% / 7);
box-sizing: border-box;
/* #endif */
&__select {
flex: 1;
@include flex;
align-items: center;
justify-content: center;
position: relative;
&__dot {
width: 7px;
height: 7px;
border-radius: 100px;
background-color: $u-error;
position: absolute;
top: 12px;
right: 7px;
}
&__buttom-info {
color: $u-content-color;
text-align: center;
position: absolute;
bottom: 5px;
font-size: 10px;
text-align: center;
left: 0;
right: 0;
&--selected {
color: #ffffff;
}
&--disabled {
color: #cacbcd;
}
}
&__info {
text-align: center;
font-size: 16px;
&--selected {
color: #ffffff;
}
&--disabled {
color: #cacbcd;
}
}
&--selected {
background-color: $u-primary;
@include flex;
justify-content: center;
align-items: center;
flex: 1;
border-radius: 3px;
}
&--range-selected {
opacity: 0.3;
border-radius: 0;
}
&--range-start-selected {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&--range-end-selected {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
}
}
}
</style>

View File

@ -0,0 +1,144 @@
export default {
props: {
// 日历顶部标题
title: {
type: String,
default: uni.$u.props.calendar.title
},
// 是否显示标题
showTitle: {
type: Boolean,
default: uni.$u.props.calendar.showTitle
},
// 是否显示副标题
showSubtitle: {
type: Boolean,
default: uni.$u.props.calendar.showSubtitle
},
// 日期类型选择single-选择单个日期multiple-可以选择多个日期range-选择日期范围
mode: {
type: String,
default: uni.$u.props.calendar.mode
},
// mode=range时第一个日期底部的提示文字
startText: {
type: String,
default: uni.$u.props.calendar.startText
},
// mode=range时最后一个日期底部的提示文字
endText: {
type: String,
default: uni.$u.props.calendar.endText
},
// 自定义列表
customList: {
type: Array,
default: uni.$u.props.calendar.customList
},
// 主题色,对底部按钮和选中日期有效
color: {
type: String,
default: uni.$u.props.calendar.color
},
// 最小的可选日期
minDate: {
type: [String, Number],
default: uni.$u.props.calendar.minDate
},
// 最大可选日期
maxDate: {
type: [String, Number],
default: uni.$u.props.calendar.maxDate
},
// 默认选中的日期mode为multiple或range是必须为数组格式
defaultDate: {
type: [Array, String, Date, null],
default: uni.$u.props.calendar.defaultDate
},
// mode=multiple时最多可选多少个日期
maxCount: {
type: [String, Number],
default: uni.$u.props.calendar.maxCount
},
// 日期行高
rowHeight: {
type: [String, Number],
default: uni.$u.props.calendar.rowHeight
},
// 日期格式化函数
formatter: {
type: [Function, null],
default: uni.$u.props.calendar.formatter
},
// 是否显示农历
showLunar: {
type: Boolean,
default: uni.$u.props.calendar.showLunar
},
// 是否显示月份背景色
showMark: {
type: Boolean,
default: uni.$u.props.calendar.showMark
},
// 确定按钮的文字
confirmText: {
type: String,
default: uni.$u.props.calendar.confirmText
},
// 确认按钮处于禁用状态时的文字
confirmDisabledText: {
type: String,
default: uni.$u.props.calendar.confirmDisabledText
},
// 是否显示日历弹窗
show: {
type: Boolean,
default: uni.$u.props.calendar.show
},
// 是否允许点击遮罩关闭日历
closeOnClickOverlay: {
type: Boolean,
default: uni.$u.props.calendar.closeOnClickOverlay
},
// 是否为只读状态,只读状态下禁止选择日期
readonly: {
type: Boolean,
default: uni.$u.props.calendar.readonly
},
// 是否展示确认按钮
showConfirm: {
type: Boolean,
default: uni.$u.props.calendar.showConfirm
},
// 日期区间最多可选天数默认无限制mode = range时有效
maxRange: {
type: [Number, String],
default: uni.$u.props.calendar.maxRange
},
// 范围选择超过最多可选天数时的提示文案mode = range时有效
rangePrompt: {
type: String,
default: uni.$u.props.calendar.rangePrompt
},
// 范围选择超过最多可选天数时是否展示提示文案mode = range时有效
showRangePrompt: {
type: Boolean,
default: uni.$u.props.calendar.showRangePrompt
},
// 是否允许日期范围的起止时间为同一天mode = range时有效
allowSameDay: {
type: Boolean,
default: uni.$u.props.calendar.allowSameDay
},
// 圆角值
round: {
type: [Boolean, String, Number],
default: uni.$u.props.calendar.round
},
// 最多展示月份数量
monthNum: {
type: [Number, String],
default: 3
}
}
}

View File

@ -0,0 +1,384 @@
<template>
<u-popup
:show="show"
mode="bottom"
closeable
@close="close"
:round="round"
:closeOnClickOverlay="closeOnClickOverlay"
>
<view class="u-calendar">
<uHeader
:title="title"
:subtitle="subtitle"
:showSubtitle="showSubtitle"
:showTitle="showTitle"
></uHeader>
<scroll-view
:style="{
height: $u.addUnit(listHeight)
}"
scroll-y
@scroll="onScroll"
:scroll-top="scrollTop"
:scrollIntoView="scrollIntoView"
>
<uMonth
:color="color"
:rowHeight="rowHeight"
:showMark="showMark"
:months="months"
:mode="mode"
:maxCount="maxCount"
:startText="startText"
:endText="endText"
:defaultDate="defaultDate"
:minDate="innerMinDate"
:maxDate="innerMaxDate"
:maxMonth="monthNum"
:readonly="readonly"
:maxRange="maxRange"
:rangePrompt="rangePrompt"
:showRangePrompt="showRangePrompt"
:allowSameDay="allowSameDay"
ref="month"
@monthSelected="monthSelected"
@updateMonthTop="updateMonthTop"
></uMonth>
</scroll-view>
<slot name="footer" v-if="showConfirm">
<view class="u-calendar__confirm">
<u-button
shape="circle"
:text="
buttonDisabled ? confirmDisabledText : confirmText
"
:color="color"
@click="confirm"
:disabled="buttonDisabled"
></u-button>
</view>
</slot>
</view>
</u-popup>
</template>
<script>
import uHeader from './header.vue'
import uMonth from './month.vue'
import props from './props.js'
import util from './util.js'
import dayjs from '../../libs/util/dayjs.js'
import Calendar from '../../libs/util/calendar.js'
/**
* Calendar 日历
* @description 此组件用于单个选择日期范围选择日期等日历被包裹在底部弹起的容器中.
* @tutorial https://www.uviewui.com/components/calendar.html
*
* @property {String} title 标题内容 (默认 日期选择 )
* @property {Boolean} showTitle 是否显示标题 (默认 true )
* @property {Boolean} showSubtitle 是否显示副标题 (默认 true )
* @property {String} mode 日期类型选择 single-选择单个日期multiple-可以选择多个日期range-选择日期范围 默认 'single' )
* @property {String} startText mode=range时第一个日期底部的提示文字 (默认 '开始' )
* @property {String} endText mode=range时最后一个日期底部的提示文字 (默认 '结束' )
* @property {Array} customList 自定义列表
* @property {String} color 主题色对底部按钮和选中日期有效 (默认 #3c9cff' )
* @property {String | Number} minDate 最小的可选日期 (默认 0 )
* @property {String | Number} maxDate 最大可选日期 (默认 0 )
* @property {Array | String| Date} defaultDate 默认选中的日期mode为multiple或range是必须为数组格式
* @property {String | Number} maxCount mode=multiple时最多可选多少个日期 (默认 Number.MAX_SAFE_INTEGER )
* @property {String | Number} rowHeight 日期行高 (默认 56 )
* @property {Function} formatter 日期格式化函数
* @property {Boolean} showLunar 是否显示农历 (默认 false )
* @property {Boolean} showMark 是否显示月份背景色 (默认 true )
* @property {String} confirmText 确定按钮的文字 (默认 '确定' )
* @property {String} confirmDisabledText 确认按钮处于禁用状态时的文字 (默认 '确定' )
* @property {Boolean} show 是否显示日历弹窗 (默认 false )
* @property {Boolean} closeOnClickOverlay 是否允许点击遮罩关闭日历 (默认 false )
* @property {Boolean} readonly 是否为只读状态只读状态下禁止选择日期 (默认 false )
* @property {String | Number} maxRange 日期区间最多可选天数默认无限制mode = range时有效
* @property {String} rangePrompt 范围选择超过最多可选天数时的提示文案mode = range时有效
* @property {Boolean} showRangePrompt 范围选择超过最多可选天数时是否展示提示文案mode = range时有效 (默认 true )
* @property {Boolean} allowSameDay 是否允许日期范围的起止时间为同一天mode = range时有效 (默认 false )
* @property {Number|String} round 圆角值默认无圆角 (默认 0 )
* @property {Number|String} monthNum 最多展示的月份数量 (默认 3 )
*
* @event {Function()} confirm 点击确定按钮时触发 选择日期相关的返回参数
* @event {Function()} close 日历关闭时触发 可定义页面关闭时的回调事件
* @example <u-calendar :defaultDate="defaultDateMultiple" :show="show" mode="multiple" @confirm="confirm">
</u-calendar>
* */
export default {
name: 'u-calendar',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
components: {
uHeader,
uMonth
},
data() {
return {
//
months: [],
// index
monthIndex: 0,
//
listHeight: 0,
// month
selected: [],
scrollIntoView: '',
scrollTop:0,
//
innerFormatter: (value) => value
}
},
watch: {
selectedChange: {
immediate: true,
handler(n) {
this.setMonth()
}
},
//
show: {
immediate: true,
handler(n) {
this.setMonth()
}
}
},
computed: {
// maxDateminDate(2021-10-10)()dayjs
innerMaxDate() {
return uni.$u.test.number(this.maxDate)
? Number(this.maxDate)
: this.maxDate
},
innerMinDate() {
return uni.$u.test.number(this.minDate)
? Number(this.minDate)
: this.minDate
},
//
selectedChange() {
return [this.innerMinDate, this.innerMaxDate, this.defaultDate]
},
subtitle() {
// this.months
if (this.months.length) {
return `${this.months[this.monthIndex].year}${
this.months[this.monthIndex].month
}`
} else {
return ''
}
},
buttonDisabled() {
// range1disabled
if (this.mode === 'range') {
if (this.selected.length <= 1) {
return true
} else {
return false
}
} else {
return false
}
}
},
mounted() {
this.start = Date.now()
this.init()
},
methods: {
// propsref
setFormatter(e) {
this.innerFormatter = e
},
// month
monthSelected(e) {
this.selected = e
if (!this.showConfirm) {
// 2
if (
this.mode === 'multiple' ||
this.mode === 'single' ||
(this.mode === 'range' && this.selected.length >= 2)
) {
this.$emit('confirm', this.selected)
}
}
},
init() {
// maxDateminDate
if (
this.innerMaxDate &&
this.innerMinDate &&
new Date(this.innerMaxDate).getTime() < new Date(this.innerMinDate).getTime()
) {
return uni.$u.error('maxDate不能小于minDate')
}
//
this.listHeight = this.rowHeight * 5 + 30
this.setMonth()
},
close() {
this.$emit('close')
},
//
confirm() {
if (!this.buttonDisabled) {
this.$emit('confirm', this.selected)
}
},
//
getMonths(minDate, maxDate) {
const minYear = dayjs(minDate).year()
const minMonth = dayjs(minDate).month() + 1
const maxYear = dayjs(maxDate).year()
const maxMonth = dayjs(maxDate).month() + 1
return (maxYear - minYear) * 12 + (maxMonth - minMonth) + 1
},
//
setMonth() {
//
const minDate = this.innerMinDate || dayjs().valueOf()
// 3
const maxDate =
this.innerMaxDate ||
dayjs(minDate)
.add(this.monthNum - 1, 'month')
.valueOf()
//
const months = uni.$u.range(
1,
this.monthNum,
this.getMonths(minDate, maxDate)
)
//
this.months = []
for (let i = 0; i < months; i++) {
this.months.push({
date: new Array(
dayjs(minDate).add(i, 'month').daysInMonth()
)
.fill(1)
.map((item, index) => {
// 1-31
let day = index + 1
// 0-60
const week = dayjs(minDate)
.add(i, 'month')
.date(day)
.day()
const date = dayjs(minDate)
.add(i, 'month')
.date(day)
.format('YYYY-MM-DD')
let bottomInfo = ''
if (this.showLunar) {
//
const lunar = Calendar.solar2lunar(
dayjs(date).year(),
dayjs(date).month() + 1,
dayjs(date).date()
)
bottomInfo = lunar.IDayCn
}
let config = {
day,
week,
// disabled
disabled:
dayjs(date).isBefore(
dayjs(minDate).format('YYYY-MM-DD')
) ||
dayjs(date).isAfter(
dayjs(maxDate).format('YYYY-MM-DD')
),
// formatter
date: new Date(date),
bottomInfo,
dot: false,
month:
dayjs(minDate).add(i, 'month').month() + 1
}
const formatter =
this.formatter || this.innerFormatter
return formatter(config)
}),
//
month: dayjs(minDate).add(i, 'month').month() + 1,
//
year: dayjs(minDate).add(i, 'month').year()
})
}
},
//
scrollIntoDefaultMonth(selected) {
//
const _index = this.months.findIndex(({
year,
month
}) => {
month = uni.$u.padZero(month)
return `${year}-${month}` === selected
})
if (_index !== -1) {
// #ifndef MP-WEIXIN
this.$nextTick(() => {
this.scrollIntoView = `month-${_index}`
})
// #endif
// #ifdef MP-WEIXIN
this.scrollTop = this.months[_index].top || 0;
// #endif
}
},
// scroll-view
onScroll(event) {
// 0scroll-view
const scrollTop = Math.max(0, event.detail.scrollTop)
//
for (let i = 0; i < this.months.length; i++) {
if (scrollTop >= (this.months[i].top || this.listHeight)) {
this.monthIndex = i
}
}
},
// top
updateMonthTop(topArr = []) {
// toponScroll
topArr.map((item, index) => {
this.months[index].top = item
})
//
if (!this.defaultDate) {
//
const selected = dayjs().format("YYYY-MM")
this.scrollIntoDefaultMonth(selected)
return
}
let selected = dayjs().format("YYYY-MM");
// Date
if (!uni.$u.test.array(this.defaultDate)) {
selected = dayjs(this.defaultDate).format("YYYY-MM")
} else {
selected = dayjs(this.defaultDate[0]).format("YYYY-MM");
}
this.scrollIntoDefaultMonth(selected)
}
}
}
</script>
<style lang="scss" scoped>
@import '../../libs/css/components.scss';
.u-calendar {
&__confirm {
padding: 7px 18px;
}
}
</style>

View File

@ -0,0 +1,85 @@
export default {
methods: {
// 设置月份数据
setMonth() {
// 月初是周几
const day = dayjs(this.date).date(1).day()
const start = day == 0 ? 6 : day - 1
// 本月天数
const days = dayjs(this.date).endOf('month').format('D')
// 上个月天数
const prevDays = dayjs(this.date).endOf('month').subtract(1, 'month').format('D')
// 日期数据
const arr = []
// 清空表格
this.month = []
// 添加上月数据
arr.push(
...new Array(start).fill(1).map((e, i) => {
const day = prevDays - start + i + 1
return {
value: day,
disabled: true,
date: dayjs(this.date).subtract(1, 'month').date(day).format('YYYY-MM-DD')
}
})
)
// 添加本月数据
arr.push(
...new Array(days - 0).fill(1).map((e, i) => {
const day = i + 1
return {
value: day,
date: dayjs(this.date).date(day).format('YYYY-MM-DD')
}
})
)
// 添加下个月
arr.push(
...new Array(42 - days - start).fill(1).map((e, i) => {
const day = i + 1
return {
value: day,
disabled: true,
date: dayjs(this.date).add(1, 'month').date(day).format('YYYY-MM-DD')
}
})
)
// 分割数组
for (let n = 0; n < arr.length; n += 7) {
this.month.push(
arr.slice(n, n + 7).map((e, i) => {
e.index = i + n
// 自定义信息
const custom = this.customList.find((c) => c.date == e.date)
// 农历
if (this.lunar) {
const {
IDayCn,
IMonthCn
} = this.getLunar(e.date)
e.lunar = IDayCn == '初一' ? IMonthCn : IDayCn
}
return {
...e,
...custom
}
})
)
}
}
}
}

View File

@ -0,0 +1,14 @@
export default {
props: {
// 是否打乱键盘按键的顺序
random: {
type: Boolean,
default: false
},
// 输入一个中文后,是否自动切换到英文
autoChange: {
type: Boolean,
default: false
}
}
}

View File

@ -0,0 +1,311 @@
<template>
<view
class="u-keyboard"
@touchmove.stop.prevent="noop"
>
<view
v-for="(group, i) in abc ? engKeyBoardList : areaList"
:key="i"
class="u-keyboard__button"
:index="i"
:class="[i + 1 === 4 && 'u-keyboard__button--center']"
>
<view
v-if="i === 3"
class="u-keyboard__button__inner-wrapper"
>
<view
class="u-keyboard__button__inner-wrapper__left"
hover-class="u-hover-class"
:hover-stay-time="200"
@tap="changeCarInputMode"
>
<text
class="u-keyboard__button__inner-wrapper__left__lang"
:class="[!abc && 'u-keyboard__button__inner-wrapper__left__lang--active']"
></text>
<text class="u-keyboard__button__inner-wrapper__left__line">/</text>
<text
class="u-keyboard__button__inner-wrapper__left__lang"
:class="[abc && 'u-keyboard__button__inner-wrapper__left__lang--active']"
></text>
</view>
</view>
<view
class="u-keyboard__button__inner-wrapper"
v-for="(item, j) in group"
:key="j"
>
<view
class="u-keyboard__button__inner-wrapper__inner"
:hover-stay-time="200"
@tap="carInputClick(i, j)"
hover-class="u-hover-class"
>
<text class="u-keyboard__button__inner-wrapper__inner__text">{{ item }}</text>
</view>
</view>
<view
v-if="i === 3"
@touchstart="backspaceClick"
@touchend="clearTimer"
class="u-keyboard__button__inner-wrapper"
>
<view
class="u-keyboard__button__inner-wrapper__right"
hover-class="u-hover-class"
:hover-stay-time="200"
>
<u-icon
size="28"
name="backspace"
color="#303133"
></u-icon>
</view>
</view>
</view>
</view>
</template>
<script>
import props from './props.js';
/**
* keyboard 键盘组件
* @description 此为uView自定义的键盘面板内含了数字键盘车牌号键身份证号键盘3种模式都有可以打乱按键顺序的选项
* @tutorial https://uviewui.com/components/keyboard.html
* @property {Boolean} random 是否打乱键盘的顺序
* @event {Function} change 点击键盘触发
* @event {Function} backspace 点击退格键触发
* @example <u-keyboard ref="uKeyboard" mode="car" v-model="show"></u-keyboard>
*/
export default {
name: "u-keyboard",
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
// abc=truebac=false
abc: false
};
},
computed: {
areaList() {
let data = [
'京',
'沪',
'粤',
'津',
'冀',
'豫',
'云',
'辽',
'黑',
'湘',
'皖',
'鲁',
'苏',
'浙',
'赣',
'鄂',
'桂',
'甘',
'晋',
'陕',
'蒙',
'吉',
'闽',
'贵',
'渝',
'川',
'青',
'琼',
'宁',
'挂',
'藏',
'港',
'澳',
'新',
'使',
'学'
];
let tmp = [];
//
if (this.random) data = uni.$u.randomArray(data);
//
tmp[0] = data.slice(0, 10);
tmp[1] = data.slice(10, 20);
tmp[2] = data.slice(20, 30);
tmp[3] = data.slice(30, 36);
return tmp;
},
engKeyBoardList() {
let data = [
1,
2,
3,
4,
5,
6,
7,
8,
9,
0,
'Q',
'W',
'E',
'R',
'T',
'Y',
'U',
'I',
'O',
'P',
'A',
'S',
'D',
'F',
'G',
'H',
'J',
'K',
'L',
'Z',
'X',
'C',
'V',
'B',
'N',
'M'
];
let tmp = [];
if (this.random) data = uni.$u.randomArray(data);
tmp[0] = data.slice(0, 10);
tmp[1] = data.slice(10, 20);
tmp[2] = data.slice(20, 30);
tmp[3] = data.slice(30, 36);
return tmp;
}
},
methods: {
//
carInputClick(i, j) {
let value = '';
//
if (this.abc) value = this.engKeyBoardList[i][j];
else value = this.areaList[i][j];
//
if (!this.abc && this.autoChange) uni.$u.sleep(200).then(() => this.abc = true)
this.$emit('change', value);
},
// |
changeCarInputMode() {
this.abc = !this.abc;
},
// 退
backspaceClick() {
this.$emit('backspace');
clearInterval(this.timer); //
this.timer = null;
this.timer = setInterval(() => {
this.$emit('backspace');
}, 250);
},
clearTimer() {
clearInterval(this.timer);
this.timer = null;
},
}
};
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-car-keyboard-background-color: rgb(224, 228, 230) !default;
$u-car-keyboard-padding:6px 0 6px !default;
$u-car-keyboard-button-inner-width:64rpx !default;
$u-car-keyboard-button-inner-background-color:#FFFFFF !default;
$u-car-keyboard-button-height:80rpx !default;
$u-car-keyboard-button-inner-box-shadow:0 1px 0px #999992 !default;
$u-car-keyboard-button-border-radius:4px !default;
$u-car-keyboard-button-inner-margin:8rpx 5rpx !default;
$u-car-keyboard-button-text-font-size:16px !default;
$u-car-keyboard-button-text-color:$u-main-color !default;
$u-car-keyboard-center-inner-margin: 0 4rpx !default;
$u-car-keyboard-special-button-width:134rpx !default;
$u-car-keyboard-lang-font-size:16px !default;
$u-car-keyboard-lang-color:$u-main-color !default;
$u-car-keyboard-active-color:$u-primary !default;
$u-car-keyboard-line-font-size:15px !default;
$u-car-keyboard-line-color:$u-main-color !default;
$u-car-keyboard-line-margin:0 1px !default;
$u-car-keyboard-u-hover-class-background-color:#BBBCC6 !default;
.u-keyboard {
@include flex(column);
justify-content: space-around;
background-color: $u-car-keyboard-background-color;
align-items: stretch;
padding: $u-car-keyboard-padding;
&__button {
@include flex;
justify-content: center;
flex: 1;
/* #ifndef APP-NVUE */
/* #endif */
&__inner-wrapper {
box-shadow: $u-car-keyboard-button-inner-box-shadow;
margin: $u-car-keyboard-button-inner-margin;
border-radius: $u-car-keyboard-button-border-radius;
&__inner {
@include flex;
justify-content: center;
align-items: center;
width: $u-car-keyboard-button-inner-width;
background-color: $u-car-keyboard-button-inner-background-color;
height: $u-car-keyboard-button-height;
border-radius: $u-car-keyboard-button-border-radius;
&__text {
font-size: $u-car-keyboard-button-text-font-size;
color: $u-car-keyboard-button-text-color;
}
}
&__left,
&__right {
border-radius: $u-car-keyboard-button-border-radius;
width: $u-car-keyboard-special-button-width;
height: $u-car-keyboard-button-height;
background-color: $u-car-keyboard-u-hover-class-background-color;
@include flex;
justify-content: center;
align-items: center;
box-shadow: $u-car-keyboard-button-inner-box-shadow;
}
&__left {
&__line {
font-size: $u-car-keyboard-line-font-size;
color: $u-car-keyboard-line-color;
margin: $u-car-keyboard-line-margin;
}
&__lang {
font-size: $u-car-keyboard-lang-font-size;
color: $u-car-keyboard-lang-color;
&--active {
color: $u-car-keyboard-active-color;
}
}
}
}
}
}
.u-hover-class {
background-color: $u-car-keyboard-u-hover-class-background-color;
}
</style>

View File

@ -0,0 +1,299 @@
<template>
<view
class="u-card"
@tap.stop="click"
:class="{ 'u-border': border, 'u-card-full': full, 'u-card--border': borderRadius > 0 }"
:style="{
borderRadius: borderRadius + 'rpx',
margin: margin,
boxShadow: boxShadow
}"
>
<view
v-if="showHead"
class="u-card__head"
:style="[{padding: padding + 'rpx'}, headStyle]"
:class="{
'u-border-bottom': headBorderBottom
}"
@tap="headClick"
>
<view v-if="!$slots.head" class="u-flex u-row-between">
<view class="u-card__head--left u-flex u-line-1" v-if="title">
<image
:src="thumb"
class="u-card__head--left__thumb"
mode="aspectfull"
v-if="thumb"
:style="{
height: thumbWidth + 'rpx',
width: thumbWidth + 'rpx',
borderRadius: thumbCircle ? '100rpx' : '6rpx'
}"
></image>
<text
class="u-card__head--left__title u-line-1"
:style="{
fontSize: titleSize + 'rpx',
color: titleColor
}"
>
{{ title }}
</text>
</view>
<view class="u-card__head--right u-line-1" v-if="subTitle">
<text
class="u-card__head__title__text"
:style="{
fontSize: subTitleSize + 'rpx',
color: subTitleColor
}"
>
{{ subTitle }}
</text>
</view>
</view>
<slot name="head" v-else />
</view>
<view @tap="bodyClick" class="u-card__body" :style="[{padding: padding + 'rpx'}, bodyStyle]"><slot name="body" /></view>
<view
v-if="showFoot"
class="u-card__foot"
@tap="footClick"
:style="[{padding: $slots.foot ? padding + 'rpx' : 0}, footStyle]"
:class="{
'u-border-top': footBorderTop
}"
>
<slot name="foot" />
</view>
</view>
</template>
<script>
/**
* card 卡片
* @description 卡片组件一般用于多个列表条目且风格统一的场景
* @tutorial https://www.uviewui.com/components/card.html
* @property {Boolean} full 卡片与屏幕两侧是否留空隙默认false
* @property {String} title 头部左边的标题
* @property {String} title-color 标题颜色默认#303133
* @property {String | Number} title-size 标题字体大小单位rpx默认30
* @property {String} sub-title 头部右边的副标题
* @property {String} sub-title-color 副标题颜色默认#909399
* @property {String | Number} sub-title-size 副标题字体大小默认26
* @property {Boolean} border 是否显示边框默认true
* @property {String | Number} index 用于标识点击了第几个卡片
* @property {String} box-shadow 卡片外围阴影字符串形式默认none
* @property {String} margin 卡片与屏幕两边和上下元素的间距需带单位"30rpx 20rpx"默认30rpx
* @property {String | Number} border-radius 卡片整体的圆角值单位rpx默认16
* @property {Object} head-style 头部自定义样式对象形式
* @property {Object} body-style 中部自定义样式对象形式
* @property {Object} foot-style 底部自定义样式对象形式
* @property {Boolean} head-border-bottom 是否显示头部的下边框默认true
* @property {Boolean} foot-border-top 是否显示底部的上边框默认true
* @property {Boolean} show-head 是否显示头部默认true
* @property {Boolean} show-head 是否显示尾部默认true
* @property {String} thumb 缩略图路径如设置将显示在标题的左边不建议使用相对路径
* @property {String | Number} thumb-width 缩略图的宽度高等于宽单位rpx默认60
* @property {Boolean} thumb-circle 缩略图是否为圆形默认false
* @event {Function} click 整个卡片任意位置被点击时触发
* @event {Function} head-click 卡片头部被点击时触发
* @event {Function} body-click 卡片主体部分被点击时触发
* @event {Function} foot-click 卡片底部部分被点击时触发
* @example <u-card padding="30" title="card"></u-card>
*/
export default {
name: 'u-card',
props: {
//
full: {
type: Boolean,
default: false
},
//
title: {
type: String,
default: ''
},
//
titleColor: {
type: String,
default: '#303133'
},
// rpx
titleSize: {
type: [Number, String],
default: '30'
},
//
subTitle: {
type: String,
default: ''
},
//
subTitleColor: {
type: String,
default: '#909399'
},
// rpx
subTitleSize: {
type: [Number, String],
default: '26'
},
// full=false()
border: {
type: Boolean,
default: true
},
//
index: {
type: [Number, String, Object],
default: ''
},
// "30rpx 30rpx""20rpx 20rpx 30rpx 30rpx"
margin: {
type: String,
default: '30rpx'
},
// card
borderRadius: {
type: [Number, String],
default: '16'
},
//
headStyle: {
type: Object,
default() {
return {};
}
},
//
bodyStyle: {
type: Object,
default() {
return {};
}
},
//
footStyle: {
type: Object,
default() {
return {};
}
},
//
headBorderBottom: {
type: Boolean,
default: true
},
//
footBorderTop: {
type: Boolean,
default: true
},
//
thumb: {
type: String,
default: ''
},
// rpx
thumbWidth: {
type: [String, Number],
default: '60'
},
//
thumbCircle: {
type: Boolean,
default: false
},
// headbodyfoot
padding: {
type: [String, Number],
default: '30'
},
//
showHead: {
type: Boolean,
default: true
},
//
showFoot: {
type: Boolean,
default: true
},
//
boxShadow: {
type: String,
default: 'none'
}
},
data() {
return {};
},
methods: {
click() {
this.$emit('click', this.index);
},
headClick() {
this.$emit('head-click', this.index);
},
bodyClick() {
this.$emit('body-click', this.index);
},
footClick() {
this.$emit('foot-click', this.index);
}
}
};
</script>
<style lang="scss" scoped>
@import "../../libs/css/style.components.scss";
.u-card {
position: relative;
overflow: hidden;
font-size: 28rpx;
background-color: #ffffff;
box-sizing: border-box;
&-full {
// 0
margin-left: 0 !important;
margin-right: 0 !important;
width: 100%;
}
&--border:after {
border-radius: 16rpx;
}
&__head {
&--left {
color: $u-main-color;
&__thumb {
margin-right: 16rpx;
}
&__title {
max-width: 400rpx;
}
}
&--right {
color: $u-tips-color;
margin-left: 6rpx;
}
}
&__body {
color: $u-content-color;
}
&__foot {
color: $u-tips-color;
}
}
</style>

View File

@ -0,0 +1,14 @@
export default {
props: {
// 分组标题
title: {
type: String,
default: uni.$u.props.cellGroup.title
},
// 是否显示外边框
border: {
type: Boolean,
default: uni.$u.props.cellGroup.border
}
}
}

View File

@ -0,0 +1,61 @@
<template>
<view :style="[$u.addStyle(customStyle)]" :class="[customClass]" class="u-cell-group">
<view v-if="title" class="u-cell-group__title">
<slot name="title">
<text class="u-cell-group__title__text">{{ title }}</text>
</slot>
</view>
<view class="u-cell-group__wrapper">
<u-line v-if="border"></u-line>
<slot />
</view>
</view>
</template>
<script>
import props from './props.js';
/**
* cellGroup 单元格
* @description cell单元格一般用于一组列表的情况比如个人中心页设置页等
* @tutorial https://uviewui.com/components/cell.html
*
* @property {String} title 分组标题
* @property {Boolean} border 是否显示外边框 (默认 true )
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} click 点击cell列表时触发
* @example <u-cell-group title="设置喜好">
*/
export default {
name: 'u-cell-group',
mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-cell-group-title-padding: 16px 16px 8px !default;
$u-cell-group-title-font-size: 15px !default;
$u-cell-group-title-line-height: 16px !default;
$u-cell-group-title-color: $u-main-color !default;
.u-cell-group {
flex: 1;
&__title {
padding: $u-cell-group-title-padding;
&__text {
font-size: $u-cell-group-title-font-size;
line-height: $u-cell-group-title-line-height;
color: $u-cell-group-title-color;
}
}
&__wrapper {
position: relative;
}
}
</style>

View File

@ -0,0 +1,316 @@
<template>
<view
@tap="click"
class="u-cell"
:class="{ 'u-border-bottom': borderBottom, 'u-border-top': borderTop, 'u-col-center': center, 'u-cell--required': required }"
hover-stay-time="150"
:hover-class="hoverClass"
:style="{
backgroundColor: bgColor
}"
>
<u-icon :size="iconSize" :name="icon" v-if="icon" :custom-style="iconStyle" class="u-cell__left-icon-wrap"></u-icon>
<view class="u-flex" v-else>
<slot name="icon"></slot>
</view>
<view
class="u-cell_title"
:style="[
{
width: titleWidth ? titleWidth + 'rpx' : 'auto'
},
titleStyle
]"
>
<block v-if="title !== ''">{{ title }}</block>
<slot name="title" v-else></slot>
<view class="u-cell__label" v-if="label || $slots.label" :style="[labelStyle]">
<block v-if="label !== ''">{{ label }}</block>
<slot name="label" v-else></slot>
</view>
</view>
<view class="u-cell__value" :style="[valueStyle]">
<block class="u-cell__value" v-if="value !== ''">{{ value }}</block>
<slot v-else></slot>
</view>
<view class="u-flex u-cell_right" v-if="$slots['right-icon']">
<slot name="right-icon"></slot>
</view>
<u-icon v-if="arrow" name="arrow-right" :style="[arrowStyle]" class="u-icon-wrap u-cell__right-icon-wrap"></u-icon>
</view>
</template>
<script>
/**
* cellItem 单元格Item
* @description cell单元格一般用于一组列表的情况比如个人中心页设置页等搭配u-cell-group使用
* @tutorial https://www.uviewui.com/components/cell.html
* @property {String} title 左侧标题
* @property {String} icon 左侧图标名只支持uView内置图标见Icon 图标
* @property {Object} icon-style 左边图标的样式对象形式
* @property {String} value 右侧内容
* @property {String} label 标题下方的描述信息
* @property {Boolean} border-bottom 是否显示cell的下边框默认true
* @property {Boolean} border-top 是否显示cell的上边框默认false
* @property {Boolean} center 是否使内容垂直居中默认false
* @property {String} hover-class 是否开启点击反馈none为无效果默认true
* // @property {Boolean} border-gap border-bottomtrueCelltrue
* @property {Boolean} arrow 是否显示右侧箭头默认true
* @property {Boolean} required 箭头方向可选值默认right
* @property {Boolean} arrow-direction 是否显示左边表示必填的星号默认false
* @property {Object} title-style 标题样式对象形式
* @property {Object} value-style 右侧内容样式对象形式
* @property {Object} label-style 标题下方描述信息的样式对象形式
* @property {String} bg-color 背景颜色默认transparent
* @property {String Number} index 用于在click事件回调中返回标识当前是第几个Item
* @property {String Number} title-width 标题的宽度单位rpx
* @example <u-cell-item icon="integral-fill" title="会员等级" value="新版本"></u-cell-item>
*/
export default {
name: 'u-cell-item',
props: {
// (uView)src
icon: {
type: String,
default: ''
},
//
title: {
type: [String, Number],
default: ''
},
//
value: {
type: [String, Number],
default: ''
},
//
label: {
type: [String, Number],
default: ''
},
//
borderBottom: {
type: Boolean,
default: true
},
//
borderTop: {
type: Boolean,
default: false
},
// cellcell线线
// 1.4.0border-topborder-bottom
// borderGap: {
// type: Boolean,
// default: true
// },
// cellnone
hoverClass: {
type: String,
default: 'u-cell-hover'
},
//
arrow: {
type: Boolean,
default: true
},
//
center: {
type: Boolean,
default: false
},
//
required: {
type: Boolean,
default: false
},
// rpx
titleWidth: {
type: [Number, String],
default: ''
},
// right|up|downright
arrowDirection: {
type: String,
default: 'right'
},
//
titleStyle: {
type: Object,
default() {
return {};
}
},
//
valueStyle: {
type: Object,
default() {
return {};
}
},
//
labelStyle: {
type: Object,
default() {
return {};
}
},
//
bgColor: {
type: String,
default: 'transparent'
},
// cell
index: {
type: [String, Number],
default: ''
},
// 使lable
useLabelSlot: {
type: Boolean,
default: false
},
// rpxicon
iconSize: {
type: [Number, String],
default: 34
},
//
iconStyle: {
type: Object,
default() {
return {}
}
},
},
data() {
return {
};
},
computed: {
arrowStyle() {
let style = {};
if (this.arrowDirection == 'up') style.transform = 'rotate(-90deg)';
else if (this.arrowDirection == 'down') style.transform = 'rotate(90deg)';
else style.transform = 'rotate(0deg)';
return style;
}
},
methods: {
click() {
this.$emit('click', this.index);
}
}
};
</script>
<style lang="scss" scoped>
@import "../../libs/css/style.components.scss";
.u-cell {
@include vue-flex;
align-items: center;
position: relative;
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
width: 100%;
padding: 26rpx 32rpx;
font-size: 28rpx;
line-height: 54rpx;
color: $u-content-color;
background-color: #fff;
text-align: left;
}
.u-cell_title {
font-size: 28rpx;
}
.u-cell__left-icon-wrap {
margin-right: 10rpx;
font-size: 32rpx;
}
.u-cell__right-icon-wrap {
margin-left: 10rpx;
color: #969799;
font-size: 28rpx;
}
.u-cell__left-icon-wrap,
.u-cell__right-icon-wrap {
@include vue-flex;
align-items: center;
height: 48rpx;
}
.u-cell-border:after {
position: absolute;
/* #ifndef APP-NVUE */
box-sizing: border-box;
content: ' ';
pointer-events: none;
border-bottom: 1px solid $u-border-color;
/* #endif */
right: 0;
left: 0;
top: 0;
transform: scaleY(0.5);
}
.u-cell-border {
position: relative;
}
.u-cell__label {
margin-top: 6rpx;
font-size: 26rpx;
line-height: 36rpx;
color: $u-tips-color;
/* #ifndef APP-NVUE */
word-wrap: break-word;
/* #endif */
}
.u-cell__value {
overflow: hidden;
text-align: right;
/* #ifndef APP-NVUE */
vertical-align: middle;
/* #endif */
color: $u-tips-color;
font-size: 26rpx;
}
.u-cell__title,
.u-cell__value {
flex: 1;
}
.u-cell--required {
/* #ifndef APP-NVUE */
overflow: visible;
/* #endif */
@include vue-flex;
align-items: center;
}
.u-cell--required:before {
position: absolute;
/* #ifndef APP-NVUE */
content: '*';
/* #endif */
left: 8px;
margin-top: 4rpx;
font-size: 14px;
color: $u-type-error;
}
.u-cell_right {
line-height: 1;
}
</style>

View File

@ -0,0 +1,110 @@
export default {
props: {
// 标题
title: {
type: [String, Number],
default: uni.$u.props.cell.title
},
// 标题下方的描述信息
label: {
type: [String, Number],
default: uni.$u.props.cell.label
},
// 右侧的内容
value: {
type: [String, Number],
default: uni.$u.props.cell.value
},
// 左侧图标名称,或者图片链接(本地文件建议使用绝对地址)
icon: {
type: String,
default: uni.$u.props.cell.icon
},
// 是否禁用cell
disabled: {
type: Boolean,
default: uni.$u.props.cell.disabled
},
// 是否显示下边框
border: {
type: Boolean,
default: uni.$u.props.cell.border
},
// 内容是否垂直居中(主要是针对右侧的value部分)
center: {
type: Boolean,
default: uni.$u.props.cell.center
},
// 点击后跳转的URL地址
url: {
type: String,
default: uni.$u.props.cell.url
},
// 链接跳转的方式内部使用的是uView封装的route方法可能会进行拦截操作
linkType: {
type: String,
default: uni.$u.props.cell.linkType
},
// 是否开启点击反馈(表现为点击时加上灰色背景)
clickable: {
type: Boolean,
default: uni.$u.props.cell.clickable
},
// 是否展示右侧箭头并开启点击反馈
isLink: {
type: Boolean,
default: uni.$u.props.cell.isLink
},
// 是否显示表单状态下的必填星号(此组件可能会内嵌入input组件)
required: {
type: Boolean,
default: uni.$u.props.cell.required
},
// 右侧的图标箭头
rightIcon: {
type: String,
default: uni.$u.props.cell.rightIcon
},
// 右侧箭头的方向可选值为leftupdown
arrowDirection: {
type: String,
default: uni.$u.props.cell.arrowDirection
},
// 左侧图标样式
iconStyle: {
type: [Object, String],
default: () => {
return uni.$u.props.cell.iconStyle
}
},
// 右侧箭头图标的样式
rightIconStyle: {
type: [Object, String],
default: () => {
return uni.$u.props.cell.rightIconStyle
}
},
// 标题的样式
titleStyle: {
type: [Object, String],
default: () => {
return uni.$u.props.cell.titleStyle
}
},
// 单位元的大小可选值为large
size: {
type: String,
default: uni.$u.props.cell.size
},
// 点击cell是否阻止事件传播
stop: {
type: Boolean,
default: uni.$u.props.cell.stop
},
// 标识符cell被点击时返回
name: {
type: [Number, String],
default: uni.$u.props.cell.name
}
}
}

View File

@ -0,0 +1,229 @@
<template>
<view class="u-cell" :class="[customClass]" :style="[$u.addStyle(customStyle)]"
:hover-class="(!disabled && (clickable || isLink)) ? 'u-cell--clickable' : ''" :hover-stay-time="250"
@tap="clickHandler">
<view class="u-cell__body" :class="[ center && 'u-cell--center', size === 'large' && 'u-cell__body--large']">
<view class="u-cell__body__content">
<view class="u-cell__left-icon-wrap" v-if="$slots.icon || icon">
<slot name="icon" v-if="$slots.icon">
</slot>
<u-icon v-else :name="icon" :custom-style="iconStyle" :size="size === 'large' ? 22 : 18"></u-icon>
</view>
<view class="u-cell__title">
<slot name="title">
<text v-if="title" class="u-cell__title-text" :style="[titleTextStyle]"
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__title-text--large']">{{ title }}</text>
</slot>
<slot name="label">
<text class="u-cell__label" v-if="label"
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__label--large']">{{ label }}</text>
</slot>
</view>
</view>
<slot name="value">
<text class="u-cell__value"
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__value--large']"
v-if="!$u.test.empty(value)">{{ value }}</text>
</slot>
<view class="u-cell__right-icon-wrap" v-if="$slots['right-icon'] || isLink"
:class="[`u-cell__right-icon-wrap--${arrowDirection}`]">
<slot name="right-icon" v-if="$slots['right-icon']">
</slot>
<u-icon v-else :name="rightIcon" :custom-style="rightIconStyle" :color="disabled ? '#c8c9cc' : 'info'"
:size="size === 'large' ? 18 : 16"></u-icon>
</view>
</view>
<u-line v-if="border"></u-line>
</view>
</template>
<script>
import props from './props.js';
/**
* cell 单元格
* @description cell单元格一般用于一组列表的情况比如个人中心页设置页等
* @tutorial https://uviewui.com/components/cell.html
* @property {String | Number} title 标题
* @property {String | Number} label 标题下方的描述信息
* @property {String | Number} value 右侧的内容
* @property {String} icon 左侧图标名称或者图片链接(本地文件建议使用绝对地址)
* @property {Boolean} disabled 是否禁用cell
* @property {Boolean} border 是否显示下边框 (默认 true )
* @property {Boolean} center 内容是否垂直居中(主要是针对右侧的value部分) (默认 false )
* @property {String} url 点击后跳转的URL地址
* @property {String} linkType 链接跳转的方式内部使用的是uView封装的route方法可能会进行拦截操作 (默认 'navigateTo' )
* @property {Boolean} clickable 是否开启点击反馈(表现为点击时加上灰色背景) 默认 false
* @property {Boolean} isLink 是否展示右侧箭头并开启点击反馈 默认 false
* @property {Boolean} required 是否显示表单状态下的必填星号(此组件可能会内嵌入input组件) 默认 false
* @property {String} rightIcon 右侧的图标箭头 默认 'arrow-right'
* @property {String} arrowDirection 右侧箭头的方向可选值为leftupdown
* @property {Object | String} rightIconStyle 右侧箭头图标的样式
* @property {Object | String} titleStyle 标题的样式
* @property {Object | String} iconStyle 左侧图标样式
* @property {String} size 单位元的大小可选值为 largenormalmini
* @property {Boolean} stop 点击cell是否阻止事件传播 (默认 true )
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} click 点击cell列表时触发
* @example 该组件需要搭配cell-group组件使用见官方文档示例
*/
export default {
name: 'u-cell',
data() {
return {
}
},
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
computed: {
titleTextStyle() {
return uni.$u.addStyle(this.titleStyle)
}
},
methods: {
// cell
clickHandler(e) {
if (this.disabled) return
this.$emit('click', {
name: this.name
})
// url(propsmixin)
this.openPage()
//
this.stop && this.preventEvent(e)
},
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-cell-padding: 10px 15px !default;
$u-cell-font-size: 15px !default;
$u-cell-line-height: 24px !default;
$u-cell-color: $u-main-color !default;
$u-cell-icon-size: 16px !default;
$u-cell-title-font-size: 15px !default;
$u-cell-title-line-height: 22px !default;
$u-cell-title-color: $u-main-color !default;
$u-cell-label-font-size: 12px !default;
$u-cell-label-color: $u-tips-color !default;
$u-cell-label-line-height: 18px !default;
$u-cell-value-font-size: 14px !default;
$u-cell-value-color: $u-content-color !default;
$u-cell-clickable-color: $u-bg-color !default;
$u-cell-disabled-color: #c8c9cc !default;
$u-cell-padding-top-large: 13px !default;
$u-cell-padding-bottom-large: 13px !default;
$u-cell-value-font-size-large: 15px !default;
$u-cell-label-font-size-large: 14px !default;
$u-cell-title-font-size-large: 16px !default;
$u-cell-left-icon-wrap-margin-right: 4px !default;
$u-cell-right-icon-wrap-margin-left: 4px !default;
$u-cell-title-flex:1 !default;
$u-cell-label-margin-top:5px !default;
.u-cell {
&__body {
@include flex();
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
padding: $u-cell-padding;
font-size: $u-cell-font-size;
color: $u-cell-color;
// line-height: $u-cell-line-height;
align-items: center;
&__content {
@include flex(row);
align-items: center;
flex: 1;
}
&--large {
padding-top: $u-cell-padding-top-large;
padding-bottom: $u-cell-padding-bottom-large;
}
}
&__left-icon-wrap,
&__right-icon-wrap {
@include flex();
align-items: center;
// height: $u-cell-line-height;
font-size: $u-cell-icon-size;
}
&__left-icon-wrap {
margin-right: $u-cell-left-icon-wrap-margin-right;
}
&__right-icon-wrap {
margin-left: $u-cell-right-icon-wrap-margin-left;
transition: transform 0.3s;
&--up {
transform: rotate(-90deg);
}
&--down {
transform: rotate(90deg);
}
}
&__title {
flex: $u-cell-title-flex;
&-text {
font-size: $u-cell-title-font-size;
line-height: $u-cell-title-line-height;
color: $u-cell-title-color;
&--large {
font-size: $u-cell-title-font-size-large;
}
}
}
&__label {
margin-top: $u-cell-label-margin-top;
font-size: $u-cell-label-font-size;
color: $u-cell-label-color;
line-height: $u-cell-label-line-height;
&--large {
font-size: $u-cell-label-font-size-large;
}
}
&__value {
text-align: right;
font-size: $u-cell-value-font-size;
line-height: $u-cell-line-height;
color: $u-cell-value-color;
&--large {
font-size: $u-cell-value-font-size-large;
}
}
&--clickable {
background-color: $u-cell-clickable-color;
}
&--disabled {
color: $u-cell-disabled-color;
/* #ifndef APP-NVUE */
cursor: not-allowed;
/* #endif */
}
&--center {
align-items: center;
}
}
</style>

View File

@ -0,0 +1,82 @@
export default {
props: {
// 标识符
name: {
type: String,
default: uni.$u.props.checkboxGroup.name
},
// 绑定的值
value: {
type: Array,
default: uni.$u.props.checkboxGroup.value
},
// 形状circle-圆形square-方形
shape: {
type: String,
default: uni.$u.props.checkboxGroup.shape
},
// 是否禁用全部checkbox
disabled: {
type: Boolean,
default: uni.$u.props.checkboxGroup.disabled
},
// 选中状态下的颜色如设置此值将会覆盖parent的activeColor值
activeColor: {
type: String,
default: uni.$u.props.checkboxGroup.activeColor
},
// 未选中的颜色
inactiveColor: {
type: String,
default: uni.$u.props.checkboxGroup.inactiveColor
},
// 整个组件的尺寸默认px
size: {
type: [String, Number],
default: uni.$u.props.checkboxGroup.size
},
// 布局方式row-横向column-纵向
placement: {
type: String,
default: uni.$u.props.checkboxGroup.placement
},
// label的字体大小px单位
labelSize: {
type: [String, Number],
default: uni.$u.props.checkboxGroup.labelSize
},
// label的字体颜色
labelColor: {
type: [String],
default: uni.$u.props.checkboxGroup.labelColor
},
// 是否禁止点击文本操作
labelDisabled: {
type: Boolean,
default: uni.$u.props.checkboxGroup.labelDisabled
},
// 图标颜色
iconColor: {
type: String,
default: uni.$u.props.checkboxGroup.iconColor
},
// 图标的大小单位px
iconSize: {
type: [String, Number],
default: uni.$u.props.checkboxGroup.iconSize
},
// 勾选图标的对齐方式left-左边right-右边
iconPlacement: {
type: String,
default: uni.$u.props.checkboxGroup.iconPlacement
},
// 竖向配列时,是否显示下划线
borderBottom: {
type: Boolean,
default: uni.$u.props.checkboxGroup.borderBottom
}
}
}

View File

@ -0,0 +1,103 @@
<template>
<view
class="u-checkbox-group"
:class="bemClass"
>
<slot></slot>
</view>
</template>
<script>
import props from './props.js';
/**
* checkboxGroup 复选框组
* @description 复选框组件一般用于需要多个选择的场景该组件功能完整使用方便
* @tutorial https://www.uviewui.com/components/checkbox.html
* @property {String} name 标识符
* @property {Array} value 绑定的值
* @property {String} shape 形状circle-圆形square-方形 默认 'square'
* @property {Boolean} disabled 是否禁用全部checkbox 默认 false
* @property {String} activeColor 选中状态下的颜色如设置此值将会覆盖parent的activeColor值 默认 '#2979ff'
* @property {String} inactiveColor 未选中的颜色 默认 '#c8c9cc'
* @property {String | Number} size 整个组件的尺寸 单位px 默认 18
* @property {String} placement 布局方式row-横向column-纵向 默认 'row'
* @property {String | Number} labelSize label的字体大小px单位 默认 14
* @property {String} labelColor label的字体颜色 默认 '#303133'
* @property {Boolean} labelDisabled 是否禁止点击文本操作 (默认 false )
* @property {String} iconColor 图标颜色 默认 '#ffffff'
* @property {String | Number} iconSize 图标的大小单位px 默认 12
* @property {String} iconPlacement 勾选图标的对齐方式left-左边right-右边 默认 'left'
* @property {Boolean} borderBottom placement为row时是否显示下边框 默认 false
* @event {Function} change 任一个checkbox状态发生变化时触发回调为一个对象
* @event {Function} input 修改通过v-model绑定的值时触发回调为一个对象
* @example <u-checkbox-group></u-checkbox-group>
*/
export default {
name: 'u-checkbox-group',
mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
computed: {
// computedu-checkbox
// parentDatawatch(u-checkbox-group)
//
parentData() {
return [this.value, this.disabled, this.inactiveColor, this.activeColor, this.size, this.labelDisabled, this.shape,
this.iconSize, this.borderBottom, this.placement
]
},
bemClass() {
// this.bemcomputedmixin
return this.bem('checkbox-group', ['placement'])
},
},
watch: {
//
parentData() {
if (this.children.length) {
this.children.map(child => {
// (u-checkbox)init()
typeof(child.init) === 'function' && child.init()
})
}
},
},
data() {
return {
}
},
created() {
this.children = []
},
methods: {
// checkbox
unCheckedOther(childInstance) {
const values = []
this.children.map(child => {
// checkbox
if (child.isChecked) {
values.push(child.name)
}
})
//
this.$emit('change', values)
// v-model
this.$emit('input', values)
},
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-checkbox-group {
&--row {
@include flex;
}
&--column {
@include flex(column);
}
}
</style>

View File

@ -0,0 +1,69 @@
export default {
props: {
// checkbox的名称
name: {
type: [String, Number, Boolean],
default: uni.$u.props.checkbox.name
},
// 形状square为方形circle为圆型
shape: {
type: String,
default: uni.$u.props.checkbox.shape
},
// 整体的大小
size: {
type: [String, Number],
default: uni.$u.props.checkbox.size
},
// 是否默认选中
checked: {
type: Boolean,
default: uni.$u.props.checkbox.checked
},
// 是否禁用
disabled: {
type: [String, Boolean],
default: uni.$u.props.checkbox.disabled
},
// 选中状态下的颜色如设置此值将会覆盖parent的activeColor值
activeColor: {
type: String,
default: uni.$u.props.checkbox.activeColor
},
// 未选中的颜色
inactiveColor: {
type: String,
default: uni.$u.props.checkbox.inactiveColor
},
// 图标的大小单位px
iconSize: {
type: [String, Number],
default: uni.$u.props.checkbox.iconSize
},
// 图标颜色
iconColor: {
type: String,
default: uni.$u.props.checkbox.iconColor
},
// label提示文字因为nvue下直接slot进来的文字由于特殊的结构无法修改样式
label: {
type: [String, Number],
default: uni.$u.props.checkbox.label
},
// label的字体大小px单位
labelSize: {
type: [String, Number],
default: uni.$u.props.checkbox.labelSize
},
// label的颜色
labelColor: {
type: String,
default: uni.$u.props.checkbox.labelColor
},
// 是否禁止点击提示语选中复选框
labelDisabled: {
type: [String, Boolean],
default: uni.$u.props.checkbox.labelDisabled
}
}
}

View File

@ -0,0 +1,344 @@
<template>
<view
class="u-checkbox"
:style="[checkboxStyle]"
@tap.stop="wrapperClickHandler"
:class="[`u-checkbox-label--${parentData.iconPlacement}`, parentData.borderBottom && parentData.placement === 'column' && 'u-border-bottom']"
>
<view
class="u-checkbox__icon-wrap"
@tap.stop="iconClickHandler"
:class="iconClasses"
:style="[iconWrapStyle]"
>
<slot name="icon">
<u-icon
class="u-checkbox__icon-wrap__icon"
name="checkbox-mark"
:size="elIconSize"
:color="elIconColor"
/>
</slot>
</view>
<text
@tap.stop="labelClickHandler"
:style="{
color: elDisabled ? elInactiveColor : elLabelColor,
fontSize: elLabelSize,
lineHeight: elLabelSize
}"
>{{label}}</text>
</view>
</template>
<script>
import props from './props.js';
/**
* checkbox 复选框
* @description 复选框组件一般用于需要多个选择的场景该组件功能完整使用方便
* @tutorial https://uviewui.com/components/checkbox.html
* @property {String | Number | Boolean} name checkbox组件的标示符
* @property {String} shape 形状square为方形circle为圆型
* @property {String | Number} size 整体的大小
* @property {Boolean} checked 是否默认选中
* @property {String | Boolean} disabled 是否禁用
* @property {String} activeColor 选中状态下的颜色如设置此值将会覆盖parent的activeColor值
* @property {String} inactiveColor 未选中的颜色
* @property {String | Number} iconSize 图标的大小单位px
* @property {String} iconColor 图标颜色
* @property {String | Number} label label提示文字因为nvue下直接slot进来的文字由于特殊的结构无法修改样式
* @property {String} labelColor label的颜色
* @property {String | Number} labelSize label的字体大小px单位
* @property {String | Boolean} labelDisabled 是否禁止点击提示语选中复选框
* @property {Object} customStyle 定义需要用到的外部样式
*
* @event {Function} change 任一个checkbox状态发生变化时触发回调为一个对象
* @example <u-checkbox v-model="checked" :disabled="false"></u-checkbox>
*/
export default {
name: "u-checkbox",
mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
data() {
return {
isChecked: false,
// computed使this.parent.shape
// 使
parentData: {
iconSize: 12,
labelDisabled: null,
disabled: null,
shape: 'square',
activeColor: null,
inactiveColor: null,
size: 18,
value: null,
iconColor: null,
placement: 'row',
borderBottom: false,
iconPlacement: 'left'
}
}
},
computed: {
// u-raios-group
elDisabled() {
return this.disabled !== '' ? this.disabled : this.parentData.disabled !== null ? this.parentData.disabled : false;
},
// label
elLabelDisabled() {
return this.labelDisabled !== '' ? this.labelDisabled : this.parentData.labelDisabled !== null ? this.parentData.labelDisabled :
false;
},
// size21px
elSize() {
return this.size ? this.size : (this.parentData.size ? this.parentData.size : 21);
},
// 12px
elIconSize() {
return this.iconSize ? this.iconSize : (this.parentData.iconSize ? this.parentData.iconSize : 12);
},
//
elActiveColor() {
return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff');
},
//
elInactiveColor() {
return this.inactiveColor ? this.inactiveColor : (this.parentData.inactiveColor ? this.parentData.inactiveColor :
'#c8c9cc');
},
// label
elLabelColor() {
return this.labelColor ? this.labelColor : (this.parentData.labelColor ? this.parentData.labelColor : '#606266')
},
//
elShape() {
return this.shape ? this.shape : (this.parentData.shape ? this.parentData.shape : 'circle');
},
// label
elLabelSize() {
return uni.$u.addUnit(this.labelSize ? this.labelSize : (this.parentData.labelSize ? this.parentData.labelSize :
'15'))
},
elIconColor() {
const iconColor = this.iconColor ? this.iconColor : (this.parentData.iconColor ? this.parentData.iconColor :
'#ffffff');
//
if (this.elDisabled) {
// disabledcheckboxelInactiveColor
return this.isChecked ? this.elInactiveColor : 'transparent'
} else {
return this.isChecked ? iconColor : 'transparent'
}
},
iconClasses() {
let classes = []
//
classes.push('u-checkbox__icon-wrap--' + this.elShape)
if (this.elDisabled) {
classes.push('u-checkbox__icon-wrap--disabled')
}
if (this.isChecked && this.elDisabled) {
classes.push('u-checkbox__icon-wrap--disabled--checked')
}
// ","
// #ifdef MP-ALIPAY || MP-TOUTIAO
classes = classes.join(' ')
// #endif
return classes
},
iconWrapStyle() {
// checkbox
const style = {}
style.backgroundColor = this.isChecked && !this.elDisabled ? this.elActiveColor : '#ffffff'
style.borderColor = this.isChecked && !this.elDisabled ? this.elActiveColor : this.elInactiveColor
style.width = uni.$u.addUnit(this.elSize)
style.height = uni.$u.addUnit(this.elSize)
//
if (this.parentData.iconPlacement === 'right') {
style.marginRight = 0
}
return style
},
checkboxStyle() {
const style = {}
if (this.parentData.borderBottom && this.parentData.placement === 'row') {
uni.$u.error('检测到您将borderBottom设置为true需要同时将u-checkbox-group的placement设置为column才有效')
}
//
if (this.parentData.borderBottom && this.parentData.placement === 'column') {
style.paddingBottom = '8px'
}
return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
}
},
mounted() {
this.init()
},
methods: {
init() {
// provide/inject使created
this.updateParentData()
if (!this.parent) {
uni.$u.error('u-checkbox必须搭配u-checkbox-group组件使用')
}
// u-checkbox-groupvaluearray
if (this.checked) {
this.isChecked = true
} else if (uni.$u.test.array(this.parentData.value)) {
// this.name
this.isChecked = this.parentData.value.some(item => {
return item === this.name
})
}
},
updateParentData() {
this.getParentData('u-checkbox-group')
},
//
wrapperClickHandler(e) {
this.parentData.iconPlacement === 'right' && this.iconClickHandler(e)
},
//
iconClickHandler(e) {
this.preventEvent(e)
//
if (!this.elDisabled) {
this.setRadioCheckedStatus()
}
},
// label
labelClickHandler(e) {
this.preventEvent(e)
// label
if (!this.elLabelDisabled && !this.elDisabled) {
this.setRadioCheckedStatus()
}
},
emitEvent() {
this.$emit('change', this.isChecked)
// u-form
this.$nextTick(() => {
uni.$u.formValidate(this, 'change')
})
},
//
// checkedtrueu-checkbox
// u-checkboxcheckedfalse()
setRadioCheckedStatus() {
//
this.isChecked = !this.isChecked
this.emitEvent()
typeof this.parent.unCheckedOther === 'function' && this.parent.unCheckedOther(this)
}
},
watch:{
checked(){
this.isChecked = this.checked
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-checkbox-icon-wrap-margin-right:6px !default;
$u-checkbox-icon-wrap-font-size:6px !default;
$u-checkbox-icon-wrap-border-width:1px !default;
$u-checkbox-icon-wrap-border-color:#c8c9cc !default;
$u-checkbox-icon-wrap-icon-line-height:0 !default;
$u-checkbox-icon-wrap-circle-border-radius:100% !default;
$u-checkbox-icon-wrap-square-border-radius:3px !default;
$u-checkbox-icon-wrap-checked-color:#fff !default;
$u-checkbox-icon-wrap-checked-background-color:red !default;
$u-checkbox-icon-wrap-checked-border-color:#2979ff !default;
$u-checkbox-icon-wrap-disabled-background-color:#ebedf0 !default;
$u-checkbox-icon-wrap-disabled-checked-color:#c8c9cc !default;
$u-checkbox-label-margin-left:5px !default;
$u-checkbox-label-margin-right:12px !default;
$u-checkbox-label-color:$u-content-color !default;
$u-checkbox-label-font-size:15px !default;
$u-checkbox-label-disabled-color:#c8c9cc !default;
.u-checkbox {
/* #ifndef APP-NVUE */
@include flex(row);
/* #endif */
overflow: hidden;
flex-direction: row;
align-items: center;
&-label--left {
flex-direction: row
}
&-label--right {
flex-direction: row-reverse;
justify-content: space-between
}
&__icon-wrap {
/* #ifndef APP-NVUE */
box-sizing: border-box;
// nvueborder-color
transition-property: border-color, background-color, color;
transition-duration: 0.2s;
/* #endif */
color: $u-content-color;
@include flex;
align-items: center;
justify-content: center;
color: transparent;
text-align: center;
margin-right: $u-checkbox-icon-wrap-margin-right;
font-size: $u-checkbox-icon-wrap-font-size;
border-width: $u-checkbox-icon-wrap-border-width;
border-color: $u-checkbox-icon-wrap-border-color;
border-style: solid;
/* #ifdef MP-TOUTIAO */
// 0
&__icon {
line-height: $u-checkbox-icon-wrap-icon-line-height;
}
/* #endif */
&--circle {
border-radius: $u-checkbox-icon-wrap-circle-border-radius;
}
&--square {
border-radius: $u-checkbox-icon-wrap-square-border-radius;
}
&--checked {
color: $u-checkbox-icon-wrap-checked-color;
background-color: $u-checkbox-icon-wrap-checked-background-color;
border-color: $u-checkbox-icon-wrap-checked-border-color;
}
&--disabled {
background-color: $u-checkbox-icon-wrap-disabled-background-color !important;
}
&--disabled--checked {
color: $u-checkbox-icon-wrap-disabled-checked-color !important;
}
}
&__label {
/* #ifndef APP-NVUE */
word-wrap: break-word;
/* #endif */
margin-left: $u-checkbox-label-margin-left;
margin-right: $u-checkbox-label-margin-right;
color: $u-checkbox-label-color;
font-size: $u-checkbox-label-font-size;
&--disabled {
color: $u-checkbox-label-disabled-color;
}
}
}
</style>

View File

@ -0,0 +1,8 @@
export default {
props: {
percentage: {
type: [String, Number],
default: uni.$u.props.circleProgress.percentage
}
}
}

View File

@ -0,0 +1,198 @@
<template>
<view class="u-circle-progress">
<view class="u-circle-progress__left">
<view
class="u-circle-progress__left__circle"
:style="[leftSyle]"
ref="left-circle"
>
</view>
</view>
<view
class="u-circle-progress__right"
>
<view
class="u-circle-progress__right__circle"
ref="right-circle"
:style="[rightSyle]"
>
</view>
</view>
<view class="u-circle-progress__circle">
</view>
</view>
</template>
<script>
import props from './props.js';
// #ifdef APP-NVUE
const animation = uni.requireNativePlugin('animation')
// #endif
/**
* CircleProgress 圆形进度条 TODO: 待完善
* @description 展示操作或任务的当前进度比如上传文件是一个圆形的进度环
* @tutorial https://www.uviewui.com/components/circleProgress.html
* @property {String | Number} percentage 圆环进度百分比值为数值类型0-100 (默认 30 )
* @example
*/
export default {
name: 'u-circle-progress',
mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
data() {
return {
leftBorderColor: 'rgb(200, 200, 200)',
rightBorderColor: 'rgb(200, 200, 200)',
}
},
computed: {
leftSyle() {
const style = {}
style.borderTopColor = this.leftBorderColor
style.borderRightColor = this.leftBorderColor
return style
},
rightSyle() {
const style = {}
style.borderLeftColor = this.rightBorderColor
style.borderBottomColor = this.rightBorderColor
return style
}
},
mounted() {
uni.$u.sleep().then(() => {
this.rightBorderColor = 'rgb(66, 185, 131)'
// this.init()
})
},
methods: {
init() {
animation.transition(this.$refs['right-circle'].ref, {
styles: {
transform: 'rotate(45deg)',
transformOrigin: 'center center'
},
}, () => {
this.rightBorderColor = 'rgb(66, 185, 131)'
// animation.transition(this.$refs['right-circle'].ref, {
// styles: {
// transform: 'rotate(225deg)',
// transformOrigin: 'center center'
// },
// duration: 3000,
// }, () => {
// animation.transition(this.$refs['left-circle'].ref, {
// styles: {
// transform: 'rotate(45deg)',
// transformOrigin: 'center center'
// },
// }, () => {
// this.leftBorderColor = 'rgb(66, 185, 131)'
// animation.transition(this.$refs['left-circle'].ref, {
// styles: {
// transform: 'rotate(225deg)',
// transformOrigin: 'center center'
// },
// duration: 1500,
// }, () => {
// })
// })
// })
})
}
},
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-circle-progress {
@include flex(row);
position: relative;
border-radius: 100px;
height: 100px;
width: 100px;
// transform: rotate(0deg);
// background-color: rgb(66, 185, 131);
background-color: rgb(200, 200, 200);
overflow: hidden;
justify-content: space-between;
&__circle {
border-radius: 100px;
height: 90px;
width: 90px;
transform: translate(-50%, -50%);
background-color: rgb(255, 255, 255);
left: 50px;
top: 50px;
position: absolute;
}
&__left {
position: absolute;
left: 0;
width: 50px;
height: 100px;
overflow: hidden;
box-sizing: border-box;
// background-color: rgb(66, 185, 131);
// background-color: rgb(200, 200, 200);
// transform-origin: left center;
&__circle {
box-sizing: border-box;
// background-color: red;
border-left-color: transparent;
border-bottom-color: transparent;
border-top-left-radius: 50px;
border-top-right-radius: 50px;
border-bottom-right-radius: 50px;
// border-left-color: rgb(66, 185, 131);
// border-bottom-color: rgb(66, 185, 131);
border-top-color: rgb(66, 185, 131);
border-right-color: rgb(66, 185, 131);
border-width: 5px;
width: 100px;
height: 100px;
transform: rotate(225deg);
// border-radius: 100px;
}
}
&__right {
position: absolute;
right: 0;
width: 50px;
height: 100px;
overflow: hidden;
&__circle {
position: absolute;
right: 0;
box-sizing: border-box;
// background-color: red;
border-top-color: transparent;
border-right-color: transparent;
border-top-left-radius: 50px;
border-bottom-left-radius: 50px;
border-bottom-right-radius: 50px;
// border-left-color: rgb(66, 185, 131);
// border-bottom-color: rgb(66, 185, 131);
border-left-color: rgb(200, 200, 200);
border-bottom-color: rgb(200, 200, 200);
border-width: 5px;
width: 100px;
height: 100px;
transform: rotate(45deg);
transform-origin: center center;
// border-radius: 100px;
}
}
}
</style>

View File

@ -0,0 +1,79 @@
export default {
props: {
// 键盘弹起时,是否自动上推页面
adjustPosition: {
type: Boolean,
default: uni.$u.props.codeInput.adjustPosition
},
// 最大输入长度
maxlength: {
type: [String, Number],
default: uni.$u.props.codeInput.maxlength
},
// 是否用圆点填充
dot: {
type: Boolean,
default: uni.$u.props.codeInput.dot
},
// 显示模式box-盒子模式line-底部横线模式
mode: {
type: String,
default: uni.$u.props.codeInput.mode
},
// 是否细边框
hairline: {
type: Boolean,
default: uni.$u.props.codeInput.hairline
},
// 字符间的距离
space: {
type: [String, Number],
default: uni.$u.props.codeInput.space
},
// 预置值
value: {
type: [String, Number],
default: uni.$u.props.codeInput.value
},
// 是否自动获取焦点
focus: {
type: Boolean,
default: uni.$u.props.codeInput.focus
},
// 字体是否加粗
bold: {
type: Boolean,
default: uni.$u.props.codeInput.bold
},
// 字体颜色
color: {
type: String,
default: uni.$u.props.codeInput.color
},
// 字体大小
fontSize: {
type: [String, Number],
default: uni.$u.props.codeInput.fontSize
},
// 输入框的大小,宽等于高
size: {
type: [String, Number],
default: uni.$u.props.codeInput.size
},
// 是否隐藏原生键盘如果想用自定义键盘的话需设置此参数为true
disabledKeyboard: {
type: Boolean,
default: uni.$u.props.codeInput.disabledKeyboard
},
// 边框和线条颜色
borderColor: {
type: String,
default: uni.$u.props.codeInput.borderColor
},
// 是否禁止输入"."符号
disabledDot: {
type: Boolean,
default: uni.$u.props.codeInput.disabledDot
}
}
}

View File

@ -0,0 +1,252 @@
<template>
<view class="u-code-input">
<view
class="u-code-input__item"
:style="[itemStyle(index)]"
v-for="(item, index) in codeLength"
:key="index"
>
<view
class="u-code-input__item__dot"
v-if="dot && codeArray.length > index"
></view>
<text
v-else
:style="{
fontSize: $u.addUnit(fontSize),
fontWeight: bold ? 'bold' : 'normal',
color: color
}"
>{{codeArray[index]}}</text>
<view
class="u-code-input__item__line"
v-if="mode === 'line'"
:style="[lineStyle]"
></view>
<!-- #ifndef APP-PLUS -->
<view v-if="isFocus && codeArray.length === index" :style="{backgroundColor: color}" class="u-code-input__item__cursor"></view>
<!-- #endif -->
</view>
<input
:disabled="disabledKeyboard"
type="number"
:focus="focus"
:value="inputValue"
:maxlength="maxlength"
:adjustPosition="adjustPosition"
class="u-code-input__input"
@input="inputHandler"
:style="{
height: $u.addUnit(size)
}"
@focus="isFocus = true"
@blur="isFocus = false"
/>
</view>
</template>
<script>
import props from './props.js';
/**
* CodeInput 验证码输入
* @description 该组件一般用于验证用户短信验证码的场景也可以结合uView的键盘组件使用
* @tutorial https://www.uviewui.com/components/codeInput.html
* @property {String | Number} maxlength 最大输入长度 默认 6
* @property {Boolean} dot 是否用圆点填充 默认 false
* @property {String} mode 显示模式box-盒子模式line-底部横线模式 默认 'box'
* @property {Boolean} hairline 是否细边框 默认 false
* @property {String | Number} space 字符间的距离 默认 10
* @property {String | Number} value 预置值
* @property {Boolean} focus 是否自动获取焦点 默认 false
* @property {Boolean} bold 字体和输入横线是否加粗 默认 false
* @property {String} color 字体颜色 默认 '#606266'
* @property {String | Number} fontSize 字体大小单位px 默认 18
* @property {String | Number} size 输入框的大小宽等于高 默认 35
* @property {Boolean} disabledKeyboard 是否隐藏原生键盘如果想用自定义键盘的话需设置此参数为true 默认 false
* @property {String} borderColor 边框和线条颜色 默认 '#c9cacc'
* @property {Boolean} disabledDot 是否禁止输入"."符号 默认 true
*
* @event {Function} change 输入内容发生改变时触发具体见上方说明 value当前输入的值
* @event {Function} finish 输入字符个数达maxlength值时触发见上方说明 value当前输入的值
* @example <u-code-input v-model="value4" :focus="true"></u-code-input>
*/
export default {
name: 'u-code-input',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
inputValue: '',
isFocus: this.focus
}
},
watch: {
value: {
immediate: true,
handler(val) {
//
this.inputValue = String(val).substring(0, this.maxlength)
}
},
},
computed: {
// v-for
codeLength() {
return new Array(Number(this.maxlength))
},
// item
itemStyle() {
return index => {
const addUnit = uni.$u.addUnit
const style = {
width: addUnit(this.size),
height: addUnit(this.size)
}
//
if (this.mode === 'box') {
// 0.5px
style.border = `${this.hairline ? 0.5 : 1}px solid ${this.borderColor}`
// 0
if (uni.$u.getPx(this.space) === 0) {
//
if (index === 0) {
style.borderTopLeftRadius = '3px'
style.borderBottomLeftRadius = '3px'
}
if (index === this.codeLength.length - 1) {
style.borderTopRightRadius = '3px'
style.borderBottomRightRadius = '3px'
}
//
if (index !== this.codeLength.length - 1) {
style.borderRight = 'none'
}
}
}
if (index !== this.codeLength.length - 1) {
// margin-right
style.marginRight = addUnit(this.space)
} else {
//
style.marginRight = 0
}
return style
}
},
// item
codeArray() {
return String(this.inputValue).split('')
},
// 线线
lineStyle() {
const style = {}
style.height = this.hairline ? '2px' : '4px'
style.width = uni.$u.addUnit(this.size)
// 线
style.backgroundColor = this.borderColor
return style
}
},
methods: {
//
inputHandler(e) {
const value = e.detail.value
this.inputValue = value
// .
if(this.disabledDot) {
this.$nextTick(() => {
this.inputValue = value.replace('.', '')
})
}
// maxlengthchangefinish
this.$emit('change', value)
// v-model
this.$emit('input', value)
//
if (String(value).length >= Number(this.maxlength)) {
this.$emit('finish', value)
}
}
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
$u-code-input-cursor-width: 1px;
$u-code-input-cursor-height: 40%;
$u-code-input-cursor-animation-duration: 1s;
$u-code-input-cursor-animation-name: u-cursor-flicker;
.u-code-input {
@include flex;
position: relative;
overflow: hidden;
&__item {
@include flex;
justify-content: center;
align-items: center;
position: relative;
&__text {
font-size: 15px;
color: $u-content-color;
}
&__dot {
width: 7px;
height: 7px;
border-radius: 100px;
background-color: $u-content-color;
}
&__line {
position: absolute;
bottom: 0;
height: 4px;
border-radius: 100px;
width: 40px;
background-color: $u-content-color;
}
/* #ifndef APP-PLUS */
&__cursor {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: $u-code-input-cursor-width;
height: $u-code-input-cursor-height;
animation: $u-code-input-cursor-animation-duration u-cursor-flicker infinite;
}
/* #endif */
}
&__input {
// input
//
position: absolute;
left: -750rpx;
width: 1500rpx;
top: 0;
background-color: transparent;
text-align: left;
}
}
/* #ifndef APP-PLUS */
@keyframes u-cursor-flicker {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
100% {
opacity: 0;
}
}
/* #endif */
</style>

View File

@ -0,0 +1,34 @@
export default {
props: {
// 倒计时总秒数
seconds: {
type: [String, Number],
default: uni.$u.props.code.seconds
},
// 尚未开始时提示
startText: {
type: String,
default: uni.$u.props.code.startText
},
// 正在倒计时中的提示
changeText: {
type: String,
default: uni.$u.props.code.changeText
},
// 倒计时结束时的提示
endText: {
type: String,
default: uni.$u.props.code.endText
},
// 是否在H5刷新或各端返回再进入时继续倒计时
keepRunning: {
type: Boolean,
default: uni.$u.props.code.keepRunning
},
// 为了区分多个页面,或者一个页面多个倒计时组件本地存储的继续倒计时变了
uniqueKey: {
type: String,
default: uni.$u.props.code.uniqueKey
}
}
}

View File

@ -0,0 +1,129 @@
<template>
<view class="u-code">
<!-- 此组件功能由js完成无需写html逻辑 -->
</view>
</template>
<script>
import props from './props.js';
/**
* Code 验证码输入框
* @description 考虑到用户实际发送验证码的场景可能是一个按钮也可能是一段文字提示语各有不同所以本组件 不提供界面显示只提供提示语由用户将提示语嵌入到具体的场景
* @tutorial https://www.uviewui.com/components/code.html
* @property {String | Number} seconds 倒计时所需的秒数默认 60
* @property {String} startText 开始前的提示语见官网说明默认 '获取验证码'
* @property {String} changeText 倒计时期间的提示语必须带有字母"x"见官网说明默认 'X秒重新获取'
* @property {String} endText 倒计结束的提示语见官网说明默认 '重新获取'
* @property {Boolean} keepRunning 是否在H5刷新或各端返回再进入时继续倒计时 默认false
* @property {String} uniqueKey 为了区分多个页面或者一个页面多个倒计时组件本地存储的继续倒计时变了
*
* @event {Function} change 倒计时期间每秒触发一次
* @event {Function} start 开始倒计时触发
* @event {Function} end 结束倒计时触发
* @example <u-code ref="uCode" @change="codeChange" seconds="20"></u-code>
*/
export default {
name: "u-code",
mixins: [uni.$u.mpMixin, uni.$u.mixin,props],
data() {
return {
secNum: this.seconds,
timer: null,
canGetCode: true, //
}
},
mounted() {
this.checkKeepRunning()
},
watch: {
seconds: {
immediate: true,
handler(n) {
this.secNum = n
}
}
},
methods: {
checkKeepRunning() {
// 退(H5)
let lastTimestamp = Number(uni.getStorageSync(this.uniqueKey + '_$uCountDownTimestamp'))
if(!lastTimestamp) return this.changeEvent(this.startText)
//
let nowTimestamp = Math.floor((+ new Date()) / 1000)
//
if(this.keepRunning && lastTimestamp && lastTimestamp > nowTimestamp) {
//
this.secNum = lastTimestamp - nowTimestamp
//
uni.removeStorageSync(this.uniqueKey + '_$uCountDownTimestamp')
//
this.start()
} else {
//
this.changeEvent(this.startText)
}
},
//
start() {
//
if(this.timer) {
clearInterval(this.timer)
this.timer = null
}
this.$emit('start')
this.canGetCode = false
// setInterval1
this.changeEvent(this.changeText.replace(/x|X/, this.secNum))
this.timer = setInterval(() => {
if (--this.secNum) {
// "x"
this.changeEvent(this.changeText.replace(/x|X/, this.secNum))
} else {
clearInterval(this.timer)
this.timer = null
this.changeEvent(this.endText)
this.secNum = this.seconds
this.$emit('end')
this.canGetCode = true
}
}, 1000)
this.setTimeToStorage()
},
//
reset() {
this.canGetCode = true
clearInterval(this.timer)
this.secNum = this.seconds
this.changeEvent(this.endText)
},
changeEvent(text) {
this.$emit('change', text)
},
// H5
setTimeToStorage() {
if(!this.keepRunning || !this.timer) return
//
// 0
if(this.secNum > 0 && this.secNum <= this.seconds) {
// (+ new Date())1000
let nowTimestamp = Math.floor((+ new Date()) / 1000)
// => +
uni.setStorage({
key: this.uniqueKey + '_$uCountDownTimestamp',
data: nowTimestamp + Number(this.secNum)
})
}
}
},
//
beforeDestroy() {
this.setTimeToStorage()
clearTimeout(this.timer)
this.timer = null
}
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
</style>

View File

@ -0,0 +1,29 @@
export default {
props: {
// 占父容器宽度的多少等分总分为12份
span: {
type: [String, Number],
default: uni.$u.props.col.span
},
// 指定栅格左侧的间隔数(总12栏)
offset: {
type: [String, Number],
default: uni.$u.props.col.offset
},
// 水平排列方式,可选值为`start`(或`flex-start`)、`end`(或`flex-end`)、`center`、`around`(或`space-around`)、`between`(或`space-between`)
justify: {
type: String,
default: uni.$u.props.col.justify
},
// 垂直对齐方式可选值为top、center、bottom、stretch
align: {
type: String,
default: uni.$u.props.col.align
},
// 文字对齐方式
textAlign: {
type: String,
default: uni.$u.props.col.textAlign
}
}
}

View File

@ -0,0 +1,162 @@
<template>
<view
class="u-col"
ref="u-col"
:class="[
'u-col-' + span
]"
:style="[colStyle]"
@tap="clickHandler"
>
<slot></slot>
</view>
</template>
<script>
import props from './props.js';
/**
* CodeInput 栅格系统的列
* @description 该组件一般用于Layout 布局 通过基础的 12 分栏迅速简便地创建布局
* @tutorial https://www.uviewui.com/components/Layout.html
* @property {String | Number} span 栅格占据的列数总12等份 (默认 12 )
* @property {String | Number} offset 分栏左边偏移计算方式与span相同 (默认 0 )
* @property {String} justify 水平排列方式可选值为`start`(`flex-start`)`end`(`flex-end`)`center``around`(`space-around`)`between`(`space-between`) (默认 'start' )
* @property {String} align 垂直对齐方式可选值为topcenterbottomstretch (默认 'stretch' )
* @property {String} textAlign 文字水平对齐方式 (默认 'left' )
* @property {Object} customStyle 定义需要用到的外部样式
* @event {Function} click col被点击会阻止事件冒泡到row
* @example <u-col span="3" offset="3" > <view class="demo-layout bg-purple"></view> </u-col>
*/
export default {
name: 'u-col',
mixins: [uni.$u.mpMixin, uni.$u.mixin, props],
data() {
return {
width: 0,
parentData: {
gutter: 0
},
gridNum: 12
}
},
computed: {
uJustify() {
if (this.justify == 'end' || this.justify == 'start') return 'flex-' + this.justify
else if (this.justify == 'around' || this.justify == 'between') return 'space-' + this.justify
else return this.justify
},
uAlignItem() {
if (this.align == 'top') return 'flex-start'
if (this.align == 'bottom') return 'flex-end'
else return this.align
},
colStyle() {
const style = {
// "padding: 0 10px"nvue
paddingLeft: uni.$u.addUnit(uni.$u.getPx(this.parentData.gutter)/2),
paddingRight: uni.$u.addUnit(uni.$u.getPx(this.parentData.gutter)/2),
alignItems: this.uAlignItem,
justifyContent: this.uJustify,
textAlign: this.textAlign,
// #ifndef APP-NVUE
// nvue使
flex: `0 0 ${100 / this.gridNum * this.span}%`,
marginLeft: 100 / 12 * this.offset + '%',
// #endif
// #ifdef APP-NVUE
// nvue使
width: uni.$u.addUnit(Math.floor(this.width / this.gridNum * Number(this.span))),
marginLeft: uni.$u.addUnit(Math.floor(this.width / this.gridNum * Number(this.offset))),
// #endif
}
return uni.$u.deepMerge(style, uni.$u.addStyle(this.customStyle))
}
},
mounted() {
this.init()
},
methods: {
async init() {
// provide/inject使created
this.updateParentData()
this.width = await this.parent.getComponentWidth()
},
updateParentData() {
this.getParentData('u-row')
},
clickHandler(e) {
this.$emit('click');
}
},
}
</script>
<style lang="scss" scoped>
@import "../../libs/css/components.scss";
.u-col {
padding: 0;
/* #ifndef APP-NVUE */
box-sizing:border-box;
/* #endif */
/* #ifdef MP */
display: block;
/* #endif */
}
// nvue
/* #ifndef APP-NVUE */
.u-col-0 {
width: 0;
}
.u-col-1 {
width: calc(100%/12);
}
.u-col-2 {
width: calc(100%/12 * 2);
}
.u-col-3 {
width: calc(100%/12 * 3);
}
.u-col-4 {
width: calc(100%/12 * 4);
}
.u-col-5 {
width: calc(100%/12 * 5);
}
.u-col-6 {
width: calc(100%/12 * 6);
}
.u-col-7 {
width: calc(100%/12 * 7);
}
.u-col-8 {
width: calc(100%/12 * 8);
}
.u-col-9 {
width: calc(100%/12 * 9);
}
.u-col-10 {
width: calc(100%/12 * 10);
}
.u-col-11 {
width: calc(100%/12 * 11);
}
.u-col-12 {
width: calc(100%/12 * 12);
}
/* #endif */
</style>

Some files were not shown because too many files have changed in this diff Show More