feat:还原更新框架
This commit is contained in:
@@ -12,19 +12,7 @@
|
|||||||
|
|
||||||
## 说明
|
## 说明
|
||||||
|
|
||||||
【文档有广告,不喜勿入谢谢】
|
uview-plus,是uni-app全面兼容vue3/nvue/鸿蒙/uni-app-x的uni-app生态框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水。uview-plus是基于uView2.x移植的支持vue3的版本,感谢uView。
|
||||||
|
|
||||||
uview-plus,是uni-app全面兼容vue3/nvue/鸿蒙/uni-app-x(已经发布https://ext.dcloud.net.cn/plugin?name=uview-ultra)的uni-app生态框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水。uview-plus是基于uView2.x移植的支持vue3的版本,感谢uView。
|
|
||||||
|
|
||||||
## 版本
|
|
||||||
|
|
||||||
### uview-plus v3 (uni-app版本)
|
|
||||||
1. 保持选项式API,尽可能兼容原有uview2各种API,比如mixins,方便大家升级更容易;
|
|
||||||
2. 新手友好,保持原汁原味js,二次开发方便,未使用typescript重写,但带有独立的类型申明包;
|
|
||||||
|
|
||||||
### uview-ultra v4 (uni-app-x版本)
|
|
||||||
1. 尽可能保持原有组件的API一致,方便大家升级;
|
|
||||||
2. 使用uts + 组合式API架构级全新重构,但仍然保持源码的简易,不封装过于复杂,便于修改。
|
|
||||||
|
|
||||||
## 可视化设计
|
## 可视化设计
|
||||||
|
|
||||||
@@ -44,13 +32,7 @@ uview-plus现已推出免费可视化设计,可以方便的进行页面可视
|
|||||||
您可以通过**微信**扫码,查看最佳的演示效果。
|
您可以通过**微信**扫码,查看最佳的演示效果。
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
<img src="https://uview-plus.jiangruyi.com/common/h5_qrcode.png" width="220" height="220" >
|
||||||
| H5 | 微信小程序 | 安卓 | 鸿蒙Next(已上架) |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| <img src="https://uview-plus.jiangruyi.com/common/h5_qrcode.png" width="160" height="160" /> | <img src="https://uview-plus.jiangruyi.com/common/weixin_mini_qrcode.jpg" width="160" height="160" /> | <img src="https://uview-plus.jiangruyi.com/common/android_qrcode.png" width="160" height="160" /> | <img src="https://uview-plus.jiangruyi.com/common/hos_qrcode.jpg" width="160" height="160" /> |
|
|
||||||
<br>
|
|
||||||
<img src="https://uview-plus.jiangruyi.com/common/hos.png">
|
|
||||||
|
|
||||||
|
|
||||||
## 链接
|
## 链接
|
||||||
|
|
||||||
@@ -59,6 +41,9 @@ uview-plus现已推出免费可视化设计,可以方便的进行页面可视
|
|||||||
- [升级指南](https://uview-plus.jiangruyi.com/components/changeGuide.html)
|
- [升级指南](https://uview-plus.jiangruyi.com/components/changeGuide.html)
|
||||||
- [关于我们](https://uview-plus.jiangruyi.com/cooperation/about.html)
|
- [关于我们](https://uview-plus.jiangruyi.com/cooperation/about.html)
|
||||||
|
|
||||||
|
## 交流反馈
|
||||||
|
|
||||||
|
欢迎加入我们的QQ群交流反馈:[点此跳转](https://uview-plus.jiangruyi.com/components/addQQGroup.html)
|
||||||
|
|
||||||
## 关于PR
|
## 关于PR
|
||||||
|
|
||||||
@@ -87,4 +72,3 @@ uview-plus现已推出免费可视化设计,可以方便的进行页面可视
|
|||||||
## 版权信息
|
## 版权信息
|
||||||
uview-plus遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uview-plus应用到您的产品中。
|
uview-plus遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uview-plus应用到您的产品中。
|
||||||
|
|
||||||
Root 组件基于上游项目 `uni-ku/root` 二次开发,已按 MIT 要求保留其原始授权文件:`libs/root/LICENSE`。
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,109 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view class="u-action-sheet-data">
|
|
||||||
<view class="u-action-sheet-data__trigger">
|
|
||||||
<slot name="trigger"></slot>
|
|
||||||
<up-input
|
|
||||||
v-if="!$slots['trigger']"
|
|
||||||
:modelValue="current"
|
|
||||||
disabled
|
|
||||||
disabledColor="#ffffff"
|
|
||||||
:placeholder="title"
|
|
||||||
border="none"
|
|
||||||
></up-input>
|
|
||||||
<view @click="show = true"
|
|
||||||
class="u-action-sheet-data__trigger__cover"></view>
|
|
||||||
</view>
|
|
||||||
<up-action-sheet
|
|
||||||
:show="show"
|
|
||||||
:actions="options"
|
|
||||||
:title="title"
|
|
||||||
safeAreaInsetBottom
|
|
||||||
:description="description"
|
|
||||||
@close="show = false"
|
|
||||||
@select="select"
|
|
||||||
>
|
|
||||||
</up-action-sheet>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
modelValue: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
type: Array,
|
|
||||||
default: () => {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
valueKey: {
|
|
||||||
type: String,
|
|
||||||
default: 'value'
|
|
||||||
},
|
|
||||||
labelKey: {
|
|
||||||
type: String,
|
|
||||||
default: 'name'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
show: false,
|
|
||||||
current: '',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
if (this.modelValue) {
|
|
||||||
this.options.forEach((ele) => {
|
|
||||||
if (ele[this.valueKey] == this.modelValue) {
|
|
||||||
this.current = ele[this.labelKey]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['update:modelValue'],
|
|
||||||
watch: {
|
|
||||||
modelValue() {
|
|
||||||
this.options.forEach((ele) => {
|
|
||||||
if (ele[this.valueKey] == this.modelValue) {
|
|
||||||
this.current = ele[this.labelKey]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
hideKeyboard() {
|
|
||||||
uni.hideKeyboard()
|
|
||||||
},
|
|
||||||
select(e) {
|
|
||||||
this.$emit('update:modelValue', e[this.valueKey])
|
|
||||||
this.current = e[this.labelKey]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.u-action-sheet-data {
|
|
||||||
&__trigger {
|
|
||||||
position: relative;
|
|
||||||
&__cover {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-08-16 10:52:35
|
* @lastTime : 2021-08-20 16:44:35
|
||||||
* @FilePath : /uview-plus/libs/config/props/actionSheet.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/actionSheet.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// action-sheet组件
|
// action-sheet组件
|
||||||
@@ -14,8 +14,6 @@ export default {
|
|||||||
title: '',
|
title: '',
|
||||||
description: '',
|
description: '',
|
||||||
actions: [],
|
actions: [],
|
||||||
nameKey: 'name',
|
|
||||||
subnameKey: 'subnameKey',
|
|
||||||
index: '',
|
index: '',
|
||||||
cancelText: '',
|
cancelText: '',
|
||||||
closeOnClickAction: true,
|
closeOnClickAction: true,
|
||||||
|
|||||||
@@ -1,16 +1,6 @@
|
|||||||
/*
|
|
||||||
* @Author : LQ
|
|
||||||
* @Description :
|
|
||||||
* @version : 3.0
|
|
||||||
* @LastAuthor : jry
|
|
||||||
* @lastTime : 2025-08-16 10:52:35
|
|
||||||
* @FilePath : /uview-plus/libs/config/props/props.js
|
|
||||||
*/
|
|
||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import ActionSheetDefaultProps from './actionSheet'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(ActionSheetDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 操作菜单是否展示 (默认false)
|
// 操作菜单是否展示 (默认false)
|
||||||
@@ -33,16 +23,6 @@ export const props = defineMixin({
|
|||||||
type: Array,
|
type: Array,
|
||||||
default: () => defProps.actionSheet.actions
|
default: () => defProps.actionSheet.actions
|
||||||
},
|
},
|
||||||
// 选项名称key
|
|
||||||
nameKey: {
|
|
||||||
type: String,
|
|
||||||
default: () => defProps.actionSheet.nameKey
|
|
||||||
},
|
|
||||||
// 选项子名称key
|
|
||||||
subnameKey: {
|
|
||||||
type: String,
|
|
||||||
default: () => defProps.actionSheet.subnameKey
|
|
||||||
},
|
|
||||||
// 取消按钮的文字,不为空时显示按钮
|
// 取消按钮的文字,不为空时显示按钮
|
||||||
cancelText: {
|
cancelText: {
|
||||||
type: String,
|
type: String,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<u-popup
|
<u-popup
|
||||||
:show="show"
|
:show="show"
|
||||||
@@ -7,39 +8,32 @@
|
|||||||
:round="round"
|
:round="round"
|
||||||
>
|
>
|
||||||
<view class="u-action-sheet">
|
<view class="u-action-sheet">
|
||||||
<!-- 顶部标题区域 -->
|
|
||||||
<view
|
<view
|
||||||
class="u-action-sheet__header"
|
class="u-action-sheet__header"
|
||||||
v-if="title"
|
v-if="title"
|
||||||
>
|
>
|
||||||
<text
|
<text class="u-action-sheet__header__title u-line-1">{{title}}</text>
|
||||||
class="u-action-sheet__header__title u-line-1"
|
|
||||||
:style="titleDynamicStyle"
|
|
||||||
>{{title}}</text>
|
|
||||||
<view
|
<view
|
||||||
class="u-action-sheet__header__icon-wrap"
|
class="u-action-sheet__header__icon-wrap"
|
||||||
@tap.stop="cancel"
|
@tap.stop="cancel"
|
||||||
>
|
>
|
||||||
<up-icon
|
<u-icon
|
||||||
name="close"
|
name="close"
|
||||||
size="17"
|
size="17"
|
||||||
:color="closeIconColor"
|
color="#c8c9cc"
|
||||||
bold
|
bold
|
||||||
></up-icon>
|
></u-icon>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<!-- 描述信息 -->
|
|
||||||
<text
|
<text
|
||||||
class="u-action-sheet__description"
|
class="u-action-sheet__description"
|
||||||
:style="[{
|
:style="[{
|
||||||
marginTop: `${title && description ? 0 : '18px'}`
|
marginTop: `${title && description ? 0 : '18px'}`
|
||||||
}, descriptionDynamicStyle]"
|
}]"
|
||||||
v-if="description"
|
v-if="description"
|
||||||
>{{description}}</text>
|
>{{description}}</text>
|
||||||
<slot>
|
<slot>
|
||||||
<!-- 分割线 -->
|
<u-line v-if="description"></u-line>
|
||||||
<u-line v-if="description" :color="dividerColor"></u-line>
|
|
||||||
<!-- 操作项列表 -->
|
|
||||||
<scroll-view scroll-y class="u-action-sheet__item-wrap" :style="{maxHeight: wrapMaxHeight}">
|
<scroll-view scroll-y class="u-action-sheet__item-wrap" :style="{maxHeight: wrapMaxHeight}">
|
||||||
<view :key="index" v-for="(item, index) in actions">
|
<view :key="index" v-for="(item, index) in actions">
|
||||||
<!-- #ifdef MP -->
|
<!-- #ifdef MP -->
|
||||||
@@ -68,20 +62,17 @@
|
|||||||
@tap.stop="selectHandler(index)"
|
@tap.stop="selectHandler(index)"
|
||||||
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
|
:hover-class="!item.disabled && !item.loading ? 'u-action-sheet--hover' : ''"
|
||||||
:hover-stay-time="150"
|
:hover-stay-time="150"
|
||||||
:style="getItemHoverStyle(index)"
|
|
||||||
>
|
>
|
||||||
<template v-if="!item.loading">
|
<template v-if="!item.loading">
|
||||||
<text
|
<text
|
||||||
class="u-action-sheet__item-wrap__item__name"
|
class="u-action-sheet__item-wrap__item__name"
|
||||||
:style="[itemStyle(index)]"
|
:style="[itemStyle(index)]"
|
||||||
>{{ item[nameKey] }}</text>
|
>{{ item.name }}</text>
|
||||||
<text
|
<text
|
||||||
v-if="item[subnameKey]"
|
v-if="item.subname"
|
||||||
class="u-action-sheet__item-wrap__item__subname"
|
class="u-action-sheet__item-wrap__item__subname"
|
||||||
:style="[subnameStyle(index)]"
|
>{{ item.subname }}</text>
|
||||||
>{{ item[subnameKey] }}</text>
|
|
||||||
</template>
|
</template>
|
||||||
<!-- 加载状态图标 -->
|
|
||||||
<u-loading-icon
|
<u-loading-icon
|
||||||
v-else
|
v-else
|
||||||
custom-class="van-action-sheet__loading"
|
custom-class="van-action-sheet__loading"
|
||||||
@@ -92,25 +83,21 @@
|
|||||||
<!-- #ifdef MP -->
|
<!-- #ifdef MP -->
|
||||||
</button>
|
</button>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<!-- 选项间分割线 -->
|
<u-line v-if="index !== actions.length - 1"></u-line>
|
||||||
<u-line v-if="index !== actions.length - 1" :color="dividerColor"></u-line>
|
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
</slot>
|
</slot>
|
||||||
<!-- 取消按钮前的分割区域 -->
|
|
||||||
<u-gap
|
<u-gap
|
||||||
:bgColor="cancelGapColor"
|
bgColor="#eaeaec"
|
||||||
height="6"
|
height="6"
|
||||||
v-if="cancelText"
|
v-if="cancelText"
|
||||||
></u-gap>
|
></u-gap>
|
||||||
<!-- 取消按钮 -->
|
|
||||||
<view class="u-action-sheet__item-wrap__item u-action-sheet__cancel"
|
<view class="u-action-sheet__item-wrap__item u-action-sheet__cancel"
|
||||||
hover-class="u-action-sheet--hover" @tap="cancel" v-if="cancelText">
|
hover-class="u-action-sheet--hover" @tap="cancel" v-if="cancelText">
|
||||||
<text
|
<text
|
||||||
@touchmove.stop.prevent
|
@touchmove.stop.prevent
|
||||||
:hover-stay-time="150"
|
:hover-stay-time="150"
|
||||||
class="u-action-sheet__cancel-text"
|
class="u-action-sheet__cancel-text"
|
||||||
:style="cancelTextDynamicStyle"
|
|
||||||
>{{cancelText}}</text>
|
>{{cancelText}}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -127,7 +114,7 @@
|
|||||||
/**
|
/**
|
||||||
* ActionSheet 操作菜单
|
* ActionSheet 操作菜单
|
||||||
* @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
|
* @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/actionSheet.html
|
* @tutorial https://ijry.github.io/uview-plus/components/actionSheet.html
|
||||||
*
|
*
|
||||||
* @property {Boolean} show 操作菜单是否展示 (默认 false )
|
* @property {Boolean} show 操作菜单是否展示 (默认 false )
|
||||||
* @property {String} title 操作菜单标题
|
* @property {String} title 操作菜单标题
|
||||||
@@ -167,54 +154,20 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
titleDynamicStyle() {
|
|
||||||
return {
|
|
||||||
color: this.upThemeVar('--up-main-color', '#303133')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
descriptionDynamicStyle() {
|
|
||||||
return {
|
|
||||||
color: this.upThemeVar('--up-tips-color', '#909193')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
closeIconColor() {
|
|
||||||
return this.upThemeVar('--up-content-color', '#606266')
|
|
||||||
},
|
|
||||||
dividerColor() {
|
|
||||||
return this.upThemeVar('--up-border-color', this.upThemeIsDark ? '#3a3a3c' : '#dadbde')
|
|
||||||
},
|
|
||||||
cancelGapColor() {
|
|
||||||
return this.upThemeVar('--up-gap-bg-color', this.upThemeIsDark ? '#111111' : '#eaeaec')
|
|
||||||
},
|
|
||||||
cancelTextDynamicStyle() {
|
|
||||||
return {
|
|
||||||
color: this.upThemeVar('--up-main-color', '#303133')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 操作项目的样式
|
// 操作项目的样式
|
||||||
itemStyle() {
|
itemStyle() {
|
||||||
return (index) => {
|
return (index) => {
|
||||||
const style = {
|
let style = {};
|
||||||
color: this.upThemeVar('--up-main-color', '#303133')
|
|
||||||
};
|
|
||||||
if (this.actions[index].color) style.color = this.actions[index].color
|
if (this.actions[index].color) style.color = this.actions[index].color
|
||||||
if (this.actions[index].fontSize) style.fontSize = addUnit(this.actions[index].fontSize)
|
if (this.actions[index].fontSize) style.fontSize = addUnit(this.actions[index].fontSize)
|
||||||
// 选项被禁用的样式
|
// 选项被禁用的样式
|
||||||
if (this.actions[index].disabled) style.color = this.upThemeVar('--up-light-color', '#c0c4cc')
|
if (this.actions[index].disabled) style.color = '#c0c4cc'
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
subnameStyle() {
|
|
||||||
return (index) => ({
|
|
||||||
color: this.actions[index].disabled
|
|
||||||
? this.upThemeVar('--up-light-color', '#c0c4cc')
|
|
||||||
: this.upThemeVar('--up-tips-color', '#909193')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
emits: ["close", "select", "update:show"],
|
emits: ["close", "select", "update:show"],
|
||||||
methods: {
|
methods: {
|
||||||
// 关闭操作菜单事件处理
|
|
||||||
closeHandler() {
|
closeHandler() {
|
||||||
// 允许点击遮罩关闭时,才发出close事件
|
// 允许点击遮罩关闭时,才发出close事件
|
||||||
if(this.closeOnClickOverlay) {
|
if(this.closeOnClickOverlay) {
|
||||||
@@ -227,7 +180,6 @@
|
|||||||
this.$emit('update:show', false)
|
this.$emit('update:show', false)
|
||||||
this.$emit('close')
|
this.$emit('close')
|
||||||
},
|
},
|
||||||
// 选择操作项处理
|
|
||||||
selectHandler(index) {
|
selectHandler(index) {
|
||||||
const item = this.actions[index]
|
const item = this.actions[index]
|
||||||
if (item && !item.disabled && !item.loading) {
|
if (item && !item.disabled && !item.loading) {
|
||||||
@@ -238,39 +190,30 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 动态处理Hover时候第一个item的圆角
|
|
||||||
getItemHoverStyle(index) {
|
|
||||||
if (index === 0 && this.round && !this.title && !this.description) {
|
|
||||||
return {
|
|
||||||
borderTopLeftRadius: `${this.round}px`,
|
|
||||||
borderTopRightRadius: `${this.round}px`,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return {}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
$u-action-sheet-reset-button-width:100% !default;
|
$u-action-sheet-reset-button-width:100% !default;
|
||||||
$u-action-sheet-title-font-size: 16px !default;
|
$u-action-sheet-title-font-size: 16px !default;
|
||||||
$u-action-sheet-title-padding: 12px 30px !default;
|
$u-action-sheet-title-padding: 12px 30px !default;
|
||||||
$u-action-sheet-title-color: var(--up-main-color, #303133) !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-right:15px !default;
|
||||||
$u-action-sheet-header-icon-wrap-top:15px !default;
|
$u-action-sheet-header-icon-wrap-top:15px !default;
|
||||||
$u-action-sheet-description-font-size:13px !default;
|
$u-action-sheet-description-font-size:13px !default;
|
||||||
$u-action-sheet-description-color: var(--up-tips-color, #909193) !default;
|
$u-action-sheet-description-color:14px !default;
|
||||||
$u-action-sheet-description-margin: 18px 15px !default;
|
$u-action-sheet-description-margin: 18px 15px !default;
|
||||||
$u-action-sheet-item-wrap-item-padding:17px !default;
|
$u-action-sheet-item-wrap-item-padding:17px !default;
|
||||||
$u-action-sheet-item-wrap-name-font-size:16px !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-font-size:13px !default;
|
||||||
$u-action-sheet-item-wrap-subname-color: var(--up-tips-color, #909193) !default;
|
$u-action-sheet-item-wrap-subname-color: #c0c4cc !default;
|
||||||
$u-action-sheet-item-wrap-subname-margin-top:10px !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-font-size:16px !default;
|
||||||
$u-action-sheet-cancel-text-color: var(--up-main-color, #303133) !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-font-size:15px !default;
|
||||||
$u-action-sheet-cancel-text-hover-background-color: var(--up-hover-bg-color, rgb(242, 243, 245)) !default;
|
$u-action-sheet-cancel-text-hover-background-color:rgb(242, 243, 245) !default;
|
||||||
|
|
||||||
.u-reset-button {
|
.u-reset-button {
|
||||||
width: $u-action-sheet-reset-button-width;
|
width: $u-action-sheet-reset-button-width;
|
||||||
@@ -296,9 +239,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__description {
|
&__description {
|
||||||
display: block;
|
|
||||||
font-size: $u-action-sheet-description-font-size;
|
font-size: $u-action-sheet-description-font-size;
|
||||||
color: $u-action-sheet-description-color;
|
color: $u-tips-color;
|
||||||
margin: $u-action-sheet-description-margin;
|
margin: $u-action-sheet-description-margin;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@@ -314,7 +256,7 @@
|
|||||||
|
|
||||||
&__name {
|
&__name {
|
||||||
font-size: $u-action-sheet-item-wrap-name-font-size;
|
font-size: $u-action-sheet-item-wrap-name-font-size;
|
||||||
color: var(--up-main-color, #303133);
|
color: $u-main-color;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
<style scoped lang="scss">
|
|
||||||
.agreement-content {
|
|
||||||
width: 100%;;
|
|
||||||
display: inline-block;
|
|
||||||
flex-direction: column;
|
|
||||||
color: var(--up-main-color, #303133);
|
|
||||||
.agreement-url {
|
|
||||||
display: inline-block;
|
|
||||||
color: var(--up-primary, #2979ff);
|
|
||||||
// #ifdef H5
|
|
||||||
cursor: pointer;
|
|
||||||
// #endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<view class="up-agreement">
|
|
||||||
<up-modal v-model:show="show" showCancelButton @confirm="confirm" @cancel="close" confirmText="阅读并同意">
|
|
||||||
<view class="agreement-content">
|
|
||||||
<slot>
|
|
||||||
我们非常重视您的个人信息和隐私保护。为了更好地保障您的个人权益,在您使用我们的产品前,
|
|
||||||
请务必审慎阅读《<text class="agreement-url" @click="urlClick('urlProtocol')">用户协议</text>》
|
|
||||||
和《<text class="agreement-url" @click="urlClick('urlPrivacy')">隐私政策</text>》内的所有条款,
|
|
||||||
尤其是:1.我们对您的个人信息的收集/保存/使用/对外提供/保护等规则条款,以及您的用户权利等条款;2. 约定我们的限制责任、免责
|
|
||||||
条款;3.其他以颜色或加粗进行标识的重要条款。如您对以上协议有任何疑问,请先不要同意,您点击“同意并继续”的行为即表示您已阅读
|
|
||||||
完毕并同意以上协议的全部内容。
|
|
||||||
</slot>
|
|
||||||
</view>
|
|
||||||
</up-modal>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'up-agreement',
|
|
||||||
props: {
|
|
||||||
urlProtocol: {
|
|
||||||
type: String,
|
|
||||||
default: '/pages/user_agreement/agreement/info?title=用户协议'
|
|
||||||
},
|
|
||||||
urlPrivacy: {
|
|
||||||
type: String,
|
|
||||||
default: '/pages/user_agreement/agreement/info?title=隐私政策'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
emits: ['confirm'],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
show: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
close() {
|
|
||||||
// #ifdef H5
|
|
||||||
window.opener = null;
|
|
||||||
window.close();
|
|
||||||
// #endif
|
|
||||||
// #ifdef APP-PLUS
|
|
||||||
plus.runtime.quit();
|
|
||||||
// #endif
|
|
||||||
},
|
|
||||||
confirm() {
|
|
||||||
this.show = false;
|
|
||||||
this.$emit('confirm', 1);
|
|
||||||
},
|
|
||||||
showModal() {
|
|
||||||
this.show = true;
|
|
||||||
},
|
|
||||||
urlClick(type) {
|
|
||||||
uni.navigateTo({
|
|
||||||
url: this[type]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-08-16 16:32:24
|
* @lastTime : 2021-08-20 16:47:24
|
||||||
* @FilePath : /uview-plus/libs/config/props/album.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/album.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// album 组件
|
// album 组件
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
/*
|
|
||||||
* @Author : jry
|
|
||||||
* @Description :
|
|
||||||
* @version : 3.0
|
|
||||||
* @LastAuthor : jry
|
|
||||||
* @lastTime : 2025-08-16 16:35:24
|
|
||||||
* @FilePath : /uview-plus/components/u-album/props.js
|
|
||||||
*/
|
|
||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import AlbumDefaultProps from './album'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(AlbumDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 图片地址,Array<String>|Array<Object>形式
|
// 图片地址,Array<String>|Array<Object>形式
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="u-album">
|
<view class="u-album">
|
||||||
<!-- 相册行容器,每行显示 rowCount 个图片 -->
|
|
||||||
<view
|
<view
|
||||||
class="u-album__row"
|
class="u-album__row"
|
||||||
ref="u-album__row"
|
ref="u-album__row"
|
||||||
@@ -9,15 +8,13 @@
|
|||||||
:key="index"
|
:key="index"
|
||||||
:style="{flexWrap: autoWrap ? 'wrap' : 'nowrap'}"
|
:style="{flexWrap: autoWrap ? 'wrap' : 'nowrap'}"
|
||||||
>
|
>
|
||||||
<!-- 图片包装容器 -->
|
|
||||||
<view
|
<view
|
||||||
class="u-album__row__wrapper"
|
class="u-album__row__wrapper"
|
||||||
v-for="(item, index1) in arr"
|
v-for="(item, index1) in arr"
|
||||||
:key="index1"
|
:key="index1"
|
||||||
:style="[imageStyle(index + 1, index1 + 1)]"
|
:style="[imageStyle(index + 1, index1 + 1)]"
|
||||||
@tap="onPreviewTap($event, getSrc(item))"
|
@tap="previewFullImage ? onPreviewTap($event, getSrc(item)) : ''"
|
||||||
>
|
>
|
||||||
<!-- 图片显示 -->
|
|
||||||
<image
|
<image
|
||||||
:src="getSrc(item)"
|
:src="getSrc(item)"
|
||||||
:mode="
|
:mode="
|
||||||
@@ -35,7 +32,6 @@
|
|||||||
}
|
}
|
||||||
]"
|
]"
|
||||||
></image>
|
></image>
|
||||||
<!-- 超出最大显示数量时的更多提示 -->
|
|
||||||
<view
|
<view
|
||||||
v-if="
|
v-if="
|
||||||
showMore &&
|
showMore &&
|
||||||
@@ -68,14 +64,14 @@ import { mixin } from '../../libs/mixin/mixin';
|
|||||||
import { addUnit, sleep } from '../../libs/function/index';
|
import { addUnit, sleep } from '../../libs/function/index';
|
||||||
import test from '../../libs/function/test';
|
import test from '../../libs/function/test';
|
||||||
// #ifdef APP-NVUE
|
// #ifdef APP-NVUE
|
||||||
// 不支持百分比单位,这里需要通过dom查询组件的宽度
|
// 由于weex为阿里的KPI业绩考核的产物,所以不支持百分比单位,这里需要通过dom查询组件的宽度
|
||||||
const dom = uni.requireNativePlugin('dom')
|
const dom = uni.requireNativePlugin('dom')
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Album 相册
|
* Album 相册
|
||||||
* @description 本组件提供一个类似相册的功能,让开发者开发起来更加得心应手。减少重复的模板代码
|
* @description 本组件提供一个类似相册的功能,让开发者开发起来更加得心应手。减少重复的模板代码
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/album.html
|
* @tutorial https://ijry.github.io/uview-plus/components/album.html
|
||||||
*
|
*
|
||||||
* @property {Array} urls 图片地址列表 Array<String>|Array<Object>形式
|
* @property {Array} urls 图片地址列表 Array<String>|Array<Object>形式
|
||||||
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
|
* @property {String} keyName 指定从数组的对象元素中读取哪个属性作为图片地址
|
||||||
@@ -112,20 +108,14 @@ export default {
|
|||||||
urls: {
|
urls: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler(newVal) {
|
handler(newVal) {
|
||||||
// 当只有一张图片时,获取图片尺寸信息
|
|
||||||
if (newVal.length === 1) {
|
if (newVal.length === 1) {
|
||||||
this.getImageRect()
|
this.getImageRect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
emits: ["albumWidth"],
|
||||||
computed: {
|
computed: {
|
||||||
/**
|
|
||||||
* 计算图片样式
|
|
||||||
* @param {Number} index1 - 行索引
|
|
||||||
* @param {Number} index2 - 列索引
|
|
||||||
* @returns {Object} 图片样式对象
|
|
||||||
*/
|
|
||||||
imageStyle() {
|
imageStyle() {
|
||||||
return (index1, index2) => {
|
return (index1, index2) => {
|
||||||
const { space, rowCount, multipleSize, urls } = this,
|
const { space, rowCount, multipleSize, urls } = this,
|
||||||
@@ -149,16 +139,11 @@ export default {
|
|||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
// 将数组划分为二维数组
|
||||||
* 将图片地址数组划分为二维数组,用于按行显示
|
|
||||||
* @returns {Array} 二维数组,每个子数组代表一行图片
|
|
||||||
*/
|
|
||||||
showUrls() {
|
showUrls() {
|
||||||
if (this.autoWrap) {
|
if (this.autoWrap) {
|
||||||
// 自动换行模式下,所有图片放在一行中显示
|
|
||||||
return [ this.urls.slice(0, this.maxCount) ];
|
return [ this.urls.slice(0, this.maxCount) ];
|
||||||
} else {
|
} else {
|
||||||
// 固定行数模式下,按 rowCount 分割图片
|
|
||||||
const arr = []
|
const arr = []
|
||||||
this.urls.map((item, index) => {
|
this.urls.map((item, index) => {
|
||||||
// 限制最大展示数量
|
// 限制最大展示数量
|
||||||
@@ -175,29 +160,18 @@ export default {
|
|||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* 计算图片宽度
|
|
||||||
* @returns {String} 图片宽度样式值
|
|
||||||
*/
|
|
||||||
imageWidth() {
|
imageWidth() {
|
||||||
return addUnit(
|
return addUnit(
|
||||||
this.urls.length === 1 ? this.singleWidth : this.multipleSize, this.unit
|
this.urls.length === 1 ? this.singleWidth : this.multipleSize, this.unit
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* 计算图片高度
|
|
||||||
* @returns {String} 图片高度样式值
|
|
||||||
*/
|
|
||||||
imageHeight() {
|
imageHeight() {
|
||||||
return addUnit(
|
return addUnit(
|
||||||
this.urls.length === 1 ? this.singleHeight : this.multipleSize, this.unit
|
this.urls.length === 1 ? this.singleHeight : this.multipleSize, this.unit
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
/**
|
// 此变量无实际用途,仅仅是为了利用computed特性,让其在urls长度等变化时,重新计算图片的宽度
|
||||||
* 计算相册总宽度,用于外部组件对齐
|
// 因为用户在某些特殊的情况下,需要让文字与相册的宽度相等,所以这里事件的形式对外发送
|
||||||
* 此变量无实际用途,仅仅是为了利用computed特性,让其在urls长度等变化时,重新计算图片的宽度
|
|
||||||
* @returns {Number} 相册宽度
|
|
||||||
*/
|
|
||||||
albumWidth() {
|
albumWidth() {
|
||||||
let width = 0
|
let width = 0
|
||||||
if (this.urls.length === 1) {
|
if (this.urls.length === 1) {
|
||||||
@@ -211,100 +185,59 @@ export default {
|
|||||||
return width
|
return width
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['preview', 'albumWidth'],
|
|
||||||
methods: {
|
methods: {
|
||||||
addUnit,
|
addUnit,
|
||||||
/**
|
// 预览图片
|
||||||
* 点击图片预览
|
|
||||||
* @param {Event} e - 点击事件对象
|
|
||||||
* @param {String} url - 当前点击图片的地址
|
|
||||||
*/
|
|
||||||
onPreviewTap(e, url) {
|
onPreviewTap(e, url) {
|
||||||
// 获取所有图片地址
|
|
||||||
const urls = this.urls.map((item) => {
|
const urls = this.urls.map((item) => {
|
||||||
return this.getSrc(item)
|
return this.getSrc(item)
|
||||||
})
|
})
|
||||||
if (this.previewFullImage) {
|
uni.previewImage({
|
||||||
// 使用系统默认预览图片功能
|
current: url,
|
||||||
uni.previewImage({
|
urls
|
||||||
current: url,
|
})
|
||||||
urls
|
// 是否阻止事件传播
|
||||||
})
|
this.stop && this.preventEvent(e)
|
||||||
// 是否阻止事件传播
|
|
||||||
this.stop && this.preventEvent(e)
|
|
||||||
} else {
|
|
||||||
// 发送自定义预览事件
|
|
||||||
this.$emit('preview', {
|
|
||||||
urls,
|
|
||||||
currentIndex: urls.indexOf(url)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
/**
|
// 获取图片的路径
|
||||||
* 获取图片地址
|
|
||||||
* @param {String|Object} item - 图片项,可以是字符串或对象
|
|
||||||
* @returns {String} 图片地址
|
|
||||||
*/
|
|
||||||
getSrc(item) {
|
getSrc(item) {
|
||||||
return test.object(item)
|
return test.object(item)
|
||||||
? (this.keyName && item[this.keyName]) || item.src
|
? (this.keyName && item[this.keyName]) || item.src
|
||||||
: item
|
: item
|
||||||
},
|
},
|
||||||
/**
|
// 单图时,获取图片的尺寸
|
||||||
* 单图时,获取图片的尺寸
|
// 在小程序中,需要将网络图片的的域名添加到小程序的download域名才可能获取尺寸
|
||||||
* 在小程序中,需要将网络图片的的域名添加到小程序的download域名才可能获取尺寸
|
// 在没有添加的情况下,让单图宽度默认为盒子的一定宽度(singlePercent)
|
||||||
* 在没有添加的情况下,让单图宽度默认为盒子的一定宽度(singlePercent)
|
|
||||||
*/
|
|
||||||
getImageRect() {
|
getImageRect() {
|
||||||
const src = this.getSrc(this.urls[0])
|
const src = this.getSrc(this.urls[0])
|
||||||
uni.getImageInfo({
|
uni.getImageInfo({
|
||||||
src,
|
src,
|
||||||
success: (res) => {
|
success: (res) => {
|
||||||
let singleSize = this.singleSize;
|
|
||||||
// 单位
|
|
||||||
let unit = '';
|
|
||||||
if (Number.isNaN(Number(this.singleSize))) {
|
|
||||||
// 大小中有字符 则记录字符
|
|
||||||
unit = this.singleSize.replace(/\d+/g, ''); // 单位
|
|
||||||
singleSize = Number(this.singleSize.replace(/\D+/g, ''), 10); // 具体值
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断图片横向还是竖向展示方式
|
// 判断图片横向还是竖向展示方式
|
||||||
const isHorizotal = res.width >= res.height
|
const isHorizotal = res.width >= res.height
|
||||||
this.singleWidth = isHorizotal
|
this.singleWidth = isHorizotal
|
||||||
? singleSize
|
? this.singleSize
|
||||||
: (res.width / res.height) * singleSize
|
: (res.width / res.height) * this.singleSize
|
||||||
this.singleHeight = !isHorizotal
|
this.singleHeight = !isHorizotal
|
||||||
? singleSize
|
? this.singleSize
|
||||||
: (res.height / res.width) * this.singleWidth
|
: (res.height / res.width) * this.singleWidth
|
||||||
|
|
||||||
// 如果有单位统一设置单位
|
|
||||||
if(unit != null && unit !== ''){
|
|
||||||
this.singleWidth = this.singleWidth + unit
|
|
||||||
this.singleHeight = this.singleHeight + unit
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
fail: () => {
|
fail: () => {
|
||||||
// 获取图片信息失败时,通过组件宽度计算
|
|
||||||
this.getComponentWidth()
|
this.getComponentWidth()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
/**
|
// 获取组件的宽度
|
||||||
* 获取组件的宽度,用于计算单图显示尺寸
|
|
||||||
*/
|
|
||||||
async getComponentWidth() {
|
async getComponentWidth() {
|
||||||
// 延时一定时间,以获取dom尺寸
|
// 延时一定时间,以获取dom尺寸
|
||||||
await sleep(30)
|
await sleep(30)
|
||||||
// #ifndef APP-NVUE
|
// #ifndef APP-NVUE
|
||||||
// H5、小程序等平台通过 $uGetRect 获取组件宽度
|
|
||||||
this.$uGetRect('.u-album__row').then((size) => {
|
this.$uGetRect('.u-album__row').then((size) => {
|
||||||
this.singleWidth = size.width * this.singlePercent
|
this.singleWidth = size.width * this.singlePercent
|
||||||
})
|
})
|
||||||
// #endif
|
// #endif
|
||||||
|
|
||||||
// #ifdef APP-NVUE
|
// #ifdef APP-NVUE
|
||||||
// NVUE 平台通过 dom 插件获取组件宽度
|
|
||||||
// 这里ref="u-album__row"所在的标签为通过for循环出来,导致this.$refs['u-album__row']是一个数组
|
// 这里ref="u-album__row"所在的标签为通过for循环出来,导致this.$refs['u-album__row']是一个数组
|
||||||
const ref = this.$refs['u-album__row'][0]
|
const ref = this.$refs['u-album__row'][0]
|
||||||
ref &&
|
ref &&
|
||||||
@@ -318,6 +251,8 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import '../../libs/css/components.scss';
|
||||||
|
|
||||||
.u-album {
|
.u-album {
|
||||||
@include flex(column);
|
@include flex(column);
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-08-17 17:23:53
|
* @lastTime : 2021-08-20 16:48:53
|
||||||
* @FilePath : /uview-plus/libs/config/props/alert.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/alert.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// alert警告组件
|
// alert警告组件
|
||||||
@@ -17,10 +17,6 @@ export default {
|
|||||||
showIcon: false,
|
showIcon: false,
|
||||||
effect: 'light',
|
effect: 'light',
|
||||||
center: false,
|
center: false,
|
||||||
fontSize: 14,
|
fontSize: 14
|
||||||
transitionMode: 'fade',
|
|
||||||
duration: 0,
|
|
||||||
icon: '',
|
|
||||||
value: true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,5 @@
|
|||||||
/*
|
|
||||||
* @Author : jry
|
|
||||||
* @Description :
|
|
||||||
* @version : 3.0
|
|
||||||
* @LastAuthor : jry
|
|
||||||
* @lastTime : 2025-08-17 17:23:53
|
|
||||||
* @FilePath : /uview-plus/libs/config/props/props.js
|
|
||||||
*/
|
|
||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import AlertDefaultProps from './alert'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(AlertDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 显示文字
|
// 显示文字
|
||||||
@@ -52,26 +41,6 @@ export const props = defineMixin({
|
|||||||
fontSize: {
|
fontSize: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
default: () => defProps.alert.fontSize
|
default: () => defProps.alert.fontSize
|
||||||
},
|
|
||||||
// 动画类型
|
|
||||||
transitionMode: {
|
|
||||||
type: [String],
|
|
||||||
default: () => defProps.alert.transitionMode
|
|
||||||
},
|
|
||||||
// 自动定时关闭毫秒
|
|
||||||
duration: {
|
|
||||||
type: [Number],
|
|
||||||
default: () => defProps.alert.duration
|
|
||||||
},
|
|
||||||
// 自定义图标
|
|
||||||
icon: {
|
|
||||||
type: [String],
|
|
||||||
default: () => defProps.alert.icon
|
|
||||||
},
|
|
||||||
// 是否显示
|
|
||||||
modelValue: {
|
|
||||||
type: [Boolean],
|
|
||||||
default: () => defProps.alert.value
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<up-transition
|
<u-transition
|
||||||
:mode="transitionMode"
|
mode="fade"
|
||||||
:show="show"
|
:show="show"
|
||||||
>
|
>
|
||||||
<view
|
<view
|
||||||
@@ -9,25 +9,22 @@
|
|||||||
@tap.stop="clickHandler"
|
@tap.stop="clickHandler"
|
||||||
:style="[addStyle(customStyle)]"
|
:style="[addStyle(customStyle)]"
|
||||||
>
|
>
|
||||||
<!-- 左侧图标 -->
|
|
||||||
<view
|
<view
|
||||||
class="u-alert__icon"
|
class="u-alert__icon"
|
||||||
v-if="showIcon"
|
v-if="showIcon"
|
||||||
>
|
>
|
||||||
<up-icon
|
<u-icon
|
||||||
:name="iconName"
|
:name="iconName"
|
||||||
size="18"
|
size="18"
|
||||||
:color="iconColor"
|
:color="iconColor"
|
||||||
></up-icon>
|
></u-icon>
|
||||||
</view>
|
</view>
|
||||||
<!-- 内容区域 -->
|
|
||||||
<view
|
<view
|
||||||
class="u-alert__content"
|
class="u-alert__content"
|
||||||
:style="[{
|
:style="[{
|
||||||
paddingRight: closable ? '20px' : 0
|
paddingRight: closable ? '20px' : 0
|
||||||
}]"
|
}]"
|
||||||
>
|
>
|
||||||
<!-- 标题 -->
|
|
||||||
<text
|
<text
|
||||||
class="u-alert__content__title"
|
class="u-alert__content__title"
|
||||||
v-if="title"
|
v-if="title"
|
||||||
@@ -37,7 +34,6 @@
|
|||||||
}]"
|
}]"
|
||||||
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
|
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
|
||||||
>{{ title }}</text>
|
>{{ title }}</text>
|
||||||
<!-- 描述信息 -->
|
|
||||||
<text
|
<text
|
||||||
class="u-alert__content__desc"
|
class="u-alert__content__desc"
|
||||||
v-if="description"
|
v-if="description"
|
||||||
@@ -48,22 +44,19 @@
|
|||||||
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
|
:class="[effect === 'dark' ? 'u-alert__text--dark' : `u-alert__text--${type}--light`]"
|
||||||
>{{ description }}</text>
|
>{{ description }}</text>
|
||||||
</view>
|
</view>
|
||||||
<!-- 关闭按钮 -->
|
|
||||||
<view
|
<view
|
||||||
class="u-alert__close"
|
class="u-alert__close"
|
||||||
v-if="closable"
|
v-if="closable"
|
||||||
@tap.stop="closeHandler"
|
@tap.stop="closeHandler"
|
||||||
>
|
>
|
||||||
<slot name="close">
|
<u-icon
|
||||||
<up-icon
|
name="close"
|
||||||
name="close"
|
:color="iconColor"
|
||||||
:color="iconColor"
|
size="15"
|
||||||
size="15"
|
></u-icon>
|
||||||
></up-icon>
|
|
||||||
</slot>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</up-transition>
|
</u-transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -74,10 +67,10 @@
|
|||||||
/**
|
/**
|
||||||
* Alert 警告提示
|
* Alert 警告提示
|
||||||
* @description 警告提示,展现需要关注的信息。
|
* @description 警告提示,展现需要关注的信息。
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/alertTips.html
|
* @tutorial https://ijry.github.io/uview-plus/components/alertTips.html
|
||||||
*
|
*
|
||||||
* @property {String} title 显示的文字
|
* @property {String} title 显示的文字
|
||||||
* @property {String} type 使用预设的颜色 (默认 'warning' )
|
* @property {String} type 使用预设的颜色 (默认 'warning' )
|
||||||
* @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选
|
* @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选
|
||||||
* @property {Boolean} closable 关闭按钮(默认为叉号icon图标) (默认 false )
|
* @property {Boolean} closable 关闭按钮(默认为叉号icon图标) (默认 false )
|
||||||
* @property {Boolean} showIcon 是否显示左边的辅助图标 ( 默认 false )
|
* @property {Boolean} showIcon 是否显示左边的辅助图标 ( 默认 false )
|
||||||
@@ -85,34 +78,24 @@
|
|||||||
* @property {Boolean} center 文字是否居中 (默认 false )
|
* @property {Boolean} center 文字是否居中 (默认 false )
|
||||||
* @property {String | Number} fontSize 字体大小 (默认 14 )
|
* @property {String | Number} fontSize 字体大小 (默认 14 )
|
||||||
* @property {Object} customStyle 定义需要用到的外部样式
|
* @property {Object} customStyle 定义需要用到的外部样式
|
||||||
* @property {String} transitionMode 过渡动画模式 (默认 'fade' )
|
|
||||||
* @property {String | Number} duration 自动关闭延时(毫秒),设置为0或负数则不自动关闭 (默认 0 )
|
|
||||||
* @property {String} icon 自定义图标名称,优先级高于type默认图标
|
|
||||||
* @property {Boolean} modelValue/v-model 绑定值,控制是否显示 (默认 true )
|
|
||||||
* @event {Function} click 点击组件时触发
|
* @event {Function} click 点击组件时触发
|
||||||
* @event {Function} close 点击关闭按钮时触发
|
* @event {Function} close 点击关闭按钮时触发
|
||||||
* @event {Function} closed 关闭动画结束时触发
|
* @example <u-alert :title="title" type = "warning" :closable="closable" :description = "description"></u-alert>
|
||||||
* @example <up-alert :title="title" type = "warning" :closable="closable" :description = "description"></up-alert>
|
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
name: 'u-alert',
|
name: 'u-alert',
|
||||||
mixins: [mpMixin, mixin, props],
|
mixins: [mpMixin, mixin, props],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// 控制组件显示隐藏
|
|
||||||
show: true
|
show: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
// 根据不同的主题类型返回对应的图标颜色
|
|
||||||
iconColor() {
|
iconColor() {
|
||||||
return this.effect === 'light' ? this.type : '#fff'
|
return this.effect === 'light' ? this.type : '#fff'
|
||||||
},
|
},
|
||||||
// 不同主题对应不同的图标
|
// 不同主题对应不同的图标
|
||||||
iconName() {
|
iconName() {
|
||||||
// 如果用户自定义了图标,则优先使用自定义图标
|
|
||||||
if (this.icon) return this.icon;
|
|
||||||
|
|
||||||
switch (this.type) {
|
switch (this.type) {
|
||||||
case 'success':
|
case 'success':
|
||||||
return 'checkmark-circle-fill';
|
return 'checkmark-circle-fill';
|
||||||
@@ -134,50 +117,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ["click","close", "closed", "update:modelValue"],
|
emits: ["click","close"],
|
||||||
watch: {
|
|
||||||
modelValue: {
|
|
||||||
handler(newVal) {
|
|
||||||
this.show = newVal;
|
|
||||||
},
|
|
||||||
immediate: true
|
|
||||||
},
|
|
||||||
show: {
|
|
||||||
handler(newVal) {
|
|
||||||
this.$emit('update:modelValue', newVal);
|
|
||||||
|
|
||||||
// 如果是从显示到隐藏,且启用了自动关闭功能
|
|
||||||
if (!newVal && this.duration > 0) {
|
|
||||||
this.$emit('closed');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
// 如果设置了自动关闭时间,则在指定时间后自动关闭
|
|
||||||
if (this.duration > 0) {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.closeHandler();
|
|
||||||
}, this.duration);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
addUnit,
|
addUnit,
|
||||||
addStyle,
|
addStyle,
|
||||||
// 点击内容区域触发click事件
|
// 点击内容
|
||||||
clickHandler() {
|
clickHandler() {
|
||||||
this.$emit('click')
|
this.$emit('click')
|
||||||
},
|
},
|
||||||
// 点击关闭按钮触发close事件并隐藏组件
|
// 点击关闭按钮
|
||||||
closeHandler() {
|
closeHandler() {
|
||||||
this.show = false
|
this.show = false
|
||||||
this.$emit('close');
|
this.$emit('close')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-alert {
|
.u-alert {
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -195,7 +153,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&--primary--light {
|
&--primary--light {
|
||||||
background-color: var(--up-primary-light, #ecf5ff);
|
background-color: #ecf5ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--error--dark {
|
&--error--dark {
|
||||||
@@ -203,7 +161,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&--error--light {
|
&--error--light {
|
||||||
background-color: var(--up-error-light, #FEF0F0);
|
background-color: #FEF0F0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--success--dark {
|
&--success--dark {
|
||||||
@@ -211,7 +169,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&--success--light {
|
&--success--light {
|
||||||
background-color: var(--up-success-light, #f5fff0);
|
background-color: #f5fff0;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--warning--dark {
|
&--warning--dark {
|
||||||
@@ -219,7 +177,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&--warning--light {
|
&--warning--light {
|
||||||
background-color: var(--up-warning-light, #FDF6EC);
|
background-color: #FDF6EC;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--info--dark {
|
&--info--dark {
|
||||||
@@ -227,7 +185,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&--info--light {
|
&--info--light {
|
||||||
background-color: var(--up-info-light, #f4f4f5);
|
background-color: #f4f4f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__icon {
|
&__icon {
|
||||||
@@ -239,22 +197,24 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
&__title {
|
&__title {
|
||||||
color: var(--up-main-color, $u-main-color);
|
color: $u-main-color;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
color: #fff;
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__desc {
|
&__desc {
|
||||||
color: var(--up-main-color, $u-main-color);
|
color: $u-main-color;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__title--dark,
|
&__title--dark,
|
||||||
&__desc--dark {
|
&__desc--dark {
|
||||||
color: var(--up-white, #FFFFFF);
|
color: #FFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__text--primary--light,
|
&__text--primary--light,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:49:55
|
||||||
* @FilePath : /uview-plus/libs/config/props/avatarGroup.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/avatarGroup.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// avatarGroup 组件
|
// avatarGroup 组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import AvatarGroupDefaultProps from './avatarGroup'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(AvatarGroupDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 头像图片组
|
// 头像图片组
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
/**
|
/**
|
||||||
* AvatarGroup 头像组
|
* AvatarGroup 头像组
|
||||||
* @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
|
* @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/avatar.html
|
* @tutorial https://ijry.github.io/uview-plus/components/avatar.html
|
||||||
*
|
*
|
||||||
* @property {Array} urls 头像图片组 (默认 [] )
|
* @property {Array} urls 头像图片组 (默认 [] )
|
||||||
* @property {String | Number} maxCount 最多展示的头像数量 ( 默认 5 )
|
* @property {String | Number} maxCount 最多展示的头像数量 ( 默认 5 )
|
||||||
@@ -79,6 +79,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-avatar-group {
|
.u-avatar-group {
|
||||||
@include flex;
|
@include flex;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:49:22
|
||||||
* @FilePath : /uview-plus/libs/config/props/avatar.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/avatar.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// avatar 组件
|
// avatar 组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import AvatarDefaultProps from './avatar'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(AvatarDefaultProps)
|
|
||||||
import test from '../../libs/function/test';
|
import test from '../../libs/function/test';
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
|
|||||||
@@ -23,12 +23,12 @@
|
|||||||
<!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU -->
|
<!-- #ifndef MP-WEIXIN && MP-QQ && MP-BAIDU -->
|
||||||
<template v-if="mpAvatar && allowMp"></template>
|
<template v-if="mpAvatar && allowMp"></template>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<up-icon
|
<u-icon
|
||||||
v-else-if="icon"
|
v-else-if="icon"
|
||||||
:name="icon"
|
:name="icon"
|
||||||
:size="fontSize"
|
:size="fontSize"
|
||||||
:color="color"
|
:color="color"
|
||||||
></up-icon>
|
></u-icon>
|
||||||
<up-text
|
<up-text
|
||||||
v-else-if="text"
|
v-else-if="text"
|
||||||
:text="text"
|
:text="text"
|
||||||
@@ -63,7 +63,7 @@
|
|||||||
/**
|
/**
|
||||||
* Avatar 头像
|
* Avatar 头像
|
||||||
* @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
|
* @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/avatar.html
|
* @tutorial https://ijry.github.io/uview-plus/components/avatar.html
|
||||||
*
|
*
|
||||||
* @property {String} src 头像路径,如加载失败,将会显示默认头像(不能为相对路径)
|
* @property {String} src 头像路径,如加载失败,将会显示默认头像(不能为相对路径)
|
||||||
* @property {String} shape 头像形状 ( circle (默认) | square)
|
* @property {String} shape 头像形状 ( circle (默认) | square)
|
||||||
@@ -151,6 +151,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-avatar {
|
.u-avatar {
|
||||||
@include flex;
|
@include flex;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:50:18
|
||||||
* @FilePath : /uview-plus/libs/config/props/backtop.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/backtop.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// backtop组件
|
// backtop组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import BackTopDefaultProps from './backtop'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(BackTopDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 返回顶部的形状,circle-圆形,square-方形
|
// 返回顶部的形状,circle-圆形,square-方形
|
||||||
|
|||||||
@@ -10,10 +10,10 @@
|
|||||||
v-if="!$slots.default && !$slots.$default"
|
v-if="!$slots.default && !$slots.$default"
|
||||||
@click="backToTop"
|
@click="backToTop"
|
||||||
>
|
>
|
||||||
<up-icon
|
<u-icon
|
||||||
:name="icon"
|
:name="icon"
|
||||||
:custom-style="iconStyle"
|
:custom-style="iconStyle"
|
||||||
></up-icon>
|
></u-icon>
|
||||||
<text
|
<text
|
||||||
v-if="text"
|
v-if="text"
|
||||||
class="u-back-top__text"
|
class="u-back-top__text"
|
||||||
@@ -111,6 +111,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import '../../libs/css/components.scss';
|
||||||
$u-back-top-flex:1 !default;
|
$u-back-top-flex:1 !default;
|
||||||
$u-back-top-height:100% !default;
|
$u-back-top-height:100% !default;
|
||||||
$u-back-top-background-color:#E1E1E1 !default;
|
$u-back-top-background-color:#E1E1E1 !default;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-23 19:51:50
|
||||||
* @FilePath : /uview-plus/libs/config/props/badge.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/badge.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// 徽标数组件
|
// 徽标数组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import BadgeDefaultProps from './badge'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(BadgeDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 是否显示圆点
|
// 是否显示圆点
|
||||||
|
|||||||
@@ -89,6 +89,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
$u-badge-primary: $u-primary !default;
|
$u-badge-primary: $u-primary !default;
|
||||||
$u-badge-error: $u-error !default;
|
$u-badge-error: $u-error !default;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,24 +0,0 @@
|
|||||||
/*
|
|
||||||
* @Author : ly
|
|
||||||
* @Description :
|
|
||||||
* @version : 4.0
|
|
||||||
* @Date : 2026-02-02 23:54:58
|
|
||||||
* @LastAuthor : ly
|
|
||||||
* @lastTime : 2026-02-02 23:54:58
|
|
||||||
* @FilePath : /uview-ultra/components/up-box/box.js
|
|
||||||
*/
|
|
||||||
export default {
|
|
||||||
// box 组件
|
|
||||||
box: {
|
|
||||||
bgColors: ['#EEFCFF', '#FCF8FF', '#FDF8F2'],
|
|
||||||
height: '160px',
|
|
||||||
borderRadius: '6px',
|
|
||||||
gap: '15px',
|
|
||||||
leftIcon: '',
|
|
||||||
leftTitle: '左',
|
|
||||||
rightTopIcon: '',
|
|
||||||
rightTopTitle: '右上',
|
|
||||||
rightBottomIcon: '',
|
|
||||||
rightBottomTitle: '右下'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,60 +1,27 @@
|
|||||||
import { defineMixin } from '../../libs/vue.js'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import BoxDefaultProps from './box.js'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(BoxDefaultProps)
|
|
||||||
|
|
||||||
export const propsBox = defineMixin({
|
export const propsBox = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 背景色
|
// 背景色
|
||||||
bgColors: {
|
bgColors: {
|
||||||
type: [Array],
|
type: [Array],
|
||||||
default: () => defProps.box.bgColors
|
default: ['#EEFCFF', '#FCF8FF', '#FDF8F2']
|
||||||
},
|
},
|
||||||
// 高度
|
// 高度
|
||||||
height: {
|
height: {
|
||||||
type: [String],
|
type: [String],
|
||||||
default: () => defProps.box.height
|
default: "160px"
|
||||||
},
|
},
|
||||||
// 圆角
|
// 圆角
|
||||||
borderRadius: {
|
borderRadius: {
|
||||||
type: [String],
|
type: [String],
|
||||||
default: () => defProps.box.borderRadius
|
default: "6px"
|
||||||
},
|
},
|
||||||
// 间隔
|
// 间隔
|
||||||
gap: {
|
gap: {
|
||||||
type: [String],
|
type: [String],
|
||||||
default: () => defProps.box.gap
|
default: "15px"
|
||||||
},
|
|
||||||
// 左侧图标
|
|
||||||
leftIcon: {
|
|
||||||
type: [String],
|
|
||||||
default: () => defProps.box.leftIcon
|
|
||||||
},
|
|
||||||
// 左侧文案
|
|
||||||
leftTitle: {
|
|
||||||
type: [String],
|
|
||||||
default: () => defProps.box.leftTitle
|
|
||||||
},
|
|
||||||
// 右上图标
|
|
||||||
rightTopIcon: {
|
|
||||||
type: [String],
|
|
||||||
default: () => defProps.box.rightTopIcon
|
|
||||||
},
|
|
||||||
// 右上文案
|
|
||||||
rightTopTitle: {
|
|
||||||
type: [String],
|
|
||||||
default: () => defProps.box.rightTopTitle
|
|
||||||
},
|
|
||||||
// 右下图标
|
|
||||||
rightBottomIcon: {
|
|
||||||
type: [String],
|
|
||||||
default: () => defProps.box.rightBottomIcon
|
|
||||||
},
|
|
||||||
// 右下文案
|
|
||||||
rightBottomTitle: {
|
|
||||||
type: [String],
|
|
||||||
default: () => defProps.box.rightBottomTitle
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,33 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="u-box" :style="[{height: height}, addStyle(customStyle)]">
|
<view class="u-box" :style="[{height: height}, addStyle(customStyle)]">
|
||||||
<view class="u-box__left" :style="{borderRadius: borderRadius, backgroundColor: bgColors[0]}">
|
<view class="u-box__left" :style="{borderRadius: borderRadius, backgroundColor: bgColors[0]}">
|
||||||
<slot name="left">
|
<slot name="left">左</slot>
|
||||||
<view class="flex flex-row items-center justify-center">
|
</view>
|
||||||
<u-icon size="36" :name="leftIcon"></u-icon>
|
<view class="u-box__gap" :style="{width: gap, height: height}"></view>
|
||||||
<text class="ml-2 text-16px">{{leftTitle}}</text>
|
<view class="u-box__right">
|
||||||
</view>
|
<view class="u-box__right-top" :style="{borderRadius: borderRadius, backgroundColor: bgColors[1]}">
|
||||||
</slot>
|
<slot name="rightTop">右上</slot>
|
||||||
</view>
|
</view>
|
||||||
<view class="u-box__gap" :style="{width: gap, height: height}"></view>
|
<view class="u-box__right-gap" :style="{height: gap}"></view>
|
||||||
<view class="u-box__right">
|
<view class="u-box__right-bottom" :style="{borderRadius: borderRadius, backgroundColor: bgColors[2]}">
|
||||||
<view class="u-box__right-top" :style="{borderRadius: borderRadius, backgroundColor: bgColors[1]}">
|
<slot name="rightBottom">右下</slot>
|
||||||
<slot name="rightTop">
|
</view>
|
||||||
<view class="flex flex-row items-center justify-center">
|
</view>
|
||||||
<u-icon size="36" :name="rightTopIcon"></u-icon>
|
|
||||||
<text class="ml-2 text-15px">{{rightTopTitle}}</text>
|
|
||||||
</view>
|
|
||||||
</slot>
|
|
||||||
</view>
|
|
||||||
<view class="u-box__right-gap" :style="{height: gap}"></view>
|
|
||||||
<view class="u-box__right-bottom" :style="{borderRadius: borderRadius, backgroundColor: bgColors[2]}">
|
|
||||||
<slot name="rightBottom">
|
|
||||||
<view class="flex flex-row items-center justify-center">
|
|
||||||
<u-icon size="36" :name="rightBottomIcon"></u-icon>
|
|
||||||
<text class="ml-2 text-15px">{{rightBottomTitle}}</text>
|
|
||||||
</view>
|
|
||||||
</slot>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -66,6 +51,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-box {
|
.u-box {
|
||||||
/* #ifndef APP-NVUE */
|
/* #ifndef APP-NVUE */
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:51:27
|
||||||
* @FilePath : /uview-plus/libs/config/props/button.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/button.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// button组件
|
// button组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import ButtonDefaultProps from './button'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(ButtonDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 是否细边框
|
// 是否细边框
|
||||||
|
|||||||
@@ -39,13 +39,13 @@
|
|||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<up-icon
|
<u-icon
|
||||||
v-if="icon"
|
v-if="icon"
|
||||||
:name="icon"
|
:name="icon"
|
||||||
:color="iconColorCom"
|
:color="iconColorCom"
|
||||||
:size="textSize * 1.35"
|
:size="textSize * 1.35"
|
||||||
:customStyle="{ marginRight: '2px' }"
|
:customStyle="{ marginRight: '2px' }"
|
||||||
></up-icon>
|
></u-icon>
|
||||||
<slot>
|
<slot>
|
||||||
<text
|
<text
|
||||||
class="u-button__text"
|
class="u-button__text"
|
||||||
@@ -87,12 +87,12 @@
|
|||||||
>
|
>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<up-icon
|
<u-icon
|
||||||
v-if="icon"
|
v-if="icon"
|
||||||
:name="icon"
|
:name="icon"
|
||||||
:color="iconColorCom"
|
:color="iconColorCom"
|
||||||
:size="textSize * 1.35"
|
:size="textSize * 1.35"
|
||||||
></up-icon>
|
></u-icon>
|
||||||
<text
|
<text
|
||||||
class="u-button__text"
|
class="u-button__text"
|
||||||
:style="[
|
:style="[
|
||||||
@@ -117,11 +117,11 @@ import { mixin } from '../../libs/mixin/mixin';
|
|||||||
import { props } from "./props";
|
import { props } from "./props";
|
||||||
import { addStyle } from '../../libs/function/index';
|
import { addStyle } from '../../libs/function/index';
|
||||||
import { throttle } from '../../libs/function/throttle';
|
import { throttle } from '../../libs/function/throttle';
|
||||||
import { getThemeVar } from '../../libs/theme/runtime.js';
|
import color from '../../libs/config/color';
|
||||||
/**
|
/**
|
||||||
* button 按钮
|
* button 按钮
|
||||||
* @description Button 按钮
|
* @description Button 按钮
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/button.html
|
* @tutorial https://ijry.github.io/uview-plus/components/button.html
|
||||||
*
|
*
|
||||||
* @property {Boolean} hairline 是否显示按钮的细边框 (默认 true )
|
* @property {Boolean} hairline 是否显示按钮的细边框 (默认 true )
|
||||||
* @property {String} type 按钮的预置样式,info,primary,error,warning,success (默认 'info' )
|
* @property {String} type 按钮的预置样式,info,primary,error,warning,success (默认 'info' )
|
||||||
@@ -192,67 +192,26 @@ export default {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isDarkTheme() {
|
|
||||||
return this.$u.theme && this.$u.theme.mode === 'dark';
|
|
||||||
},
|
|
||||||
nvueMainColor() {
|
|
||||||
return this.resolveNvueColor(this.$u.color.mainColor, this.isDarkTheme ? '#f5f5f5' : '#303133');
|
|
||||||
},
|
|
||||||
nvueBorderColor() {
|
|
||||||
return this.resolveNvueColor(this.$u.color.borderColor, this.isDarkTheme ? '#3a3a3c' : '#dadbde');
|
|
||||||
},
|
|
||||||
themeTypeColor() {
|
|
||||||
const fallbackMap = {
|
|
||||||
primary: '#3c9cff',
|
|
||||||
success: '#5ac725',
|
|
||||||
warning: '#f9ae3d',
|
|
||||||
error: '#f56c6c',
|
|
||||||
info: '#909399',
|
|
||||||
};
|
|
||||||
const type = fallbackMap[this.type] ? this.type : 'info';
|
|
||||||
return this.resolveNvueColor(
|
|
||||||
this.upThemeVar(`--up-${type}`, fallbackMap[type]),
|
|
||||||
fallbackMap[type]
|
|
||||||
);
|
|
||||||
},
|
|
||||||
nvueInfoBackgroundColor() {
|
|
||||||
return this.upThemeVar(
|
|
||||||
'--up-button-info-background-color',
|
|
||||||
this.upThemeVar(
|
|
||||||
'--up-card-bg-color',
|
|
||||||
this.isDarkTheme ? '#1c1c1e' : '#ffffff'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
nvuePlainBackgroundColor() {
|
|
||||||
return this.upThemeVar(
|
|
||||||
'--up-button-plain-background-color',
|
|
||||||
this.upThemeVar(
|
|
||||||
'--up-card-bg-color',
|
|
||||||
this.isDarkTheme ? '#1c1c1e' : '#ffffff'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
loadingColor() {
|
loadingColor() {
|
||||||
if (this.plain) {
|
if (this.plain) {
|
||||||
// 如果有设置color值,则用color值,否则使用type主题颜色
|
// 如果有设置color值,则用color值,否则使用type主题颜色
|
||||||
return this.color
|
return this.color
|
||||||
? this.color
|
? this.color
|
||||||
: this.themeTypeColor;
|
: color[`u-${this.type}`];
|
||||||
}
|
}
|
||||||
if (this.type === "info") {
|
if (this.type === "info") {
|
||||||
return this.isDarkTheme ? "#9ca3af" : "#c9c9c9";
|
return "#c9c9c9";
|
||||||
}
|
}
|
||||||
return "rgb(200, 200, 200)";
|
return "rgb(200, 200, 200)";
|
||||||
},
|
},
|
||||||
iconColorCom() {
|
iconColorCom() {
|
||||||
// 如果是镂空状态,设置了color就用color值,否则使用主题颜色,
|
// 如果是镂空状态,设置了color就用color值,否则使用主题颜色,
|
||||||
// up-icon的color能接受一个主题颜色的值
|
// u-icon的color能接受一个主题颜色的值
|
||||||
if (this.iconColor) return this.iconColor;
|
if (this.iconColor) return this.iconColor;
|
||||||
if (this.plain) {
|
if (this.plain) {
|
||||||
return this.color ? this.color : this.type;
|
return this.color ? this.color : this.type;
|
||||||
} else {
|
} else {
|
||||||
return this.type === "info" ? this.nvueMainColor : "#ffffff";
|
return this.type === "info" ? "#000000" : "#ffffff";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
baseColor() {
|
baseColor() {
|
||||||
@@ -281,30 +240,7 @@ export default {
|
|||||||
style.borderWidth = "1px";
|
style.borderWidth = "1px";
|
||||||
style.borderStyle = "solid";
|
style.borderStyle = "solid";
|
||||||
}
|
}
|
||||||
return style;
|
|
||||||
}
|
}
|
||||||
// #ifdef APP-NVUE
|
|
||||||
const typeColor = this.themeTypeColor;
|
|
||||||
if (this.plain) {
|
|
||||||
style.color = this.type === 'info' ? this.nvueMainColor : typeColor;
|
|
||||||
style.backgroundColor = this.nvuePlainBackgroundColor;
|
|
||||||
style.borderColor = this.type === 'info' ? this.nvueBorderColor : typeColor;
|
|
||||||
style.borderWidth = this.hairline ? '0.5px' : '1px';
|
|
||||||
style.borderStyle = 'solid';
|
|
||||||
} else {
|
|
||||||
style.borderWidth = this.hairline ? '0.5px' : '1px';
|
|
||||||
style.borderStyle = 'solid';
|
|
||||||
if (this.type === 'info') {
|
|
||||||
style.color = this.nvueMainColor;
|
|
||||||
style.backgroundColor = this.nvueInfoBackgroundColor;
|
|
||||||
style.borderColor = this.nvueBorderColor;
|
|
||||||
} else {
|
|
||||||
style.color = '#ffffff';
|
|
||||||
style.backgroundColor = typeColor;
|
|
||||||
style.borderColor = typeColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
return style;
|
return style;
|
||||||
},
|
},
|
||||||
// nvue版本按钮的字体不会继承父组件的颜色,需要对每一个text组件进行单独的设置
|
// nvue版本按钮的字体不会继承父组件的颜色,需要对每一个text组件进行单独的设置
|
||||||
@@ -312,12 +248,10 @@ export default {
|
|||||||
let style = {};
|
let style = {};
|
||||||
// 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色
|
// 针对自定义了color颜色的情况,镂空状态下,就是用自定义的颜色
|
||||||
if (this.type === "info") {
|
if (this.type === "info") {
|
||||||
style.color = this.nvueMainColor;
|
style.color = "#323233";
|
||||||
}
|
}
|
||||||
if (this.color) {
|
if (this.color) {
|
||||||
style.color = this.plain ? this.color : "white";
|
style.color = this.plain ? this.color : "white";
|
||||||
} else if (this.plain && this.type !== 'info') {
|
|
||||||
style.color = this.themeTypeColor;
|
|
||||||
}
|
}
|
||||||
style.fontSize = this.textSize + "px";
|
style.fontSize = this.textSize + "px";
|
||||||
return style;
|
return style;
|
||||||
@@ -337,14 +271,6 @@ export default {
|
|||||||
'error', 'opensetting', 'launchapp', 'agreeprivacyauthorization'],
|
'error', 'opensetting', 'launchapp', 'agreeprivacyauthorization'],
|
||||||
methods: {
|
methods: {
|
||||||
addStyle,
|
addStyle,
|
||||||
resolveNvueColor(colorValue, fallbackColor) {
|
|
||||||
if (typeof colorValue !== 'string') return fallbackColor;
|
|
||||||
if (colorValue.indexOf('var(') > -1) return fallbackColor;
|
|
||||||
return colorValue;
|
|
||||||
},
|
|
||||||
upThemeVar(varName, fallbackColor) {
|
|
||||||
return getThemeVar(varName, fallbackColor, this.$u);
|
|
||||||
},
|
|
||||||
clickHandler(e: any) {
|
clickHandler(e: any) {
|
||||||
// 非禁止并且非加载中,才能点击
|
// 非禁止并且非加载中,才能点击
|
||||||
if (!this.disabled && !this.loading) {
|
if (!this.disabled && !this.loading) {
|
||||||
@@ -380,6 +306,8 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
/* #ifndef APP-NVUE */
|
/* #ifndef APP-NVUE */
|
||||||
@import "./vue.scss";
|
@import "./vue.scss";
|
||||||
/* #endif */
|
/* #endif */
|
||||||
@@ -406,9 +334,9 @@ $u-button-mini-height: 22px !default;
|
|||||||
$u-button-mini-font-size: 10px !default;
|
$u-button-mini-font-size: 10px !default;
|
||||||
$u-button-mini-min-width: 50px !default;
|
$u-button-mini-min-width: 50px !default;
|
||||||
$u-button-disabled-opacity: 0.5 !default;
|
$u-button-disabled-opacity: 0.5 !default;
|
||||||
$u-button-info-color: $u-main-color !default;
|
$u-button-info-color: #323233 !default;
|
||||||
$u-button-info-background-color: var(--up-button-info-background-color, var(--up-card-bg-color, #fff)) !default;
|
$u-button-info-background-color: #fff !default;
|
||||||
$u-button-info-border-color: $u-border-color !default;
|
$u-button-info-border-color: #ebedf0 !default;
|
||||||
$u-button-info-border-width: 1px !default;
|
$u-button-info-border-width: 1px !default;
|
||||||
$u-button-info-border-style: solid !default;
|
$u-button-info-border-style: solid !default;
|
||||||
$u-button-success-color: #fff !default;
|
$u-button-success-color: #fff !default;
|
||||||
@@ -441,7 +369,7 @@ $u-button-square-border-top-left-radius: 3px !default;
|
|||||||
$u-button-square-border-bottom-left-radius: 3px !default;
|
$u-button-square-border-bottom-left-radius: 3px !default;
|
||||||
$u-button-square-border-bottom-right-radius: 3px !default;
|
$u-button-square-border-bottom-right-radius: 3px !default;
|
||||||
$u-button-icon-min-width: 1em !default;
|
$u-button-icon-min-width: 1em !default;
|
||||||
$u-button-plain-background-color: var(--up-button-plain-background-color, var(--up-card-bg-color, #fff)) !default;
|
$u-button-plain-background-color: #fff !default;
|
||||||
$u-button-hairline-border-width: 0.5px !default;
|
$u-button-hairline-border-width: 0.5px !default;
|
||||||
|
|
||||||
.u-button {
|
.u-button {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ $u-button-plain-u-button-error-color:$u-error;
|
|||||||
$u-button-plain-u-button-warning-color:$u-warning;
|
$u-button-plain-u-button-warning-color:$u-warning;
|
||||||
|
|
||||||
.u-button {
|
.u-button {
|
||||||
width: auto;
|
width: 100%;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
&__text {
|
&__text {
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* @Author : uview-plus
|
|
||||||
* @Description : calendarStrip default props
|
|
||||||
* @version : 3.0
|
|
||||||
* @Date : 2026-05-29 14:40:00
|
|
||||||
*/
|
|
||||||
import { t } from '../../libs/i18n'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
calendarStrip: {
|
|
||||||
modelValue: null,
|
|
||||||
minDate: 0,
|
|
||||||
maxDate: 0,
|
|
||||||
color: '#3c9cff',
|
|
||||||
weekText: [
|
|
||||||
t('up.week.one'),
|
|
||||||
t('up.week.two'),
|
|
||||||
t('up.week.three'),
|
|
||||||
t('up.week.four'),
|
|
||||||
t('up.week.five'),
|
|
||||||
t('up.week.six'),
|
|
||||||
t('up.week.seven')
|
|
||||||
],
|
|
||||||
fullCalendar: true,
|
|
||||||
fullCalendarProps: {},
|
|
||||||
fullMonthNum: 24,
|
|
||||||
pullDownThreshold: 40,
|
|
||||||
collapseAfterSelect: true,
|
|
||||||
readonly: false,
|
|
||||||
showToday: true,
|
|
||||||
monthFormat: '',
|
|
||||||
expandHint: '下拉展开月历',
|
|
||||||
collapseHint: '上拉收起月历'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
|
||||||
import CalendarStripDefaultProps from './calendarStrip'
|
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CalendarStripDefaultProps)
|
|
||||||
export const props = defineMixin({
|
|
||||||
props: {
|
|
||||||
modelValue: {
|
|
||||||
type: [String, Number, Date, null],
|
|
||||||
default: () => defProps.calendarStrip.modelValue
|
|
||||||
},
|
|
||||||
minDate: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: () => defProps.calendarStrip.minDate
|
|
||||||
},
|
|
||||||
maxDate: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: () => defProps.calendarStrip.maxDate
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
type: String,
|
|
||||||
default: () => defProps.calendarStrip.color
|
|
||||||
},
|
|
||||||
weekText: {
|
|
||||||
type: Array,
|
|
||||||
default: () => defProps.calendarStrip.weekText
|
|
||||||
},
|
|
||||||
fullCalendar: {
|
|
||||||
type: Boolean,
|
|
||||||
default: () => defProps.calendarStrip.fullCalendar
|
|
||||||
},
|
|
||||||
fullCalendarProps: {
|
|
||||||
type: Object,
|
|
||||||
default: () => defProps.calendarStrip.fullCalendarProps
|
|
||||||
},
|
|
||||||
fullMonthNum: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: () => defProps.calendarStrip.fullMonthNum
|
|
||||||
},
|
|
||||||
pullDownThreshold: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: () => defProps.calendarStrip.pullDownThreshold
|
|
||||||
},
|
|
||||||
collapseAfterSelect: {
|
|
||||||
type: Boolean,
|
|
||||||
default: () => defProps.calendarStrip.collapseAfterSelect
|
|
||||||
},
|
|
||||||
readonly: {
|
|
||||||
type: Boolean,
|
|
||||||
default: () => defProps.calendarStrip.readonly
|
|
||||||
},
|
|
||||||
showToday: {
|
|
||||||
type: Boolean,
|
|
||||||
default: () => defProps.calendarStrip.showToday
|
|
||||||
},
|
|
||||||
monthFormat: {
|
|
||||||
type: String,
|
|
||||||
default: () => defProps.calendarStrip.monthFormat
|
|
||||||
},
|
|
||||||
expandHint: {
|
|
||||||
type: String,
|
|
||||||
default: () => defProps.calendarStrip.expandHint
|
|
||||||
},
|
|
||||||
collapseHint: {
|
|
||||||
type: String,
|
|
||||||
default: () => defProps.calendarStrip.collapseHint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
@@ -1,507 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view class="u-calendar-strip">
|
|
||||||
<view v-if="!fullCalendar || !innerShowFull">
|
|
||||||
<view class="u-calendar-strip__header u-border-bottom">
|
|
||||||
<text
|
|
||||||
class="u-calendar-strip__header__switch"
|
|
||||||
:class="{ 'u-calendar-strip__header__switch--disabled': switchPrevDisabled }"
|
|
||||||
@tap="prevMonth"
|
|
||||||
>‹</text>
|
|
||||||
<text class="u-calendar-strip__header__title">{{ monthLabel }}</text>
|
|
||||||
<text
|
|
||||||
class="u-calendar-strip__header__switch"
|
|
||||||
:class="{ 'u-calendar-strip__header__switch--disabled': switchNextDisabled }"
|
|
||||||
@tap="nextMonth"
|
|
||||||
>›</text>
|
|
||||||
<text
|
|
||||||
v-if="fullCalendar"
|
|
||||||
class="u-calendar-strip__header__toggle"
|
|
||||||
@click="toggleFull('button')"
|
|
||||||
>▾</text>
|
|
||||||
</view>
|
|
||||||
<view
|
|
||||||
class="u-calendar-strip__scroll-wrap"
|
|
||||||
@touchstart="onTouchStart"
|
|
||||||
@touchend="onTouchEnd"
|
|
||||||
>
|
|
||||||
<scroll-view
|
|
||||||
class="u-calendar-strip__scroll"
|
|
||||||
scroll-x
|
|
||||||
enable-flex
|
|
||||||
:show-scrollbar="false"
|
|
||||||
:scroll-into-view="scrollIntoView"
|
|
||||||
>
|
|
||||||
<view class="u-calendar-strip__scroll__inner">
|
|
||||||
<view
|
|
||||||
v-for="(item, index) in monthDays"
|
|
||||||
:key="index"
|
|
||||||
class="u-calendar-strip__day"
|
|
||||||
:id="getDateId(item.date)"
|
|
||||||
:class="[
|
|
||||||
item.disabled && 'u-calendar-strip__day--disabled',
|
|
||||||
item.selected && 'u-calendar-strip__day--selected',
|
|
||||||
item.today && showToday && !item.selected && 'u-calendar-strip__day--today',
|
|
||||||
]"
|
|
||||||
:style="[dayStyle(item)]"
|
|
||||||
@tap="onDayTap(item)"
|
|
||||||
>
|
|
||||||
<text class="u-calendar-strip__day__date">{{ item.day }}</text>
|
|
||||||
<text class="u-calendar-strip__day__week">{{ getWeekLabel(item.week) }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</scroll-view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view
|
|
||||||
v-if="fullCalendar && innerShowFull"
|
|
||||||
class="u-calendar-strip__panel-wrap"
|
|
||||||
@touchstart="onTouchStart"
|
|
||||||
@touchend="onTouchEnd"
|
|
||||||
>
|
|
||||||
<view class="u-calendar-strip__panel">
|
|
||||||
<u-calendar
|
|
||||||
:show="true"
|
|
||||||
:pageInline="true"
|
|
||||||
:showTitle="false"
|
|
||||||
:showConfirm="false"
|
|
||||||
:closeOnClickOverlay="false"
|
|
||||||
:monthSwitch="true"
|
|
||||||
mode="single"
|
|
||||||
:defaultDate="innerSelectedDate"
|
|
||||||
:minDate="panelMinDate"
|
|
||||||
:maxDate="panelMaxDate"
|
|
||||||
:monthNum="panelMonthNum"
|
|
||||||
:readonly="readonly"
|
|
||||||
:showToday="showToday"
|
|
||||||
:color="color"
|
|
||||||
v-bind="fullCalendarProps"
|
|
||||||
@confirm="onPanelConfirm"
|
|
||||||
></u-calendar>
|
|
||||||
</view>
|
|
||||||
<view class="u-calendar-strip__hint u-calendar-strip__hint--panel">
|
|
||||||
<text class="u-calendar-strip__hint__text" @click="toggleFull('hint')">{{ collapseHint }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { props } from './props'
|
|
||||||
import { mpMixin } from '../../libs/mixin/mpMixin'
|
|
||||||
import { mixin } from '../../libs/mixin/mixin'
|
|
||||||
import dayjs from '../u-datetime-picker/dayjs.esm.min.js'
|
|
||||||
import test from '../../libs/function/test'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CalendarStrip 单行日历
|
|
||||||
* @description 单行横向日期日历,支持切月、下拉展开完整月历
|
|
||||||
*/
|
|
||||||
export default {
|
|
||||||
name: 'u-calendar-strip',
|
|
||||||
mixins: [mpMixin, mixin, props],
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
innerSelectedDate: '',
|
|
||||||
currentMonth: '',
|
|
||||||
scrollIntoView: '',
|
|
||||||
innerShowFull: false,
|
|
||||||
touchStartX: 0,
|
|
||||||
touchStartY: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
innerMaxDate() {
|
|
||||||
return test.number(this.maxDate) ? Number(this.maxDate) : this.maxDate
|
|
||||||
},
|
|
||||||
innerMinDate() {
|
|
||||||
return test.number(this.minDate) ? Number(this.minDate) : this.minDate
|
|
||||||
},
|
|
||||||
rangeChange() {
|
|
||||||
return [this.innerMinDate, this.innerMaxDate]
|
|
||||||
},
|
|
||||||
hasMaxDate() {
|
|
||||||
return !!this.innerMaxDate && dayjs(this.innerMaxDate).isValid()
|
|
||||||
},
|
|
||||||
hasMinDate() {
|
|
||||||
return !!this.innerMinDate && dayjs(this.innerMinDate).isValid()
|
|
||||||
},
|
|
||||||
minDateDay() {
|
|
||||||
if (!this.hasMinDate) return ''
|
|
||||||
return dayjs(this.innerMinDate).format('YYYY-MM-DD')
|
|
||||||
},
|
|
||||||
maxDateDay() {
|
|
||||||
if (!this.hasMaxDate) return ''
|
|
||||||
return dayjs(this.innerMaxDate).format('YYYY-MM-DD')
|
|
||||||
},
|
|
||||||
todayDate() {
|
|
||||||
return dayjs().format('YYYY-MM-DD')
|
|
||||||
},
|
|
||||||
monthLabel() {
|
|
||||||
if (!this.currentMonth) return ''
|
|
||||||
const date = dayjs(`${this.currentMonth}-01`)
|
|
||||||
if (this.monthFormat) return date.format(this.monthFormat)
|
|
||||||
if (uni.getLocale() == 'zh-Hans' || uni.getLocale() == 'zh-Hant') {
|
|
||||||
return date.format('YYYY年MM月')
|
|
||||||
}
|
|
||||||
return date.format('MM/YYYY')
|
|
||||||
},
|
|
||||||
monthDays() {
|
|
||||||
if (!this.currentMonth) return []
|
|
||||||
const start = dayjs(`${this.currentMonth}-01`)
|
|
||||||
const days = start.daysInMonth()
|
|
||||||
return new Array(days).fill(0).map((item, index) => {
|
|
||||||
const date = start.date(index + 1).format('YYYY-MM-DD')
|
|
||||||
return {
|
|
||||||
day: index + 1,
|
|
||||||
date,
|
|
||||||
week: start.date(index + 1).day(),
|
|
||||||
disabled: this.isDateDisabled(date),
|
|
||||||
selected: this.dateSame(date, this.innerSelectedDate),
|
|
||||||
today: this.dateSame(date, this.todayDate)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
switchPrevDisabled() {
|
|
||||||
if (!this.hasMinDate || !this.currentMonth) return false
|
|
||||||
const current = dayjs(`${this.currentMonth}-01`)
|
|
||||||
const minMonth = dayjs(this.minDateDay).startOf('month')
|
|
||||||
return current.isSame(minMonth, 'month') || current.isBefore(minMonth, 'month')
|
|
||||||
},
|
|
||||||
switchNextDisabled() {
|
|
||||||
if (!this.hasMaxDate || !this.currentMonth) return false
|
|
||||||
const current = dayjs(`${this.currentMonth}-01`)
|
|
||||||
const maxMonth = dayjs(this.maxDateDay).startOf('month')
|
|
||||||
return current.isSame(maxMonth, 'month') || current.isAfter(maxMonth, 'month')
|
|
||||||
},
|
|
||||||
panelMinDate() {
|
|
||||||
if (this.hasMinDate) return this.minDateDay
|
|
||||||
const monthNum = Math.max(1, Number(this.fullMonthNum) || 24)
|
|
||||||
const anchor = this.currentMonth || dayjs().format('YYYY-MM')
|
|
||||||
return dayjs(`${anchor}-01`).subtract(monthNum - 1, 'month').startOf('month').format('YYYY-MM-DD')
|
|
||||||
},
|
|
||||||
panelMaxDate() {
|
|
||||||
if (this.hasMaxDate) return this.maxDateDay
|
|
||||||
const monthNum = Math.max(1, Number(this.fullMonthNum) || 24)
|
|
||||||
const anchor = this.currentMonth || dayjs().format('YYYY-MM')
|
|
||||||
return dayjs(`${anchor}-01`).add(monthNum - 1, 'month').endOf('month').format('YYYY-MM-DD')
|
|
||||||
},
|
|
||||||
panelMonthNum() {
|
|
||||||
return this.getMonths(this.panelMinDate, this.panelMaxDate)
|
|
||||||
},
|
|
||||||
pullHintText() {
|
|
||||||
return this.innerShowFull ? this.collapseHint : this.expandHint
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
modelValue: {
|
|
||||||
immediate: true,
|
|
||||||
handler(n) {
|
|
||||||
this.syncByValue(n, false, 'sync')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
rangeChange() {
|
|
||||||
this.syncByValue(this.innerSelectedDate || this.modelValue, true, 'range')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['change', 'confirm', 'monthChange', 'toggleFull', 'update:modelValue'],
|
|
||||||
methods: {
|
|
||||||
dateSame(date1, date2) {
|
|
||||||
if (!date1 || !date2) return false
|
|
||||||
return dayjs(date1).isSame(dayjs(date2), 'day')
|
|
||||||
},
|
|
||||||
normalizeDate(value) {
|
|
||||||
if (!value) return ''
|
|
||||||
const parsed = dayjs(value)
|
|
||||||
if (!parsed.isValid()) return ''
|
|
||||||
return parsed.format('YYYY-MM-DD')
|
|
||||||
},
|
|
||||||
clampDate(date) {
|
|
||||||
let next = this.normalizeDate(date)
|
|
||||||
if (!next) return ''
|
|
||||||
if (this.hasMinDate && dayjs(next).isBefore(dayjs(this.minDateDay), 'day')) {
|
|
||||||
next = this.minDateDay
|
|
||||||
}
|
|
||||||
if (this.hasMaxDate && dayjs(next).isAfter(dayjs(this.maxDateDay), 'day')) {
|
|
||||||
next = this.maxDateDay
|
|
||||||
}
|
|
||||||
return next
|
|
||||||
},
|
|
||||||
isDateDisabled(date) {
|
|
||||||
if (!date) return true
|
|
||||||
if (this.hasMinDate && dayjs(date).isBefore(dayjs(this.minDateDay), 'day')) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (this.hasMaxDate && dayjs(date).isAfter(dayjs(this.maxDateDay), 'day')) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
getDateId(date) {
|
|
||||||
return `u-calendar-strip-day-${dayjs(date).format('YYYYMMDD')}`
|
|
||||||
},
|
|
||||||
getWeekLabel(week) {
|
|
||||||
const index = week === 0 ? 6 : week - 1
|
|
||||||
return this.weekText[index] || ''
|
|
||||||
},
|
|
||||||
dayStyle(item) {
|
|
||||||
const style = {}
|
|
||||||
if (item.selected) {
|
|
||||||
style.backgroundColor = this.color
|
|
||||||
}
|
|
||||||
if (!item.selected && item.today && this.showToday) {
|
|
||||||
style.borderColor = this.color
|
|
||||||
}
|
|
||||||
return style
|
|
||||||
},
|
|
||||||
scrollToDate(date) {
|
|
||||||
if (!date) {
|
|
||||||
this.scrollIntoView = ''
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const target = this.getDateId(date)
|
|
||||||
this.scrollIntoView = ''
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.scrollIntoView = target
|
|
||||||
})
|
|
||||||
},
|
|
||||||
syncByValue(value, emit = false, scene = 'sync') {
|
|
||||||
let next = this.clampDate(value)
|
|
||||||
if (!next) {
|
|
||||||
next = this.clampDate(this.todayDate)
|
|
||||||
}
|
|
||||||
if (!next) return
|
|
||||||
this.setSelectedDate(next, scene, emit)
|
|
||||||
},
|
|
||||||
setSelectedDate(date, scene = 'tap', emit = true) {
|
|
||||||
const next = this.clampDate(date)
|
|
||||||
if (!next || this.isDateDisabled(next)) return
|
|
||||||
const prevDate = this.innerSelectedDate
|
|
||||||
const prevMonth = this.currentMonth
|
|
||||||
this.innerSelectedDate = next
|
|
||||||
this.currentMonth = dayjs(next).format('YYYY-MM')
|
|
||||||
this.scrollToDate(next)
|
|
||||||
if (!emit) return
|
|
||||||
const payload = {
|
|
||||||
date: next,
|
|
||||||
month: this.currentMonth,
|
|
||||||
scene
|
|
||||||
}
|
|
||||||
if (!this.dateSame(prevDate, next)) {
|
|
||||||
this.$emit('update:modelValue', next)
|
|
||||||
}
|
|
||||||
this.$emit('change', payload)
|
|
||||||
this.$emit('confirm', payload)
|
|
||||||
if (prevMonth !== this.currentMonth) {
|
|
||||||
this.$emit('monthChange', {
|
|
||||||
month: this.currentMonth,
|
|
||||||
scene
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
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 Math.max(1, (maxYear - minYear) * 12 + (maxMonth - minMonth) + 1)
|
|
||||||
},
|
|
||||||
findFirstEnabledDate(month) {
|
|
||||||
const start = dayjs(`${month}-01`)
|
|
||||||
const days = start.daysInMonth()
|
|
||||||
for (let i = 1; i <= days; i++) {
|
|
||||||
const date = start.date(i).format('YYYY-MM-DD')
|
|
||||||
if (!this.isDateDisabled(date)) {
|
|
||||||
return date
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
},
|
|
||||||
switchMonth(step = 0) {
|
|
||||||
if (step < 0 && this.switchPrevDisabled) return
|
|
||||||
if (step > 0 && this.switchNextDisabled) return
|
|
||||||
const baseMonth = this.currentMonth || dayjs(this.todayDate).format('YYYY-MM')
|
|
||||||
const target = dayjs(`${baseMonth}-01`).add(step, 'month')
|
|
||||||
const targetMonth = target.format('YYYY-MM')
|
|
||||||
const selectedDay = dayjs(this.innerSelectedDate || this.todayDate).date()
|
|
||||||
const dayInTargetMonth = Math.min(selectedDay, target.daysInMonth())
|
|
||||||
let next = target.date(dayInTargetMonth).format('YYYY-MM-DD')
|
|
||||||
next = this.clampDate(next)
|
|
||||||
if (!next || !dayjs(next).isSame(target, 'month') || this.isDateDisabled(next)) {
|
|
||||||
next = this.findFirstEnabledDate(targetMonth)
|
|
||||||
}
|
|
||||||
if (!next) return
|
|
||||||
this.setSelectedDate(next, 'switch', true)
|
|
||||||
},
|
|
||||||
prevMonth() {
|
|
||||||
this.switchMonth(-1)
|
|
||||||
},
|
|
||||||
nextMonth() {
|
|
||||||
this.switchMonth(1)
|
|
||||||
},
|
|
||||||
onDayTap(item) {
|
|
||||||
if (this.readonly || item.disabled) return
|
|
||||||
this.setSelectedDate(item.date, 'tap', true)
|
|
||||||
},
|
|
||||||
setFullVisible(show, source = 'button') {
|
|
||||||
if (!this.fullCalendar) return
|
|
||||||
if (this.innerShowFull === show) return
|
|
||||||
this.innerShowFull = show
|
|
||||||
this.$emit('toggleFull', {
|
|
||||||
show,
|
|
||||||
source
|
|
||||||
})
|
|
||||||
},
|
|
||||||
toggleFull(source = 'button') {
|
|
||||||
this.setFullVisible(!this.innerShowFull, source)
|
|
||||||
},
|
|
||||||
onPanelConfirm(e) {
|
|
||||||
if (!Array.isArray(e) || !e.length) return
|
|
||||||
this.setSelectedDate(e[0], 'full', true)
|
|
||||||
if (this.collapseAfterSelect) {
|
|
||||||
this.setFullVisible(false, 'auto')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onTouchStart(event) {
|
|
||||||
if (!this.fullCalendar) return
|
|
||||||
const point = event?.changedTouches?.[0] || event?.touches?.[0]
|
|
||||||
if (!point) return
|
|
||||||
this.touchStartX = point.clientX
|
|
||||||
this.touchStartY = point.clientY
|
|
||||||
},
|
|
||||||
onTouchEnd(event) {
|
|
||||||
if (!this.fullCalendar) return
|
|
||||||
const point = event?.changedTouches?.[0] || event?.touches?.[0]
|
|
||||||
if (!point) return
|
|
||||||
const deltaX = point.clientX - this.touchStartX
|
|
||||||
const deltaY = point.clientY - this.touchStartY
|
|
||||||
const threshold = Number(this.pullDownThreshold) || 40
|
|
||||||
if (Math.abs(deltaY) < threshold || Math.abs(deltaY) <= Math.abs(deltaX)) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (deltaY > 0 && !this.innerShowFull) {
|
|
||||||
this.setFullVisible(true, 'pull-down')
|
|
||||||
}
|
|
||||||
if (deltaY < 0 && this.innerShowFull) {
|
|
||||||
this.setFullVisible(false, 'pull-up')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.u-calendar-strip {
|
|
||||||
background-color: var(--up-card-bg-color, #ffffff);
|
|
||||||
border-radius: 10px;
|
|
||||||
margin: 0 8px;
|
|
||||||
|
|
||||||
&__header {
|
|
||||||
@include flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 0 4px;
|
|
||||||
height: 40px;
|
|
||||||
|
|
||||||
&__switch {
|
|
||||||
width: 40px;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 20px;
|
|
||||||
line-height: 40px;
|
|
||||||
color: var(--up-main-color, $u-main-color);
|
|
||||||
|
|
||||||
&--disabled {
|
|
||||||
opacity: 0.35;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__title {
|
|
||||||
flex: 1;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--up-main-color, $u-main-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__toggle {
|
|
||||||
width: 40px;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 40px;
|
|
||||||
color: var(--up-content-color, $u-content-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__scroll-wrap {
|
|
||||||
padding: 10px 0 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__scroll {
|
|
||||||
&__inner {
|
|
||||||
@include flex;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__day {
|
|
||||||
width: 54px;
|
|
||||||
height: 62px;
|
|
||||||
margin-right: 8px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
@include flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
&__date {
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 22px;
|
|
||||||
color: var(--up-main-color, $u-main-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
&__week {
|
|
||||||
margin-top: 4px;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 16px;
|
|
||||||
color: var(--up-content-color, $u-content-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
&--selected {
|
|
||||||
.u-calendar-strip__day__date,
|
|
||||||
.u-calendar-strip__day__week {
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--today {
|
|
||||||
border-style: solid;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--disabled {
|
|
||||||
opacity: 0.4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__hint {
|
|
||||||
padding: 4px 0 10px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
&__text {
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--up-tips-color, $u-tips-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__panel {
|
|
||||||
padding: 0 8px 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__panel-wrap {
|
|
||||||
padding-top: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__hint--panel {
|
|
||||||
padding: 0 0 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,22 +1,21 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:52:43
|
||||||
* @FilePath : /uview-plus/libs/config/props/calendar.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/calendar.js
|
||||||
*/
|
*/
|
||||||
import { t } from '../../libs/i18n'
|
|
||||||
export default {
|
export default {
|
||||||
// calendar 组件
|
// calendar 组件
|
||||||
calendar: {
|
calendar: {
|
||||||
title: t("up.calendar.chooseDates"),
|
title: '日期选择',
|
||||||
showTitle: true,
|
showTitle: true,
|
||||||
showSubtitle: true,
|
showSubtitle: true,
|
||||||
mode: 'single',
|
mode: 'single',
|
||||||
startText: t("up.common.start"),
|
startText: '开始',
|
||||||
endText: t("up.common.end"),
|
endText: '结束',
|
||||||
customList: [],
|
customList: [],
|
||||||
color: '#3c9cff',
|
color: '#3c9cff',
|
||||||
minDate: 0,
|
minDate: 0,
|
||||||
@@ -27,8 +26,8 @@ export default {
|
|||||||
formatter: null,
|
formatter: null,
|
||||||
showLunar: false,
|
showLunar: false,
|
||||||
showMark: true,
|
showMark: true,
|
||||||
confirmText: t("up.common.confirm"),
|
confirmText: '确定',
|
||||||
confirmDisabledText: t("up.common.confirm"),
|
confirmDisabledText: '确定',
|
||||||
show: false,
|
show: false,
|
||||||
closeOnClickOverlay: false,
|
closeOnClickOverlay: false,
|
||||||
readonly: false,
|
readonly: false,
|
||||||
@@ -37,27 +36,10 @@ export default {
|
|||||||
rangePrompt: '',
|
rangePrompt: '',
|
||||||
showRangePrompt: true,
|
showRangePrompt: true,
|
||||||
allowSameDay: false,
|
allowSameDay: false,
|
||||||
rangeResultMode: 'all',
|
|
||||||
enableTime: false,
|
|
||||||
timePrecision: 'minute',
|
|
||||||
defaultTime: '',
|
|
||||||
round: 0,
|
round: 0,
|
||||||
overlay: true,
|
|
||||||
duration: 300,
|
|
||||||
overlayStyle: {},
|
|
||||||
overlayOpacity: 0.5,
|
|
||||||
zIndex: 10075,
|
|
||||||
safeAreaInsetBottom: true,
|
|
||||||
safeAreaInsetTop: false,
|
|
||||||
bgColor: '',
|
|
||||||
monthNum: 3,
|
monthNum: 3,
|
||||||
monthSwitch: false,
|
weekText: ['一', '二', '三', '四', '五', '六', '日'],
|
||||||
showToday: true,
|
|
||||||
todayColor: '',
|
|
||||||
weekText: [t("up.week.one"), t("up.week.two"), t("up.week.three"), t("up.week.four"), t("up.week.five"), t("up.week.six"), t("up.week.seven")],
|
|
||||||
forbidDays: [],
|
forbidDays: [],
|
||||||
forbidDaysToast: t("up.calendar.disabled"),
|
forbidDaysToast: '该日期已禁用',
|
||||||
monthFormat: '',
|
|
||||||
pageInline: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,42 +4,10 @@
|
|||||||
class="u-calendar-header__title"
|
class="u-calendar-header__title"
|
||||||
v-if="showTitle"
|
v-if="showTitle"
|
||||||
>{{ title }}</text>
|
>{{ title }}</text>
|
||||||
<view
|
<text
|
||||||
class="u-calendar-header__subtitle-wrap"
|
class="u-calendar-header__subtitle"
|
||||||
v-if="showSubtitle"
|
v-if="showSubtitle"
|
||||||
>
|
>{{ subtitle }}</text>
|
||||||
<text
|
|
||||||
v-if="showSwitch"
|
|
||||||
class="u-calendar-header__switch"
|
|
||||||
:class="{ 'u-calendar-header__switch--disabled': prevYearDisabled }"
|
|
||||||
@click="prevYear"
|
|
||||||
>«</text>
|
|
||||||
<text
|
|
||||||
v-if="showSwitch"
|
|
||||||
class="u-calendar-header__switch"
|
|
||||||
:class="{ 'u-calendar-header__switch--disabled': prevDisabled }"
|
|
||||||
@click="prev"
|
|
||||||
>‹</text>
|
|
||||||
<text class="u-calendar-header__subtitle">{{ subtitle }}</text>
|
|
||||||
<text
|
|
||||||
v-if="showSwitch"
|
|
||||||
class="u-calendar-header__switch"
|
|
||||||
:class="{ 'u-calendar-header__switch--disabled': nextDisabled }"
|
|
||||||
@click="next"
|
|
||||||
>›</text>
|
|
||||||
<text
|
|
||||||
v-if="showSwitch"
|
|
||||||
class="u-calendar-header__switch"
|
|
||||||
:class="{ 'u-calendar-header__switch--disabled': nextYearDisabled }"
|
|
||||||
@click="nextYear"
|
|
||||||
>»</text>
|
|
||||||
<text
|
|
||||||
v-if="showToday"
|
|
||||||
class="u-calendar-header__today"
|
|
||||||
:class="{ 'u-calendar-header__today--disabled': todayDisabled }"
|
|
||||||
@click="today"
|
|
||||||
>{{ todayText }}</text>
|
|
||||||
</view>
|
|
||||||
<view class="u-calendar-header__weekdays">
|
<view class="u-calendar-header__weekdays">
|
||||||
<text class="u-calendar-header__weekdays__weekday">{{ weekText[0] }}</text>
|
<text class="u-calendar-header__weekdays__weekday">{{ weekText[0] }}</text>
|
||||||
<text class="u-calendar-header__weekdays__weekday">{{ weekText[1] }}</text>
|
<text class="u-calendar-header__weekdays__weekday">{{ weekText[1] }}</text>
|
||||||
@@ -83,49 +51,9 @@
|
|||||||
weekText: {
|
weekText: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => {
|
default: () => {
|
||||||
return []
|
return ['一', '二', '三', '四', '五', '六', '日']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 是否显示月份切换按钮
|
|
||||||
showSwitch: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 上个月按钮是否禁用
|
|
||||||
prevDisabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 下个月按钮是否禁用
|
|
||||||
nextDisabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 上一年按钮是否禁用
|
|
||||||
prevYearDisabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 下一年按钮是否禁用
|
|
||||||
nextYearDisabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 是否显示今天按钮
|
|
||||||
showToday: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
// 今天按钮文案
|
|
||||||
todayText: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
// 今天按钮是否禁用
|
|
||||||
todayDisabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -133,36 +61,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
prev() {
|
name() {
|
||||||
if (!this.prevDisabled) {
|
|
||||||
this.$emit('prev')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
next() {
|
|
||||||
if (!this.nextDisabled) {
|
|
||||||
this.$emit('next')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
prevYear() {
|
|
||||||
if (!this.prevYearDisabled) {
|
|
||||||
this.$emit('prevYear')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
nextYear() {
|
|
||||||
if (!this.nextYearDisabled) {
|
|
||||||
this.$emit('nextYear')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
today() {
|
|
||||||
if (!this.todayDisabled) {
|
|
||||||
this.$emit('today')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-calendar-header {
|
.u-calendar-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -171,41 +78,20 @@
|
|||||||
|
|
||||||
&__title {
|
&__title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: var(--up-main-color, $u-main-color);
|
color: $u-main-color;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
height: 42px;
|
height: 42px;
|
||||||
line-height: 42px;
|
line-height: 42px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__subtitle-wrap {
|
|
||||||
@include flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__subtitle {
|
&__subtitle {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--up-main-color, $u-main-color);
|
color: $u-main-color;
|
||||||
text-align: center;
|
|
||||||
font-weight: bold;
|
|
||||||
min-width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__switch {
|
|
||||||
width: 44px;
|
|
||||||
height: 40px;
|
height: 40px;
|
||||||
line-height: 40px;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: var(--up-main-color, $u-main-color);
|
line-height: 40px;
|
||||||
font-size: 22px;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
&--disabled {
|
|
||||||
opacity: 0.35;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__weekdays {
|
&__weekdays {
|
||||||
@@ -214,27 +100,11 @@
|
|||||||
|
|
||||||
&__weekday {
|
&__weekday {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: var(--up-main-color, $u-main-color);
|
color: $u-main-color;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__today {
|
|
||||||
margin-left: 4px;
|
|
||||||
height: 28px;
|
|
||||||
line-height: 28px;
|
|
||||||
padding: 0 10px;
|
|
||||||
border-radius: 14px;
|
|
||||||
font-size: 13px;
|
|
||||||
color: var(--up-primary, $u-primary);
|
|
||||||
border: 1px solid var(--up-primary, $u-primary);
|
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
&--disabled {
|
|
||||||
opacity: 0.35;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<view class="u-calendar-month-wrapper" ref="u-calendar-month-wrapper">
|
<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}`]"
|
<view v-for="(item, index) in months" :key="index" :class="[`u-calendar-month-${index}`]"
|
||||||
:ref="`u-calendar-month-${index}`" :id="`month-${index}`">
|
:ref="`u-calendar-month-${index}`" :id="`month-${index}`">
|
||||||
<text v-if="index !== 0" class="u-calendar-month__title">{{ monthTitle(item) }}</text>
|
<text v-if="index !== 0" class="u-calendar-month__title">{{ item.year }}年{{ item.month }}月</text>
|
||||||
<view class="u-calendar-month__days">
|
<view class="u-calendar-month__days">
|
||||||
<view v-if="showMark" class="u-calendar-month__days__month-mark-wrapper">
|
<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>
|
<text class="u-calendar-month__days__month-mark-wrapper__text">{{ item.month }}</text>
|
||||||
@@ -33,12 +33,11 @@
|
|||||||
// #endif
|
// #endif
|
||||||
import { mpMixin } from '../../libs/mixin/mpMixin';
|
import { mpMixin } from '../../libs/mixin/mpMixin';
|
||||||
import { mixin } from '../../libs/mixin/mixin';
|
import { mixin } from '../../libs/mixin/mixin';
|
||||||
import { addUnit, deepClone, toast, sleep, getWindowInfo } from '../../libs/function/index';
|
import { addUnit, deepClone, toast, sleep } from '../../libs/function/index';
|
||||||
import { colorGradient } from '../../libs/function/colorGradient';
|
import { colorGradient } from '../../libs/function/colorGradient';
|
||||||
import test from '../../libs/function/test';
|
import test from '../../libs/function/test';
|
||||||
import defProps from '../../libs/config/props';
|
import defProps from '../../libs/config/props';
|
||||||
import dayjs from '../u-datetime-picker/dayjs.esm.min.js';
|
import dayjs from 'dayjs/esm/index'
|
||||||
import { t } from '../../libs/i18n'
|
|
||||||
export default {
|
export default {
|
||||||
name: 'u-calendar-month',
|
name: 'u-calendar-month',
|
||||||
mixins: [mpMixin, mixin],
|
mixins: [mpMixin, mixin],
|
||||||
@@ -135,16 +134,6 @@
|
|||||||
forbidDaysToast: {
|
forbidDaysToast: {
|
||||||
type: String,
|
type: String,
|
||||||
default: ''
|
default: ''
|
||||||
},
|
|
||||||
// 今天日期,用于独立高亮
|
|
||||||
todayDate: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
// 今天日期的独立高亮颜色
|
|
||||||
todayColor: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -173,24 +162,17 @@
|
|||||||
return (index1, index2, item) => {
|
return (index1, index2, item) => {
|
||||||
const style = {}
|
const style = {}
|
||||||
let week = item.week
|
let week = item.week
|
||||||
// 隐藏挂载场景下节点宽度可能拿到0,兜底使用窗口宽度避免首日偏移归零
|
|
||||||
const wrapperWidth = this.width > 0 ? this.width : (getWindowInfo().windowWidth || 0)
|
|
||||||
// 不进行四舍五入的形式保留2位小数
|
// 不进行四舍五入的形式保留2位小数
|
||||||
const dayWidth = Number(parseFloat(wrapperWidth / 7).toFixed(3).slice(0, -1))
|
const dayWidth = Number(parseFloat(this.width / 7).toFixed(3).slice(0, -1))
|
||||||
// 得出每个日期的宽度
|
// 得出每个日期的宽度
|
||||||
// #ifdef APP-NVUE
|
// #ifdef APP-NVUE
|
||||||
style.width = addUnit(dayWidth, 'px')
|
style.width = addUnit(dayWidth, 'px')
|
||||||
// #endif
|
// #endif
|
||||||
style.height = addUnit(this.rowHeight, 'px')
|
style.height = addUnit(this.rowHeight)
|
||||||
if (index2 === 0) {
|
if (index2 === 0) {
|
||||||
// 获取当前为星期几,如果为0,则为星期天,减一为每月第一天时,需要向左偏移的item个数
|
// 获取当前为星期几,如果为0,则为星期天,减一为每月第一天时,需要向左偏移的item个数
|
||||||
week = (week === 0 ? 7 : week) - 1
|
week = (week === 0 ? 7 : week) - 1
|
||||||
// #ifdef APP-NVUE
|
|
||||||
style.marginLeft = addUnit(week * dayWidth, 'px')
|
style.marginLeft = addUnit(week * dayWidth, 'px')
|
||||||
// #endif
|
|
||||||
// #ifndef APP-NVUE
|
|
||||||
style.marginLeft = `${(week / 7) * 100}%`
|
|
||||||
// #endif
|
|
||||||
}
|
}
|
||||||
if (this.mode === 'range') {
|
if (this.mode === 'range') {
|
||||||
// 之所以需要这么写,是因为DCloud公司的iOS客户端导致的bug
|
// 之所以需要这么写,是因为DCloud公司的iOS客户端导致的bug
|
||||||
@@ -210,10 +192,6 @@
|
|||||||
if (this.selected.some(item => this.dateSame(item, date))) {
|
if (this.selected.some(item => this.dateSame(item, date))) {
|
||||||
style.backgroundColor = this.color
|
style.backgroundColor = this.color
|
||||||
}
|
}
|
||||||
if (this.todayDate && this.dateSame(date, this.todayDate)) {
|
|
||||||
style.border = `1px solid ${this.resolvedTodayColor}`
|
|
||||||
style.boxSizing = 'border-box'
|
|
||||||
}
|
|
||||||
if (this.mode === 'single') {
|
if (this.mode === 'single') {
|
||||||
if (date === this.selected[0]) {
|
if (date === this.selected[0]) {
|
||||||
// 因为需要对nvue的兼容,只能这么写,无法缩写,也无法通过类名控制等等
|
// 因为需要对nvue的兼容,只能这么写,无法缩写,也无法通过类名控制等等
|
||||||
@@ -238,13 +216,12 @@
|
|||||||
// 处于第一和最后一个之间的日期,背景色设置为浅色,通过将对应颜色进行等分,再取其尾部的颜色值
|
// 处于第一和最后一个之间的日期,背景色设置为浅色,通过将对应颜色进行等分,再取其尾部的颜色值
|
||||||
if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
|
if (dayjs(date).isAfter(dayjs(this.selected[0])) && dayjs(date).isBefore(dayjs(this
|
||||||
.selected[len]))) {
|
.selected[len]))) {
|
||||||
const rangeEndColor = this.upThemeVar('--up-card-bg-color', this.upThemeIsDark ? '#1c1c1e' : '#ffffff')
|
style.backgroundColor = colorGradient(this.color, '#ffffff', 100)[90]
|
||||||
style.backgroundColor = colorGradient(this.color, rangeEndColor, 100)[90]
|
|
||||||
// 增加一个透明度,让范围区间的背景色也能看到底部的mark水印字符
|
// 增加一个透明度,让范围区间的背景色也能看到底部的mark水印字符
|
||||||
style.opacity = this.upThemeIsDark ? 0.85 : 0.7
|
style.opacity = 0.7
|
||||||
}
|
}
|
||||||
} else if (this.selected.length === 1) {
|
} else if (this.selected.length === 1) {
|
||||||
// 之所以需要这么写,是因为uni-app的iOS客户端的bug
|
// 之所以需要这么写,是因为DCloud公司的iOS客户端的开发者能力有限导致的bug
|
||||||
// 进行还原操作,否则在nvue的iOS,uni-app有bug,会导致诡异的表现
|
// 进行还原操作,否则在nvue的iOS,uni-app有bug,会导致诡异的表现
|
||||||
style.borderTopLeftRadius = '3px'
|
style.borderTopLeftRadius = '3px'
|
||||||
style.borderBottomLeftRadius = '3px'
|
style.borderBottomLeftRadius = '3px'
|
||||||
@@ -260,9 +237,6 @@
|
|||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
resolvedTodayColor() {
|
|
||||||
return this.todayColor || this.color
|
|
||||||
},
|
|
||||||
// 某个日期是否被选中
|
// 某个日期是否被选中
|
||||||
textStyle() {
|
textStyle() {
|
||||||
return (item) => {
|
return (item) => {
|
||||||
@@ -280,9 +254,6 @@
|
|||||||
style.color = this.color
|
style.color = this.color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (this.todayDate && this.dateSame(date, this.todayDate) && !this.isSelectedDate(date)) {
|
|
||||||
style.color = this.resolvedTodayColor
|
|
||||||
}
|
|
||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -321,7 +292,6 @@
|
|||||||
mounted() {
|
mounted() {
|
||||||
this.init()
|
this.init()
|
||||||
},
|
},
|
||||||
emits: ['monthSelected', 'updateMonthTop'],
|
|
||||||
methods: {
|
methods: {
|
||||||
init() {
|
init() {
|
||||||
// 初始化默认选中
|
// 初始化默认选中
|
||||||
@@ -335,13 +305,6 @@
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
monthTitle(item) {
|
|
||||||
if (uni.getLocale() == 'zh-Hans' || uni.getLocale() == 'zh-Hant') {
|
|
||||||
return item.year + '年' + (item.month < 10 ? '0' + item.month : item.month) + '月'
|
|
||||||
} else {
|
|
||||||
return (item.month < 10 ? '0' + item.month : item.month) + '/' + item.year
|
|
||||||
}
|
|
||||||
},
|
|
||||||
isForbid(item) {
|
isForbid(item) {
|
||||||
let date = dayjs(item.date).format("YYYY-MM-DD")
|
let date = dayjs(item.date).format("YYYY-MM-DD")
|
||||||
if (this.mode !== 'range' && this.forbidDays.includes(date)) {
|
if (this.mode !== 'range' && this.forbidDays.includes(date)) {
|
||||||
@@ -353,21 +316,16 @@
|
|||||||
dateSame(date1, date2) {
|
dateSame(date1, date2) {
|
||||||
return dayjs(date1).isSame(dayjs(date2))
|
return dayjs(date1).isSame(dayjs(date2))
|
||||||
},
|
},
|
||||||
isSelectedDate(date) {
|
|
||||||
return this.selected.some(item => this.dateSame(item, date))
|
|
||||||
},
|
|
||||||
// 获取月份数据区域的宽度,因为nvue不支持百分比,所以无法通过css设置每个日期item的宽度
|
// 获取月份数据区域的宽度,因为nvue不支持百分比,所以无法通过css设置每个日期item的宽度
|
||||||
getWrapperWidth() {
|
getWrapperWidth() {
|
||||||
// #ifdef APP-NVUE
|
// #ifdef APP-NVUE
|
||||||
dom.getComponentRect(this.$refs['u-calendar-month-wrapper'], res => {
|
dom.getComponentRect(this.$refs['u-calendar-month-wrapper'], res => {
|
||||||
const width = res && res.size ? Number(res.size.width) : 0
|
this.width = res.size.width
|
||||||
this.width = width > 0 ? width : (getWindowInfo().windowWidth || 0)
|
|
||||||
})
|
})
|
||||||
// #endif
|
// #endif
|
||||||
// #ifndef APP-NVUE
|
// #ifndef APP-NVUE
|
||||||
this.$uGetRect('.u-calendar-month-wrapper').then(size => {
|
this.$uGetRect('.u-calendar-month-wrapper').then(size => {
|
||||||
const width = size ? Number(size.width) : 0
|
this.width = size.width
|
||||||
this.width = width > 0 ? width : (getWindowInfo().windowWidth || 0)
|
|
||||||
})
|
})
|
||||||
// #endif
|
// #endif
|
||||||
},
|
},
|
||||||
@@ -392,7 +350,7 @@
|
|||||||
// 获取每个月份区域的尺寸
|
// 获取每个月份区域的尺寸
|
||||||
getMonthRectByPromise(el) {
|
getMonthRectByPromise(el) {
|
||||||
// #ifndef APP-NVUE
|
// #ifndef APP-NVUE
|
||||||
// $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://uview-plus.jiangruyi.com/js/getRect.html
|
// $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://ijry.github.io/uview-plus/js/getRect.html
|
||||||
// 组件内部一般用this.$uGetRect,对外的为uni.$u.getRect,二者功能一致,名称不同
|
// 组件内部一般用this.$uGetRect,对外的为uni.$u.getRect,二者功能一致,名称不同
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
this.$uGetRect(`.${el}`).then(size => {
|
this.$uGetRect(`.${el}`).then(size => {
|
||||||
@@ -456,7 +414,7 @@
|
|||||||
if(this.rangePrompt) {
|
if(this.rangePrompt) {
|
||||||
toast(this.rangePrompt)
|
toast(this.rangePrompt)
|
||||||
} else {
|
} else {
|
||||||
toast(t("up.calendar.daysExceed", { days: this.maxRange }))
|
toast(`选择天数不能超过 ${this.maxRange} 天`)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -516,24 +474,13 @@
|
|||||||
setSelected(selected, event = true) {
|
setSelected(selected, event = true) {
|
||||||
this.selected = selected
|
this.selected = selected
|
||||||
event && this.$emit('monthSelected', this.selected,'tap')
|
event && this.$emit('monthSelected', this.selected,'tap')
|
||||||
},
|
|
||||||
selectDate(date) {
|
|
||||||
const targetDate = dayjs(date).format("YYYY-MM-DD")
|
|
||||||
for (let monthIndex = 0; monthIndex < this.months.length; monthIndex++) {
|
|
||||||
const dayIndex = this.months[monthIndex].date.findIndex(item => {
|
|
||||||
return this.dateSame(item.date, targetDate)
|
|
||||||
})
|
|
||||||
if (dayIndex !== -1) {
|
|
||||||
this.clickHandler(monthIndex, dayIndex, this.months[monthIndex].date[dayIndex])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-calendar-month-wrapper {
|
.u-calendar-month-wrapper {
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
@@ -547,7 +494,7 @@
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 42px;
|
line-height: 42px;
|
||||||
height: 42px;
|
height: 42px;
|
||||||
color: var(--up-main-color, $u-main-color);
|
color: $u-main-color;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
@@ -569,7 +516,7 @@
|
|||||||
|
|
||||||
&__text {
|
&__text {
|
||||||
font-size: 155px;
|
font-size: 155px;
|
||||||
color: var(--up-calendar-month-mark-color, rgba(231, 232, 234, 0.83));
|
color: rgba(231, 232, 234, 0.83);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,7 +547,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&__buttom-info {
|
&__buttom-info {
|
||||||
color: var(--up-content-color, $u-content-color);
|
color: $u-content-color;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 5px;
|
bottom: 5px;
|
||||||
@@ -614,21 +561,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&--disabled {
|
&--disabled {
|
||||||
color: var(--up-disabled-color, #cacbcd);
|
color: #cacbcd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__info {
|
&__info {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
color: var(--up-main-color, $u-main-color);
|
|
||||||
|
|
||||||
&--selected {
|
&--selected {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--disabled {
|
&--disabled {
|
||||||
color: var(--up-disabled-color, #cacbcd);
|
color: #cacbcd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -659,5 +605,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CalendarDefaultProps from './calendar'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CalendarDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 日历顶部标题
|
// 日历顶部标题
|
||||||
@@ -100,46 +98,6 @@ export const props = defineMixin({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => defProps.calendar.show
|
default: () => defProps.calendar.show
|
||||||
},
|
},
|
||||||
// 是否显示遮罩
|
|
||||||
overlay: {
|
|
||||||
type: Boolean,
|
|
||||||
default: () => defProps.calendar.overlay
|
|
||||||
},
|
|
||||||
// 动画时长,单位ms
|
|
||||||
duration: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: () => defProps.calendar.duration
|
|
||||||
},
|
|
||||||
// 自定义遮罩的样式
|
|
||||||
overlayStyle: {
|
|
||||||
type: [Object, String],
|
|
||||||
default: () => defProps.calendar.overlayStyle
|
|
||||||
},
|
|
||||||
// 遮罩的透明度,0-1之间
|
|
||||||
overlayOpacity: {
|
|
||||||
type: [Number, String],
|
|
||||||
default: () => defProps.calendar.overlayOpacity
|
|
||||||
},
|
|
||||||
// 层级
|
|
||||||
zIndex: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: () => defProps.calendar.zIndex
|
|
||||||
},
|
|
||||||
// 是否为iPhoneX留出底部安全距离
|
|
||||||
safeAreaInsetBottom: {
|
|
||||||
type: Boolean,
|
|
||||||
default: () => defProps.calendar.safeAreaInsetBottom
|
|
||||||
},
|
|
||||||
// 是否留出顶部安全距离(状态栏高度)
|
|
||||||
safeAreaInsetTop: {
|
|
||||||
type: Boolean,
|
|
||||||
default: () => defProps.calendar.safeAreaInsetTop
|
|
||||||
},
|
|
||||||
// 弹窗背景色,设置为transparent可去除白色背景
|
|
||||||
bgColor: {
|
|
||||||
type: String,
|
|
||||||
default: () => defProps.calendar.bgColor
|
|
||||||
},
|
|
||||||
// 是否允许点击遮罩关闭日历
|
// 是否允许点击遮罩关闭日历
|
||||||
closeOnClickOverlay: {
|
closeOnClickOverlay: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -174,26 +132,6 @@ export const props = defineMixin({
|
|||||||
allowSameDay: {
|
allowSameDay: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => defProps.calendar.allowSameDay
|
default: () => defProps.calendar.allowSameDay
|
||||||
},
|
|
||||||
// 区间模式下确认返回值格式,all-返回区间内所有日期,boundary-仅返回起止日期
|
|
||||||
rangeResultMode: {
|
|
||||||
type: String,
|
|
||||||
default: () => defProps.calendar.rangeResultMode
|
|
||||||
},
|
|
||||||
// 是否开启时分秒选择
|
|
||||||
enableTime: {
|
|
||||||
type: Boolean,
|
|
||||||
default: () => defProps.calendar.enableTime
|
|
||||||
},
|
|
||||||
// 时间精度:hour-仅时,minute-时分,second-时分秒
|
|
||||||
timePrecision: {
|
|
||||||
type: String,
|
|
||||||
default: () => defProps.calendar.timePrecision
|
|
||||||
},
|
|
||||||
// 默认时间,格式支持 HH / HH:mm / HH:mm:ss
|
|
||||||
defaultTime: {
|
|
||||||
type: String,
|
|
||||||
default: () => defProps.calendar.defaultTime
|
|
||||||
},
|
},
|
||||||
// 圆角值
|
// 圆角值
|
||||||
round: {
|
round: {
|
||||||
@@ -205,21 +143,6 @@ export const props = defineMixin({
|
|||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: 3
|
default: 3
|
||||||
},
|
},
|
||||||
// 是否启用非滚动的单月切换模式
|
|
||||||
monthSwitch: {
|
|
||||||
type: Boolean,
|
|
||||||
default: () => defProps.calendar.monthSwitch
|
|
||||||
},
|
|
||||||
// 是否显示今天按钮
|
|
||||||
showToday: {
|
|
||||||
type: Boolean,
|
|
||||||
default: () => defProps.calendar.showToday
|
|
||||||
},
|
|
||||||
// 今天日期的独立高亮颜色,默认跟随主题色
|
|
||||||
todayColor: {
|
|
||||||
type: String,
|
|
||||||
default: () => defProps.calendar.todayColor
|
|
||||||
},
|
|
||||||
// 星期文案
|
// 星期文案
|
||||||
weekText: {
|
weekText: {
|
||||||
type: Array,
|
type: Array,
|
||||||
@@ -233,14 +156,5 @@ export const props = defineMixin({
|
|||||||
type: String,
|
type: String,
|
||||||
default: defProps.calendar.forbidDaysToast
|
default: defProps.calendar.forbidDaysToast
|
||||||
},
|
},
|
||||||
monthFormat:{
|
|
||||||
type: String,
|
|
||||||
default: defProps.calendar.monthFormat
|
|
||||||
},
|
|
||||||
// 是否页面内展示
|
|
||||||
pageInline:{
|
|
||||||
type: Boolean,
|
|
||||||
default: defProps.calendar.pageInline
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,18 +2,9 @@
|
|||||||
<u-popup
|
<u-popup
|
||||||
:show="show"
|
:show="show"
|
||||||
mode="bottom"
|
mode="bottom"
|
||||||
:overlay="overlay"
|
closeable
|
||||||
:duration="duration"
|
|
||||||
:overlayStyle="overlayStyle"
|
|
||||||
:overlayOpacity="overlayOpacity"
|
|
||||||
:zIndex="zIndex"
|
|
||||||
:safeAreaInsetBottom="safeAreaInsetBottom"
|
|
||||||
:safeAreaInsetTop="safeAreaInsetTop"
|
|
||||||
:bgColor="bgColor"
|
|
||||||
:closeable="!pageInline"
|
|
||||||
@close="close"
|
@close="close"
|
||||||
:round="round"
|
:round="round"
|
||||||
:pageInline="pageInline"
|
|
||||||
:closeOnClickOverlay="closeOnClickOverlay"
|
:closeOnClickOverlay="closeOnClickOverlay"
|
||||||
>
|
>
|
||||||
<view class="u-calendar">
|
<view class="u-calendar">
|
||||||
@@ -23,46 +14,10 @@
|
|||||||
:showSubtitle="showSubtitle"
|
:showSubtitle="showSubtitle"
|
||||||
:showTitle="showTitle"
|
:showTitle="showTitle"
|
||||||
:weekText="weekText"
|
:weekText="weekText"
|
||||||
:showSwitch="monthSwitch"
|
|
||||||
:showToday="showToday"
|
|
||||||
:todayText="todayText"
|
|
||||||
:todayDisabled="todayDisabled"
|
|
||||||
:prevDisabled="switchPrevDisabled"
|
|
||||||
:nextDisabled="switchNextDisabled"
|
|
||||||
:prevYearDisabled="switchPrevYearDisabled"
|
|
||||||
:nextYearDisabled="switchNextYearDisabled"
|
|
||||||
@prev="prevMonth"
|
|
||||||
@next="nextMonth"
|
|
||||||
@prevYear="prevYear"
|
|
||||||
@nextYear="nextYear"
|
|
||||||
@today="jumpToToday"
|
|
||||||
></uHeader>
|
></uHeader>
|
||||||
<view v-if="showTimePanel" class="u-calendar__time-panel">
|
|
||||||
<view v-if="mode === 'single'" class="u-calendar__time-row">
|
|
||||||
<text class="u-calendar__time-date">{{ singleDateLabel }}</text>
|
|
||||||
<view class="u-calendar__time-trigger" @click="openTimePicker('single')">
|
|
||||||
<text class="u-calendar__time-text">{{ singleTime }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view v-else-if="mode === 'range' && rangeResultMode === 'boundary'">
|
|
||||||
<view class="u-calendar__time-row">
|
|
||||||
<text class="u-calendar__time-date">{{ rangeStartDateLabel }}</text>
|
|
||||||
<view class="u-calendar__time-trigger" @click="openTimePicker('start')">
|
|
||||||
<text class="u-calendar__time-text">{{ rangeStartTime }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view class="u-calendar__time-row">
|
|
||||||
<text class="u-calendar__time-date">{{ rangeEndDateLabel }}</text>
|
|
||||||
<view class="u-calendar__time-trigger" @click="openTimePicker('end')">
|
|
||||||
<text class="u-calendar__time-text">{{ rangeEndTime }}</text>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<scroll-view
|
<scroll-view
|
||||||
v-if="!monthSwitch"
|
|
||||||
:style="{
|
:style="{
|
||||||
height: addUnit(listHeight, 'px')
|
height: addUnit(listHeight)
|
||||||
}"
|
}"
|
||||||
scroll-y
|
scroll-y
|
||||||
@scroll="onScroll"
|
@scroll="onScroll"
|
||||||
@@ -89,48 +44,11 @@
|
|||||||
:allowSameDay="allowSameDay"
|
:allowSameDay="allowSameDay"
|
||||||
:forbidDays="forbidDays"
|
:forbidDays="forbidDays"
|
||||||
:forbidDaysToast="forbidDaysToast"
|
:forbidDaysToast="forbidDaysToast"
|
||||||
:monthFormat="monthFormat"
|
|
||||||
:todayDate="todayDate"
|
|
||||||
:todayColor="todayColor"
|
|
||||||
ref="month"
|
ref="month"
|
||||||
@monthSelected="monthSelected"
|
@monthSelected="monthSelected"
|
||||||
@updateMonthTop="onUpdateMonthTop"
|
@updateMonthTop="updateMonthTop"
|
||||||
></uMonth>
|
></uMonth>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
<view
|
|
||||||
v-else
|
|
||||||
:style="{
|
|
||||||
height: addUnit(listHeight, 'px')
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<uMonth
|
|
||||||
:color="color"
|
|
||||||
:rowHeight="rowHeight"
|
|
||||||
:showMark="showMark"
|
|
||||||
:months="currentMonths"
|
|
||||||
: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"
|
|
||||||
:forbidDays="forbidDays"
|
|
||||||
:forbidDaysToast="forbidDaysToast"
|
|
||||||
:monthFormat="monthFormat"
|
|
||||||
:todayDate="todayDate"
|
|
||||||
:todayColor="todayColor"
|
|
||||||
ref="month"
|
|
||||||
@monthSelected="monthSelected"
|
|
||||||
@updateMonthTop="onUpdateMonthTop"
|
|
||||||
></uMonth>
|
|
||||||
</view>
|
|
||||||
<slot name="footer" v-if="showConfirm">
|
<slot name="footer" v-if="showConfirm">
|
||||||
<view class="u-calendar__confirm">
|
<view class="u-calendar__confirm">
|
||||||
<u-button
|
<u-button
|
||||||
@@ -146,32 +64,6 @@
|
|||||||
</slot>
|
</slot>
|
||||||
</view>
|
</view>
|
||||||
</u-popup>
|
</u-popup>
|
||||||
<u-popup
|
|
||||||
:show="timePickerShow"
|
|
||||||
mode="center"
|
|
||||||
:round="8"
|
|
||||||
:closeOnClickOverlay="true"
|
|
||||||
@close="closeTimePicker"
|
|
||||||
>
|
|
||||||
<view class="u-calendar__time-picker">
|
|
||||||
<view class="u-calendar__time-picker__header">
|
|
||||||
<text class="u-calendar__time-picker__cancel" @click="closeTimePicker">取消</text>
|
|
||||||
<text class="u-calendar__time-picker__title">选择时间</text>
|
|
||||||
<text class="u-calendar__time-picker__confirm" @click="confirmTimePicker">确定</text>
|
|
||||||
</view>
|
|
||||||
<picker-view class="u-calendar__time-picker__body" :value="timePickerValue" @change="onTimePickerChange">
|
|
||||||
<picker-view-column>
|
|
||||||
<view v-for="(item, index) in hourOptions" :key="`h-${index}`" class="u-calendar__time-picker__item">{{ item }}</view>
|
|
||||||
</picker-view-column>
|
|
||||||
<picker-view-column v-if="timePrecision !== 'hour'">
|
|
||||||
<view v-for="(item, index) in minuteOptions" :key="`m-${index}`" class="u-calendar__time-picker__item">{{ item }}</view>
|
|
||||||
</picker-view-column>
|
|
||||||
<picker-view-column v-if="timePrecision === 'second'">
|
|
||||||
<view v-for="(item, index) in secondOptions" :key="`s-${index}`" class="u-calendar__time-picker__item">{{ item }}</view>
|
|
||||||
</picker-view-column>
|
|
||||||
</picker-view>
|
|
||||||
</view>
|
|
||||||
</u-popup>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -179,17 +71,16 @@ import uHeader from './header.vue'
|
|||||||
import uMonth from './month.vue'
|
import uMonth from './month.vue'
|
||||||
import { props } from './props.js'
|
import { props } from './props.js'
|
||||||
import util from './util.js'
|
import util from './util.js'
|
||||||
import dayjs from '../u-datetime-picker/dayjs.esm.min.js';
|
import dayjs from 'dayjs/esm/index'
|
||||||
import Calendar from '../../libs/util/calendar.js'
|
import Calendar from '../../libs/util/calendar.js'
|
||||||
import { mpMixin } from '../../libs/mixin/mpMixin.js'
|
import { mpMixin } from '../../libs/mixin/mpMixin.js'
|
||||||
import { mixin } from '../../libs/mixin/mixin.js'
|
import { mixin } from '../../libs/mixin/mixin.js'
|
||||||
import { addUnit, getPx, range, error, padZero } from '../../libs/function/index';
|
import { addUnit, range, error, padZero } from '../../libs/function/index';
|
||||||
import test from '../../libs/function/test';
|
import test from '../../libs/function/test';
|
||||||
import { t } from '../../libs/i18n'
|
|
||||||
/**
|
/**
|
||||||
* Calendar 日历
|
* Calendar 日历
|
||||||
* @description 此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中.
|
* @description 此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中.
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/calendar.html
|
* @tutorial https://ijry.github.io/uview-plus/components/calendar.html
|
||||||
*
|
*
|
||||||
* @property {String} title 标题内容 (默认 日期选择 )
|
* @property {String} title 标题内容 (默认 日期选择 )
|
||||||
* @property {Boolean} showTitle 是否显示标题 (默认 true )
|
* @property {Boolean} showTitle 是否显示标题 (默认 true )
|
||||||
@@ -210,28 +101,14 @@ import { t } from '../../libs/i18n'
|
|||||||
* @property {String} confirmText 确定按钮的文字 (默认 '确定' )
|
* @property {String} confirmText 确定按钮的文字 (默认 '确定' )
|
||||||
* @property {String} confirmDisabledText 确认按钮处于禁用状态时的文字 (默认 '确定' )
|
* @property {String} confirmDisabledText 确认按钮处于禁用状态时的文字 (默认 '确定' )
|
||||||
* @property {Boolean} show 是否显示日历弹窗 (默认 false )
|
* @property {Boolean} show 是否显示日历弹窗 (默认 false )
|
||||||
* @property {Boolean} overlay 是否显示遮罩 (默认 true )
|
|
||||||
* @property {String | Number} duration 动画时长,单位ms (默认 300 )
|
|
||||||
* @property {Object | String} overlayStyle 自定义遮罩的样式
|
|
||||||
* @property {Number | String} overlayOpacity 遮罩透明度,0-1之间 (默认 0.5 )
|
|
||||||
* @property {String | Number} zIndex 弹出层的z-index值 (默认 10075 )
|
|
||||||
* @property {Boolean} safeAreaInsetBottom 是否留出底部安全距离 (默认 true )
|
|
||||||
* @property {Boolean} safeAreaInsetTop 是否留出顶部安全距离(状态栏高度) (默认 false )
|
|
||||||
* @property {String} bgColor 弹窗背景色,设置为transparent可去除白色背景
|
|
||||||
* @property {Boolean} closeOnClickOverlay 是否允许点击遮罩关闭日历 (默认 false )
|
* @property {Boolean} closeOnClickOverlay 是否允许点击遮罩关闭日历 (默认 false )
|
||||||
* @property {Boolean} readonly 是否为只读状态,只读状态下禁止选择日期 (默认 false )
|
* @property {Boolean} readonly 是否为只读状态,只读状态下禁止选择日期 (默认 false )
|
||||||
* @property {String | Number} maxRange 日期区间最多可选天数,默认无限制,mode = range时有效
|
* @property {String | Number} maxRange 日期区间最多可选天数,默认无限制,mode = range时有效
|
||||||
* @property {String} rangePrompt 范围选择超过最多可选天数时的提示文案,mode = range时有效
|
* @property {String} rangePrompt 范围选择超过最多可选天数时的提示文案,mode = range时有效
|
||||||
* @property {Boolean} showRangePrompt 范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效 (默认 true )
|
* @property {Boolean} showRangePrompt 范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效 (默认 true )
|
||||||
* @property {Boolean} allowSameDay 是否允许日期范围的起止时间为同一天,mode = range时有效 (默认 false )
|
* @property {Boolean} allowSameDay 是否允许日期范围的起止时间为同一天,mode = range时有效 (默认 false )
|
||||||
* @property {String} rangeResultMode 区间模式下确认返回值格式,all-返回区间内所有日期,boundary-仅返回起止日期 (默认 'all' )
|
|
||||||
* @property {Boolean} enableTime 是否开启时分秒选择 (默认 false )
|
|
||||||
* @property {String} timePrecision 时间精度,hour-仅时,minute-时分,second-时分秒 (默认 'minute' )
|
|
||||||
* @property {String} defaultTime 默认时间,支持HH/HH:mm/HH:mm:ss,不传则按00:00补齐
|
|
||||||
* @property {Number|String} round 圆角值,默认无圆角 (默认 0 )
|
* @property {Number|String} round 圆角值,默认无圆角 (默认 0 )
|
||||||
* @property {Number|String} monthNum 最多展示的月份数量 (默认 3 )
|
* @property {Number|String} monthNum 最多展示的月份数量 (默认 3 )
|
||||||
* @property {Boolean} monthSwitch 是否启用非滚动的单月切换模式 (默认 false )
|
|
||||||
* @property {String} todayColor 今天日期的独立高亮颜色,默认跟随主题色
|
|
||||||
* @property {Array} weekText 星期文案 (默认 ['一', '二', '三', '四', '五', '六', '日'] )
|
* @property {Array} weekText 星期文案 (默认 ['一', '二', '三', '四', '五', '六', '日'] )
|
||||||
*
|
*
|
||||||
* @event {Function()} confirm 点击确定按钮时触发 选择日期相关的返回参数
|
* @event {Function()} confirm 点击确定按钮时触发 选择日期相关的返回参数
|
||||||
@@ -259,15 +136,6 @@ export default {
|
|||||||
scrollIntoView: '',
|
scrollIntoView: '',
|
||||||
scrollIntoViewScroll: '',
|
scrollIntoViewScroll: '',
|
||||||
scrollTop:0,
|
scrollTop:0,
|
||||||
timePickerShow: false,
|
|
||||||
timePickerTarget: 'single',
|
|
||||||
timePickerValue: [0, 0, 0],
|
|
||||||
hourOptions: [],
|
|
||||||
minuteOptions: [],
|
|
||||||
secondOptions: [],
|
|
||||||
singleTime: '00:00',
|
|
||||||
rangeStartTime: '00:00',
|
|
||||||
rangeEndTime: '00:00',
|
|
||||||
// 过滤处理方法
|
// 过滤处理方法
|
||||||
innerFormatter: (value) => value
|
innerFormatter: (value) => value
|
||||||
}
|
}
|
||||||
@@ -285,13 +153,6 @@ export default {
|
|||||||
this.setMonth()
|
this.setMonth()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
timePrecision() {
|
|
||||||
this.initTimeOptions()
|
|
||||||
this.initTimeValues()
|
|
||||||
},
|
|
||||||
defaultTime() {
|
|
||||||
this.initTimeValues()
|
|
||||||
},
|
|
||||||
// 打开弹窗时,设置月份数据
|
// 打开弹窗时,设置月份数据
|
||||||
show: {
|
show: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
@@ -318,28 +179,6 @@ export default {
|
|||||||
? Number(this.minDate)
|
? Number(this.minDate)
|
||||||
: this.minDate
|
: this.minDate
|
||||||
},
|
},
|
||||||
todayDate() {
|
|
||||||
return dayjs().format('YYYY-MM-DD')
|
|
||||||
},
|
|
||||||
todayText() {
|
|
||||||
return t('up.calendar.today')
|
|
||||||
},
|
|
||||||
todayDisabled() {
|
|
||||||
const today = dayjs(this.todayDate)
|
|
||||||
const minDate = this.innerMinDate
|
|
||||||
? dayjs(this.innerMinDate)
|
|
||||||
: null
|
|
||||||
const maxDate = this.innerMaxDate
|
|
||||||
? dayjs(this.innerMaxDate)
|
|
||||||
: null
|
|
||||||
if (minDate && today.isBefore(minDate, 'day')) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (maxDate && today.isAfter(maxDate, 'day')) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
// 多个条件的变化,会引起选中日期的变化,这里统一管理监听
|
// 多个条件的变化,会引起选中日期的变化,这里统一管理监听
|
||||||
selectedChange() {
|
selectedChange() {
|
||||||
return [this.innerMinDate, this.innerMaxDate, this.defaultDate]
|
return [this.innerMinDate, this.innerMaxDate, this.defaultDate]
|
||||||
@@ -347,53 +186,13 @@ export default {
|
|||||||
subtitle() {
|
subtitle() {
|
||||||
// 初始化时,this.months为空数组,所以需要特别判断处理
|
// 初始化时,this.months为空数组,所以需要特别判断处理
|
||||||
if (this.months.length) {
|
if (this.months.length) {
|
||||||
if (uni.getLocale() == 'zh-Hans' || uni.getLocale() == 'zh-Hant') {
|
return `${this.months[this.monthIndex].year}年${
|
||||||
return this.months[this.monthIndex].year + '年' + (this.months[this.monthIndex].month < 10 ? '0' + this.months[this.monthIndex].month : this.months[this.monthIndex].month) + '月'
|
this.months[this.monthIndex].month
|
||||||
} else {
|
}月`
|
||||||
return (this.months[this.monthIndex].month < 10 ? '0' + this.months[this.monthIndex].month : this.months[this.monthIndex].month) + '/' + this.months[this.monthIndex].year
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
currentMonths() {
|
|
||||||
if (this.monthSwitch && this.months.length) {
|
|
||||||
return [this.months[this.monthIndex]]
|
|
||||||
}
|
|
||||||
return this.months
|
|
||||||
},
|
|
||||||
switchPrevDisabled() {
|
|
||||||
return this.monthIndex <= 0
|
|
||||||
},
|
|
||||||
switchNextDisabled() {
|
|
||||||
return this.monthIndex >= this.months.length - 1
|
|
||||||
},
|
|
||||||
switchPrevYearDisabled() {
|
|
||||||
return this.monthIndex - 12 < 0
|
|
||||||
},
|
|
||||||
switchNextYearDisabled() {
|
|
||||||
return this.monthIndex + 12 > this.months.length - 1
|
|
||||||
},
|
|
||||||
showTimePanel() {
|
|
||||||
if (!this.enableTime) return false
|
|
||||||
if (this.mode === 'single') return true
|
|
||||||
if (this.mode === 'range' && this.rangeResultMode === 'boundary') {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
singleDateLabel() {
|
|
||||||
return this.selected[0] || '--'
|
|
||||||
},
|
|
||||||
rangeStartDateLabel() {
|
|
||||||
return this.selected[0] || '--'
|
|
||||||
},
|
|
||||||
rangeEndDateLabel() {
|
|
||||||
if (this.selected.length >= 2) {
|
|
||||||
return this.selected[this.selected.length - 1]
|
|
||||||
}
|
|
||||||
return '--'
|
|
||||||
},
|
|
||||||
buttonDisabled() {
|
buttonDisabled() {
|
||||||
// 如果为range类型,且选择的日期个数不足1个时,让底部的按钮出于disabled状态
|
// 如果为range类型,且选择的日期个数不足1个时,让底部的按钮出于disabled状态
|
||||||
if (this.mode === 'range') {
|
if (this.mode === 'range') {
|
||||||
@@ -414,130 +213,6 @@ export default {
|
|||||||
emits: ["confirm", "close"],
|
emits: ["confirm", "close"],
|
||||||
methods: {
|
methods: {
|
||||||
addUnit,
|
addUnit,
|
||||||
padTime(num) {
|
|
||||||
return String(num).padStart(2, '0')
|
|
||||||
},
|
|
||||||
initTimeOptions() {
|
|
||||||
this.hourOptions = Array.from({ length: 24 }, (_, i) => this.padTime(i))
|
|
||||||
this.minuteOptions = Array.from({ length: 60 }, (_, i) => this.padTime(i))
|
|
||||||
this.secondOptions = Array.from({ length: 60 }, (_, i) => this.padTime(i))
|
|
||||||
},
|
|
||||||
parseTimeValue(value = '') {
|
|
||||||
const raw = String(value || '').trim()
|
|
||||||
const parts = raw.length ? raw.split(':') : []
|
|
||||||
const getNumber = (index, max) => {
|
|
||||||
const current = Number(parts[index] || 0)
|
|
||||||
if (Number.isNaN(current)) return 0
|
|
||||||
return Math.max(0, Math.min(max, current))
|
|
||||||
}
|
|
||||||
const hour = getNumber(0, 23)
|
|
||||||
const minute = getNumber(1, 59)
|
|
||||||
const second = getNumber(2, 59)
|
|
||||||
return [hour, minute, second]
|
|
||||||
},
|
|
||||||
getDefaultTimeValue() {
|
|
||||||
const [hour, minute, second] = this.parseTimeValue(this.defaultTime)
|
|
||||||
if (this.timePrecision === 'hour') {
|
|
||||||
return this.padTime(hour)
|
|
||||||
}
|
|
||||||
if (this.timePrecision === 'second') {
|
|
||||||
return `${this.padTime(hour)}:${this.padTime(minute)}:${this.padTime(second)}`
|
|
||||||
}
|
|
||||||
return `${this.padTime(hour)}:${this.padTime(minute)}`
|
|
||||||
},
|
|
||||||
initTimeValues() {
|
|
||||||
const value = this.getDefaultTimeValue()
|
|
||||||
this.singleTime = value
|
|
||||||
this.rangeStartTime = value
|
|
||||||
this.rangeEndTime = value
|
|
||||||
},
|
|
||||||
timeToPickerValue(value = '') {
|
|
||||||
const [hour, minute, second] = this.parseTimeValue(value)
|
|
||||||
return [hour, minute, second]
|
|
||||||
},
|
|
||||||
pickerValueToTime(value = []) {
|
|
||||||
const hour = Number(value[0] || 0)
|
|
||||||
const minute = Number(value[1] || 0)
|
|
||||||
const second = Number(value[2] || 0)
|
|
||||||
if (this.timePrecision === 'hour') {
|
|
||||||
return this.padTime(hour)
|
|
||||||
}
|
|
||||||
if (this.timePrecision === 'second') {
|
|
||||||
return `${this.padTime(hour)}:${this.padTime(minute)}:${this.padTime(second)}`
|
|
||||||
}
|
|
||||||
return `${this.padTime(hour)}:${this.padTime(minute)}`
|
|
||||||
},
|
|
||||||
openTimePicker(target) {
|
|
||||||
this.timePickerTarget = target
|
|
||||||
let currentValue = this.singleTime
|
|
||||||
if (target === 'start') currentValue = this.rangeStartTime
|
|
||||||
if (target === 'end') currentValue = this.rangeEndTime
|
|
||||||
this.timePickerValue = this.timeToPickerValue(currentValue)
|
|
||||||
this.timePickerShow = true
|
|
||||||
},
|
|
||||||
onTimePickerChange(e) {
|
|
||||||
this.timePickerValue = e.detail.value
|
|
||||||
},
|
|
||||||
closeTimePicker() {
|
|
||||||
this.timePickerShow = false
|
|
||||||
},
|
|
||||||
confirmTimePicker() {
|
|
||||||
const value = this.pickerValueToTime(this.timePickerValue)
|
|
||||||
if (this.timePickerTarget === 'single') this.singleTime = value
|
|
||||||
if (this.timePickerTarget === 'start') this.rangeStartTime = value
|
|
||||||
if (this.timePickerTarget === 'end') this.rangeEndTime = value
|
|
||||||
this.timePickerShow = false
|
|
||||||
},
|
|
||||||
timeToSecond(timeText = '') {
|
|
||||||
const [hour, minute, second] = this.parseTimeValue(timeText)
|
|
||||||
return hour * 3600 + minute * 60 + second
|
|
||||||
},
|
|
||||||
validateSameDayRangeTime() {
|
|
||||||
if (!this.enableTime || this.mode !== 'range' || this.rangeResultMode !== 'boundary') {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (this.selected.length < 2) return true
|
|
||||||
const startDate = this.selected[0]
|
|
||||||
const endDate = this.selected[this.selected.length - 1]
|
|
||||||
if (startDate !== endDate) return true
|
|
||||||
const startSeconds = this.timeToSecond(this.rangeStartTime)
|
|
||||||
const endSeconds = this.timeToSecond(this.rangeEndTime)
|
|
||||||
if (endSeconds < startSeconds) {
|
|
||||||
uni.showToast({
|
|
||||||
title: '结束时间不能早于开始时间',
|
|
||||||
icon: 'none'
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
appendTime(dateText, timeText) {
|
|
||||||
return `${dateText} ${timeText}`
|
|
||||||
},
|
|
||||||
getConfirmValue(selected = this.selected) {
|
|
||||||
let result = selected
|
|
||||||
if (
|
|
||||||
this.mode === 'range' &&
|
|
||||||
this.rangeResultMode === 'boundary' &&
|
|
||||||
selected.length >= 2
|
|
||||||
) {
|
|
||||||
const len = selected.length - 1
|
|
||||||
result = [selected[0], selected[len]]
|
|
||||||
}
|
|
||||||
if (!this.showTimePanel || !this.enableTime) {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
if (this.mode === 'single' && result.length >= 1) {
|
|
||||||
return [this.appendTime(result[0], this.singleTime)]
|
|
||||||
}
|
|
||||||
if (this.mode === 'range' && this.rangeResultMode === 'boundary' && result.length >= 2) {
|
|
||||||
return [
|
|
||||||
this.appendTime(result[0], this.rangeStartTime),
|
|
||||||
this.appendTime(result[1], this.rangeEndTime)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
},
|
|
||||||
// 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用
|
// 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用
|
||||||
setFormatter(e) {
|
setFormatter(e) {
|
||||||
this.innerFormatter = e
|
this.innerFormatter = e
|
||||||
@@ -556,8 +231,7 @@ export default {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if( scene === 'tap') {
|
if( scene === 'tap') {
|
||||||
if (!this.validateSameDayRangeTime()) return
|
this.$emit('confirm', this.selected)
|
||||||
this.$emit('confirm', this.getConfirmValue())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -572,15 +246,7 @@ export default {
|
|||||||
return error('maxDate不能小于minDate时间')
|
return error('maxDate不能小于minDate时间')
|
||||||
}
|
}
|
||||||
// 滚动区域的高度
|
// 滚动区域的高度
|
||||||
let bottomPadding = 0;
|
this.listHeight = this.rowHeight * 5 + 30
|
||||||
if (this.pageInline) {
|
|
||||||
bottomPadding = 0
|
|
||||||
} else {
|
|
||||||
bottomPadding = 30
|
|
||||||
}
|
|
||||||
this.listHeight = this.rowHeight * (this.monthSwitch ? 6 : 5) + bottomPadding
|
|
||||||
this.initTimeOptions()
|
|
||||||
this.initTimeValues()
|
|
||||||
this.setMonth()
|
this.setMonth()
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
@@ -589,8 +255,7 @@ export default {
|
|||||||
// 点击确定按钮
|
// 点击确定按钮
|
||||||
confirm() {
|
confirm() {
|
||||||
if (!this.buttonDisabled) {
|
if (!this.buttonDisabled) {
|
||||||
if (!this.validateSameDayRangeTime()) return
|
this.$emit('confirm', this.selected)
|
||||||
this.$emit('confirm', this.getConfirmValue())
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 获得两个日期之间的月份数
|
// 获得两个日期之间的月份数
|
||||||
@@ -675,67 +340,6 @@ export default {
|
|||||||
year: dayjs(minDate).add(i, 'month').year()
|
year: dayjs(minDate).add(i, 'month').year()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (this.monthSwitch) {
|
|
||||||
this.monthIndex = this.getDefaultMonthIndex()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getDefaultMonthIndex() {
|
|
||||||
let selected = dayjs().format('YYYY-MM')
|
|
||||||
if (this.defaultDate) {
|
|
||||||
if (!test.array(this.defaultDate)) {
|
|
||||||
selected = dayjs(this.defaultDate).format('YYYY-MM')
|
|
||||||
} else if (this.defaultDate.length) {
|
|
||||||
selected = dayjs(this.defaultDate[0]).format('YYYY-MM')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const index = this.months.findIndex(({ year, month }) => {
|
|
||||||
return `${year}-${padZero(month)}` === selected
|
|
||||||
})
|
|
||||||
return index === -1 ? 0 : index
|
|
||||||
},
|
|
||||||
prevMonth() {
|
|
||||||
if (!this.switchPrevDisabled) {
|
|
||||||
this.monthIndex -= 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
nextMonth() {
|
|
||||||
if (!this.switchNextDisabled) {
|
|
||||||
this.monthIndex += 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
prevYear() {
|
|
||||||
if (!this.switchPrevYearDisabled) {
|
|
||||||
this.monthIndex -= 12
|
|
||||||
}
|
|
||||||
},
|
|
||||||
nextYear() {
|
|
||||||
if (!this.switchNextYearDisabled) {
|
|
||||||
this.monthIndex += 12
|
|
||||||
}
|
|
||||||
},
|
|
||||||
jumpToToday() {
|
|
||||||
if (this.todayDisabled) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const targetMonth = dayjs(this.todayDate).format('YYYY-MM')
|
|
||||||
const selectToday = () => {
|
|
||||||
if (this.mode === 'range') {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.$refs.month && this.$refs.month.selectDate(this.todayDate)
|
|
||||||
}
|
|
||||||
if (this.monthSwitch) {
|
|
||||||
const todayMonthIndex = this.months.findIndex(({ year, month }) => {
|
|
||||||
return `${year}-${padZero(month)}` === targetMonth
|
|
||||||
})
|
|
||||||
if (todayMonthIndex !== -1) {
|
|
||||||
this.monthIndex = todayMonthIndex
|
|
||||||
this.$nextTick(selectToday)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.scrollIntoDefaultMonth(targetMonth)
|
|
||||||
this.$nextTick(selectToday)
|
|
||||||
},
|
},
|
||||||
// 滚动到默认设置的月份
|
// 滚动到默认设置的月份
|
||||||
scrollIntoDefaultMonth(selected) {
|
scrollIntoDefaultMonth(selected) {
|
||||||
@@ -750,7 +354,6 @@ export default {
|
|||||||
if (_index !== -1) {
|
if (_index !== -1) {
|
||||||
// #ifndef MP-WEIXIN
|
// #ifndef MP-WEIXIN
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.scrollIntoView = ''
|
|
||||||
this.scrollIntoView = `month-${_index}`
|
this.scrollIntoView = `month-${_index}`
|
||||||
this.scrollIntoViewScroll = this.scrollIntoView
|
this.scrollIntoViewScroll = this.scrollIntoView
|
||||||
})
|
})
|
||||||
@@ -773,12 +376,6 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 更新月份的top值
|
// 更新月份的top值
|
||||||
onUpdateMonthTop(topArr = []) {
|
|
||||||
if (this.monthSwitch) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.updateMonthTop(topArr)
|
|
||||||
},
|
|
||||||
updateMonthTop(topArr = []) {
|
updateMonthTop(topArr = []) {
|
||||||
// 设置对应月份的top值,用于onScroll方法更新月份
|
// 设置对应月份的top值,用于onScroll方法更新月份
|
||||||
topArr.map((item, index) => {
|
topArr.map((item, index) => {
|
||||||
@@ -806,88 +403,9 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import '../../libs/css/components.scss';
|
||||||
|
|
||||||
.u-calendar {
|
.u-calendar {
|
||||||
color: var(--up-main-color, $u-main-color);
|
|
||||||
background-color: var(--up-card-bg-color, #ffffff);
|
|
||||||
|
|
||||||
&__time-panel {
|
|
||||||
padding: 8px 16px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-row {
|
|
||||||
height: 34px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-date {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #303133;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-trigger {
|
|
||||||
min-width: 92px;
|
|
||||||
height: 30px;
|
|
||||||
padding: 0 10px;
|
|
||||||
border-radius: 15px;
|
|
||||||
border: 1px solid #dcdfe6;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-text {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #303133;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-picker {
|
|
||||||
width: 320px;
|
|
||||||
background-color: #ffffff;
|
|
||||||
border-radius: 8px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-picker__header {
|
|
||||||
height: 44px;
|
|
||||||
padding: 0 14px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-picker__cancel {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #909399;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-picker__title {
|
|
||||||
font-size: 15px;
|
|
||||||
color: #303133;
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-picker__confirm {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #3c9cff;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-picker__body {
|
|
||||||
width: 320px;
|
|
||||||
height: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__time-picker__item {
|
|
||||||
height: 40px;
|
|
||||||
line-height: 40px;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #303133;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__confirm {
|
&__confirm {
|
||||||
padding: 7px 18px;
|
padding: 7px 18px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import dayjs from '../u-datetime-picker/dayjs.esm.min.js';
|
import dayjs from 'dayjs/esm/index'
|
||||||
export default {
|
export default {
|
||||||
methods: {
|
methods: {
|
||||||
// 设置月份数据
|
// 设置月份数据
|
||||||
|
|||||||
@@ -1,734 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view
|
|
||||||
class="u-canvas"
|
|
||||||
:id="rootId"
|
|
||||||
:style="{
|
|
||||||
width: useRootHeightAndWidth ? '100%' : actualWidth + unit,
|
|
||||||
height: useRootHeightAndWidth ? '100%' : actualHeight + unit
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<!-- #ifdef MP || H5 -->
|
|
||||||
<canvas
|
|
||||||
class="u-canvas__canvas"
|
|
||||||
:id="canvasId"
|
|
||||||
:canvas-id="canvasId"
|
|
||||||
type="2d"
|
|
||||||
:disable-scroll="disableScroll"
|
|
||||||
:style="{ width: actualWidth + unit, height: actualHeight + unit }"
|
|
||||||
@touchstart="onTouchStart"
|
|
||||||
@touchmove="onTouchMove"
|
|
||||||
@touchend="onTouchEnd"
|
|
||||||
/>
|
|
||||||
<!-- #endif -->
|
|
||||||
|
|
||||||
<!-- #ifdef APP-PLUS -->
|
|
||||||
<canvas
|
|
||||||
class="u-canvas__canvas"
|
|
||||||
:id="canvasId"
|
|
||||||
:canvas-id="canvasId"
|
|
||||||
:disable-scroll="disableScroll"
|
|
||||||
:style="{ width: actualWidth + unit, height: actualHeight + unit }"
|
|
||||||
@touchstart="onTouchStart"
|
|
||||||
@touchmove="onTouchMove"
|
|
||||||
@touchend="onTouchEnd"
|
|
||||||
/>
|
|
||||||
<!-- #endif -->
|
|
||||||
|
|
||||||
<!-- #ifdef APP-NVUE -->
|
|
||||||
<gcanvas
|
|
||||||
class="u-canvas__canvas"
|
|
||||||
ref="gcanvas"
|
|
||||||
:style="{ width: actualWidth + unit, height: actualHeight + unit }"
|
|
||||||
@touchstart="onTouchStart"
|
|
||||||
@touchmove="onTouchMove"
|
|
||||||
@touchend="onTouchEnd"
|
|
||||||
/>
|
|
||||||
<!-- #endif -->
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// #ifdef APP-NVUE
|
|
||||||
import {
|
|
||||||
enable,
|
|
||||||
WeexBridge,
|
|
||||||
Image as GImage
|
|
||||||
} from '../../libs/util/gcanvas/index.js';
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'u-canvas',
|
|
||||||
emits: ['ready', 'touchstart', 'touchmove', 'touchend'],
|
|
||||||
props: {
|
|
||||||
canvasId: {
|
|
||||||
type: String,
|
|
||||||
default: () => `u-canvas${Math.floor(Math.random() * 1000000)}`
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: 300
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: 300
|
|
||||||
},
|
|
||||||
unit: {
|
|
||||||
type: String,
|
|
||||||
default: 'px'
|
|
||||||
},
|
|
||||||
useRootHeightAndWidth: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
bgColor: {
|
|
||||||
type: String,
|
|
||||||
default: '#ffffff'
|
|
||||||
},
|
|
||||||
disableScroll: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
rootId: `u-canvas-root-${Math.floor(Math.random() * 1000000)}`,
|
|
||||||
ctx: null,
|
|
||||||
widthLocal: this.parseSize(this.width),
|
|
||||||
heightLocal: this.parseSize(this.height),
|
|
||||||
fontSize: 12,
|
|
||||||
fontFamily: 'sans-serif',
|
|
||||||
fontWeight: 'normal',
|
|
||||||
dpr: 1
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
actualWidth() {
|
|
||||||
return this.useRootHeightAndWidth ? this.widthLocal : this.parseSize(this.width);
|
|
||||||
},
|
|
||||||
actualHeight() {
|
|
||||||
return this.useRootHeightAndWidth ? this.heightLocal : this.parseSize(this.height);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
width() {
|
|
||||||
this.refresh();
|
|
||||||
},
|
|
||||||
height() {
|
|
||||||
this.refresh();
|
|
||||||
},
|
|
||||||
bgColor() {
|
|
||||||
this.clearCanvas();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this._canvasNode = null;
|
|
||||||
this._selectorResult = null;
|
|
||||||
this._canvasElement = null;
|
|
||||||
this._imageCache = Object.create(null);
|
|
||||||
this._isNvue = false;
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.initCanvas();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
parseSize(value) {
|
|
||||||
if (typeof value === 'number') {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
if (typeof value !== 'string') {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (value.endsWith('rpx') || value.endsWith('upx')) {
|
|
||||||
return uni.upx2px(parseFloat(value));
|
|
||||||
}
|
|
||||||
if (value.endsWith('px')) {
|
|
||||||
return parseFloat(value) || 0;
|
|
||||||
}
|
|
||||||
return parseFloat(value) || 0;
|
|
||||||
},
|
|
||||||
onTouchStart(event) {
|
|
||||||
this.$emit('touchstart', event);
|
|
||||||
},
|
|
||||||
onTouchMove(event) {
|
|
||||||
this.$emit('touchmove', event);
|
|
||||||
},
|
|
||||||
onTouchEnd(event) {
|
|
||||||
this.$emit('touchend', event);
|
|
||||||
},
|
|
||||||
async getCanvasNode(id = this.canvasId, isCanvas = true) {
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
try {
|
|
||||||
// #ifdef APP-NVUE
|
|
||||||
setTimeout(() => {
|
|
||||||
const gcanvas = this.$refs.gcanvas;
|
|
||||||
if (!gcanvas) {
|
|
||||||
resolve(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._isNvue = true;
|
|
||||||
resolve(enable(gcanvas, { bridge: WeexBridge }));
|
|
||||||
}, 100);
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifndef APP-NVUE
|
|
||||||
uni.createSelectorQuery()
|
|
||||||
.in(this)
|
|
||||||
.select(`#${id}`)
|
|
||||||
.fields(
|
|
||||||
{
|
|
||||||
node: isCanvas,
|
|
||||||
size: true
|
|
||||||
},
|
|
||||||
(res) => {
|
|
||||||
resolve(res || false);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.exec();
|
|
||||||
// #endif
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取画布节点失败:', error);
|
|
||||||
resolve(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getCanvasElement() {
|
|
||||||
return this._canvasElement || null;
|
|
||||||
},
|
|
||||||
getRawContext() {
|
|
||||||
return this.ctx;
|
|
||||||
},
|
|
||||||
getCanvasContext() {
|
|
||||||
// #ifdef APP-PLUS
|
|
||||||
return uni.createCanvasContext(this.canvasId, this);
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef APP-NVUE
|
|
||||||
return this._canvasElement && typeof this._canvasElement.getContext === 'function'
|
|
||||||
? this._canvasElement.getContext('2d')
|
|
||||||
: null;
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef MP || H5
|
|
||||||
return this._canvasElement && typeof this._canvasElement.getContext === 'function'
|
|
||||||
? this._canvasElement.getContext('2d')
|
|
||||||
: null;
|
|
||||||
// #endif
|
|
||||||
},
|
|
||||||
async setNewSize() {
|
|
||||||
const rootNode = await this.getCanvasNode(this.rootId, false);
|
|
||||||
if (!rootNode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rootNode.width) {
|
|
||||||
this.widthLocal = rootNode.width;
|
|
||||||
}
|
|
||||||
if (rootNode.height) {
|
|
||||||
this.heightLocal = rootNode.height;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async initCanvas(force = false) {
|
|
||||||
try {
|
|
||||||
if (this.useRootHeightAndWidth) {
|
|
||||||
await this.setNewSize();
|
|
||||||
}
|
|
||||||
if (this.ctx && !force) {
|
|
||||||
this.$emit('ready', {
|
|
||||||
width: this.actualWidth,
|
|
||||||
height: this.actualHeight
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._canvasNode = await this.getCanvasNode(this.canvasId);
|
|
||||||
if (!this._canvasNode) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._selectorResult = this._canvasNode;
|
|
||||||
this._canvasElement = this._canvasNode.node || this._canvasNode;
|
|
||||||
this.dpr = uni.getSystemInfoSync().pixelRatio || 1;
|
|
||||||
|
|
||||||
// #ifdef MP || H5
|
|
||||||
if (this._canvasElement) {
|
|
||||||
this._canvasElement.width = Math.ceil(this.actualWidth * this.dpr);
|
|
||||||
this._canvasElement.height = Math.ceil(this.actualHeight * this.dpr);
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
this.ctx = this.getCanvasContext();
|
|
||||||
if (!this.ctx) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// #ifdef MP || H5
|
|
||||||
if (typeof this.ctx.setTransform === 'function') {
|
|
||||||
this.ctx.setTransform(this.dpr, 0, 0, this.dpr, 0, 0);
|
|
||||||
} else if (typeof this.ctx.scale === 'function') {
|
|
||||||
this.ctx.scale(this.dpr, this.dpr);
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
this.applyFont();
|
|
||||||
this.clearCanvas();
|
|
||||||
this.$emit('ready', {
|
|
||||||
width: this.actualWidth,
|
|
||||||
height: this.actualHeight
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('初始化Canvas失败:', error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
refresh() {
|
|
||||||
return this.initCanvas(true);
|
|
||||||
},
|
|
||||||
getWidth() {
|
|
||||||
return this.actualWidth;
|
|
||||||
},
|
|
||||||
getHeight() {
|
|
||||||
return this.actualHeight;
|
|
||||||
},
|
|
||||||
clearCanvas() {
|
|
||||||
if (!this.ctx) return;
|
|
||||||
this.clearRect(0, 0, this.actualWidth, this.actualHeight);
|
|
||||||
if (this.bgColor && this.bgColor !== 'transparent') {
|
|
||||||
this.beginPath();
|
|
||||||
this.rect(0, 0, this.actualWidth, this.actualHeight);
|
|
||||||
this.setFillStyle(this.bgColor);
|
|
||||||
this.fill();
|
|
||||||
}
|
|
||||||
this.draw();
|
|
||||||
},
|
|
||||||
callContext(method, ...args) {
|
|
||||||
if (this.ctx && typeof this.ctx[method] === 'function') {
|
|
||||||
return this.ctx[method](...args);
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
rect(x, y, width, height) {
|
|
||||||
return this.callContext('rect', x, y, width, height);
|
|
||||||
},
|
|
||||||
clearRect(x, y, width, height) {
|
|
||||||
return this.callContext('clearRect', x, y, width, height);
|
|
||||||
},
|
|
||||||
fillRect(x, y, width, height) {
|
|
||||||
return this.callContext('fillRect', x, y, width, height);
|
|
||||||
},
|
|
||||||
strokeRect(x, y, width, height) {
|
|
||||||
return this.callContext('strokeRect', x, y, width, height);
|
|
||||||
},
|
|
||||||
fill() {
|
|
||||||
return this.callContext('fill');
|
|
||||||
},
|
|
||||||
stroke() {
|
|
||||||
return this.callContext('stroke');
|
|
||||||
},
|
|
||||||
beginPath() {
|
|
||||||
return this.callContext('beginPath');
|
|
||||||
},
|
|
||||||
closePath() {
|
|
||||||
return this.callContext('closePath');
|
|
||||||
},
|
|
||||||
moveTo(x, y) {
|
|
||||||
return this.callContext('moveTo', x, y);
|
|
||||||
},
|
|
||||||
lineTo(x, y) {
|
|
||||||
return this.callContext('lineTo', x, y);
|
|
||||||
},
|
|
||||||
arc(x, y, radius, startAngle, endAngle, anticlockwise = false) {
|
|
||||||
return this.callContext('arc', x, y, radius, startAngle, endAngle, anticlockwise);
|
|
||||||
},
|
|
||||||
bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) {
|
|
||||||
return this.callContext('bezierCurveTo', cp1x, cp1y, cp2x, cp2y, x, y);
|
|
||||||
},
|
|
||||||
quadraticCurveTo(cpx, cpy, x, y) {
|
|
||||||
return this.callContext('quadraticCurveTo', cpx, cpy, x, y);
|
|
||||||
},
|
|
||||||
clip() {
|
|
||||||
return this.callContext('clip');
|
|
||||||
},
|
|
||||||
save() {
|
|
||||||
return this.callContext('save');
|
|
||||||
},
|
|
||||||
restore() {
|
|
||||||
return this.callContext('restore');
|
|
||||||
},
|
|
||||||
translate(x, y) {
|
|
||||||
return this.callContext('translate', x, y);
|
|
||||||
},
|
|
||||||
rotate(angle) {
|
|
||||||
return this.callContext('rotate', angle);
|
|
||||||
},
|
|
||||||
scale(x, y) {
|
|
||||||
return this.callContext('scale', x, y);
|
|
||||||
},
|
|
||||||
setFillStyle(color) {
|
|
||||||
if (!this.ctx) return;
|
|
||||||
if (typeof this.ctx.setFillStyle === 'function') {
|
|
||||||
this.ctx.setFillStyle(color);
|
|
||||||
} else {
|
|
||||||
this.ctx.fillStyle = color;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setStrokeStyle(color) {
|
|
||||||
if (!this.ctx) return;
|
|
||||||
if (typeof this.ctx.setStrokeStyle === 'function') {
|
|
||||||
this.ctx.setStrokeStyle(color);
|
|
||||||
} else {
|
|
||||||
this.ctx.strokeStyle = color;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setLineWidth(width) {
|
|
||||||
if (!this.ctx) return;
|
|
||||||
if (typeof this.ctx.setLineWidth === 'function') {
|
|
||||||
this.ctx.setLineWidth(width);
|
|
||||||
} else {
|
|
||||||
this.ctx.lineWidth = width;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setLineCap(lineCap = 'round') {
|
|
||||||
if (!this.ctx) return;
|
|
||||||
if (typeof this.ctx.setLineCap === 'function') {
|
|
||||||
this.ctx.setLineCap(lineCap);
|
|
||||||
} else {
|
|
||||||
this.ctx.lineCap = lineCap;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setLineJoin(lineJoin = 'round') {
|
|
||||||
if (!this.ctx) return;
|
|
||||||
if (typeof this.ctx.setLineJoin === 'function') {
|
|
||||||
this.ctx.setLineJoin(lineJoin);
|
|
||||||
} else {
|
|
||||||
this.ctx.lineJoin = lineJoin;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setTextAlign(align = 'left') {
|
|
||||||
if (!this.ctx) return;
|
|
||||||
if (typeof this.ctx.setTextAlign === 'function') {
|
|
||||||
this.ctx.setTextAlign(align);
|
|
||||||
} else {
|
|
||||||
this.ctx.textAlign = align;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setTextBaseline(baseline = 'alphabetic') {
|
|
||||||
if (!this.ctx) return;
|
|
||||||
if (typeof this.ctx.setTextBaseline === 'function') {
|
|
||||||
this.ctx.setTextBaseline(baseline);
|
|
||||||
} else {
|
|
||||||
this.ctx.textBaseline = baseline;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setFontSize(fontSize) {
|
|
||||||
this.fontSize = Number(fontSize) || this.fontSize;
|
|
||||||
if (this.ctx && typeof this.ctx.setFontSize === 'function') {
|
|
||||||
this.ctx.setFontSize(this.fontSize);
|
|
||||||
}
|
|
||||||
this.applyFont();
|
|
||||||
},
|
|
||||||
setFont(font) {
|
|
||||||
if (!this.ctx) return;
|
|
||||||
if ('font' in this.ctx) {
|
|
||||||
this.ctx.font = font;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const matched = String(font).match(/(\d+(?:\.\d+)?)px/);
|
|
||||||
if (matched) {
|
|
||||||
this.fontSize = Number(matched[1]);
|
|
||||||
}
|
|
||||||
this.applyFont();
|
|
||||||
},
|
|
||||||
setGlobalAlpha(alpha) {
|
|
||||||
if (!this.ctx) return;
|
|
||||||
if (typeof this.ctx.setGlobalAlpha === 'function') {
|
|
||||||
this.ctx.setGlobalAlpha(alpha);
|
|
||||||
} else {
|
|
||||||
this.ctx.globalAlpha = alpha;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setShadow(offsetX = 0, offsetY = 0, blur = 0, color = 'rgba(0,0,0,0)') {
|
|
||||||
if (!this.ctx) return;
|
|
||||||
if (typeof this.ctx.setShadow === 'function') {
|
|
||||||
this.ctx.setShadow(offsetX, offsetY, blur, color);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.ctx.shadowOffsetX = offsetX;
|
|
||||||
this.ctx.shadowOffsetY = offsetY;
|
|
||||||
this.ctx.shadowBlur = blur;
|
|
||||||
this.ctx.shadowColor = color;
|
|
||||||
},
|
|
||||||
setLineStyle(lineColor, lineWidth) {
|
|
||||||
this.setLineCap('round');
|
|
||||||
this.setLineJoin('round');
|
|
||||||
this.setStrokeStyle(lineColor);
|
|
||||||
this.setLineWidth(lineWidth);
|
|
||||||
},
|
|
||||||
applyFont() {
|
|
||||||
if (!this.ctx) return;
|
|
||||||
const font = `${this.fontWeight === 'normal' ? '' : `${this.fontWeight} `}${this.fontSize}px ${this.fontFamily}`.trim();
|
|
||||||
if ('font' in this.ctx) {
|
|
||||||
this.ctx.font = font;
|
|
||||||
} else if (typeof this.ctx.setFont === 'function') {
|
|
||||||
this.ctx.setFont(font);
|
|
||||||
} else if (typeof this.ctx.setFontSize === 'function') {
|
|
||||||
this.ctx.setFontSize(this.fontSize);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
fillText(text, x, y) {
|
|
||||||
return this.callContext('fillText', String(text), x, y);
|
|
||||||
},
|
|
||||||
measureText(text) {
|
|
||||||
if (this.ctx && typeof this.ctx.measureText === 'function') {
|
|
||||||
return this.ctx.measureText(String(text));
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
width: String(text).length * this.fontSize * 0.6
|
|
||||||
};
|
|
||||||
},
|
|
||||||
createLinearGradient(x0, y0, x1, y1) {
|
|
||||||
if (this.ctx && typeof this.ctx.createLinearGradient === 'function') {
|
|
||||||
return this.ctx.createLinearGradient(x0, y0, x1, y1);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
createRadialGradient(x0, y0, r0, x1, y1, r1) {
|
|
||||||
if (this.ctx && typeof this.ctx.createRadialGradient === 'function') {
|
|
||||||
return this.ctx.createRadialGradient(x0, y0, r0, x1, y1, r1);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
loadImage(src) {
|
|
||||||
if (this._imageCache[src]) {
|
|
||||||
return Promise.resolve(this._imageCache[src]);
|
|
||||||
}
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
let image = null;
|
|
||||||
|
|
||||||
// #ifdef APP-NVUE
|
|
||||||
image = new GImage();
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef MP
|
|
||||||
const canvas = this.getCanvasElement();
|
|
||||||
if (canvas && typeof canvas.createImage === 'function') {
|
|
||||||
image = canvas.createImage();
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef H5
|
|
||||||
image = new Image();
|
|
||||||
image.crossOrigin = 'anonymous';
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
if (!image) {
|
|
||||||
resolve(src);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
image.onload = () => {
|
|
||||||
this._imageCache[src] = image;
|
|
||||||
resolve(image);
|
|
||||||
};
|
|
||||||
image.onerror = reject;
|
|
||||||
image.src = src;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
async drawImage(source, ...args) {
|
|
||||||
if (!this.ctx || typeof this.ctx.drawImage !== 'function') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (typeof source !== 'string' || (typeof this.ctx.setFillStyle === 'function' && !this._isNvue)) {
|
|
||||||
this.ctx.drawImage(source, ...args);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const image = await this.loadImage(source);
|
|
||||||
this.ctx.drawImage(image, ...args);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
draw(isLastDraw = false, callback) {
|
|
||||||
if (this.ctx && typeof this.ctx.draw === 'function') {
|
|
||||||
return this.ctx.draw(isLastDraw, callback);
|
|
||||||
}
|
|
||||||
if (typeof callback === 'function') {
|
|
||||||
setTimeout(callback, 0);
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
},
|
|
||||||
toTempFilePath(options = {}) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const width = options.width || this.actualWidth;
|
|
||||||
const height = options.height || this.actualHeight;
|
|
||||||
const request = {
|
|
||||||
x: options.x || 0,
|
|
||||||
y: options.y || 0,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
destWidth: options.destWidth || width,
|
|
||||||
destHeight: options.destHeight || height,
|
|
||||||
fileType: options.fileType || 'png',
|
|
||||||
quality: options.quality === undefined ? 1 : options.quality
|
|
||||||
};
|
|
||||||
const success = (res) => {
|
|
||||||
if (typeof options.success === 'function') options.success(res);
|
|
||||||
resolve(res);
|
|
||||||
};
|
|
||||||
const fail = (err) => {
|
|
||||||
if (typeof options.fail === 'function') options.fail(err);
|
|
||||||
reject(err);
|
|
||||||
};
|
|
||||||
const complete = (res) => {
|
|
||||||
if (typeof options.complete === 'function') options.complete(res);
|
|
||||||
};
|
|
||||||
|
|
||||||
// #ifdef H5
|
|
||||||
const canvas = this.getCanvasElement() || (this.ctx && this.ctx.canvas);
|
|
||||||
if (canvas && typeof canvas.toDataURL === 'function') {
|
|
||||||
try {
|
|
||||||
let exportCanvas = canvas;
|
|
||||||
if (
|
|
||||||
request.x !== 0 ||
|
|
||||||
request.y !== 0 ||
|
|
||||||
request.width !== this.actualWidth ||
|
|
||||||
request.height !== this.actualHeight ||
|
|
||||||
request.destWidth !== request.width ||
|
|
||||||
request.destHeight !== request.height
|
|
||||||
) {
|
|
||||||
exportCanvas = document.createElement('canvas');
|
|
||||||
exportCanvas.width = request.destWidth;
|
|
||||||
exportCanvas.height = request.destHeight;
|
|
||||||
const exportCtx = exportCanvas.getContext('2d');
|
|
||||||
exportCtx.drawImage(
|
|
||||||
canvas,
|
|
||||||
request.x * this.dpr,
|
|
||||||
request.y * this.dpr,
|
|
||||||
request.width * this.dpr,
|
|
||||||
request.height * this.dpr,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
request.destWidth,
|
|
||||||
request.destHeight
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const mime = request.fileType === 'jpg' || request.fileType === 'jpeg'
|
|
||||||
? 'image/jpeg'
|
|
||||||
: 'image/png';
|
|
||||||
const res = {
|
|
||||||
tempFilePath: exportCanvas.toDataURL(mime, request.quality)
|
|
||||||
};
|
|
||||||
success(res);
|
|
||||||
complete(res);
|
|
||||||
return;
|
|
||||||
} catch (error) {
|
|
||||||
fail(error);
|
|
||||||
complete(error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifdef APP-NVUE
|
|
||||||
if (this.ctx && typeof this.ctx.toTempFilePath === 'function') {
|
|
||||||
this.ctx.toTempFilePath(
|
|
||||||
request.x,
|
|
||||||
request.y,
|
|
||||||
request.width,
|
|
||||||
request.height,
|
|
||||||
request.destWidth,
|
|
||||||
request.destHeight,
|
|
||||||
request.fileType,
|
|
||||||
request.quality,
|
|
||||||
(res) => {
|
|
||||||
success(res);
|
|
||||||
complete(res);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// #endif
|
|
||||||
|
|
||||||
const canvasNode = this.getCanvasElement();
|
|
||||||
const uniOptions = {
|
|
||||||
...request,
|
|
||||||
canvasId: this.canvasId,
|
|
||||||
success,
|
|
||||||
fail,
|
|
||||||
complete
|
|
||||||
};
|
|
||||||
if (canvasNode) {
|
|
||||||
uniOptions.canvas = canvasNode;
|
|
||||||
}
|
|
||||||
uni.canvasToTempFilePath(uniOptions, this);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
async exportImage(fileType = 'png', quality = 1) {
|
|
||||||
const res = await this.toTempFilePath({
|
|
||||||
fileType,
|
|
||||||
quality,
|
|
||||||
width: this.actualWidth,
|
|
||||||
height: this.actualHeight,
|
|
||||||
destWidth: this.actualWidth,
|
|
||||||
destHeight: this.actualHeight
|
|
||||||
});
|
|
||||||
return res.tempFilePath || res.apFilePath;
|
|
||||||
},
|
|
||||||
getImageData(options = {}) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const request = {
|
|
||||||
canvasId: this.canvasId,
|
|
||||||
x: options.x || 0,
|
|
||||||
y: options.y || 0,
|
|
||||||
width: options.width || this.actualWidth,
|
|
||||||
height: options.height || this.actualHeight,
|
|
||||||
success: (res) => {
|
|
||||||
if (typeof options.success === 'function') options.success(res);
|
|
||||||
resolve(res);
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
if (typeof options.fail === 'function') options.fail(err);
|
|
||||||
reject(err);
|
|
||||||
},
|
|
||||||
complete: options.complete
|
|
||||||
};
|
|
||||||
uni.canvasGetImageData(request, this);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
putImageData(options = {}) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const request = {
|
|
||||||
canvasId: this.canvasId,
|
|
||||||
x: options.x || 0,
|
|
||||||
y: options.y || 0,
|
|
||||||
width: options.width || this.actualWidth,
|
|
||||||
height: options.height || this.actualHeight,
|
|
||||||
data: options.data,
|
|
||||||
success: (res) => {
|
|
||||||
if (typeof options.success === 'function') options.success(res);
|
|
||||||
resolve(res);
|
|
||||||
},
|
|
||||||
fail: (err) => {
|
|
||||||
if (typeof options.fail === 'function') options.fail(err);
|
|
||||||
reject(err);
|
|
||||||
},
|
|
||||||
complete: options.complete
|
|
||||||
};
|
|
||||||
uni.canvasPutImageData(request, this);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.u-canvas {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.u-canvas__canvas {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:53:20
|
||||||
* @FilePath : /uview-plus/libs/config/props/carKeyboard.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/carKeyboard.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// 车牌号键盘
|
// 车牌号键盘
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CarKeyboardDefaultProps from './carKeyboard'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CarKeyboardDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 是否打乱键盘按键的顺序
|
// 是否打乱键盘按键的顺序
|
||||||
|
|||||||
@@ -56,11 +56,11 @@
|
|||||||
hover-class="u-hover-class"
|
hover-class="u-hover-class"
|
||||||
:hover-stay-time="200"
|
:hover-stay-time="200"
|
||||||
>
|
>
|
||||||
<up-icon
|
<u-icon
|
||||||
size="28"
|
size="28"
|
||||||
name="backspace"
|
name="backspace"
|
||||||
:color="upThemeVar('--up-main-color', '#303133')"
|
color="#303133"
|
||||||
></up-icon>
|
></u-icon>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
@@ -222,25 +222,26 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
$u-car-keyboard-background-color: var(--up-bg-color, rgb(224, 228, 230)) !default;
|
@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-padding:6px 0 6px !default;
|
||||||
$u-car-keyboard-button-inner-width:64rpx !default;
|
$u-car-keyboard-button-inner-width:64rpx !default;
|
||||||
$u-car-keyboard-button-inner-background-color:var(--up-card-bg-color, #ffffff) !default;
|
$u-car-keyboard-button-inner-background-color:#FFFFFF !default;
|
||||||
$u-car-keyboard-button-height:80rpx !default;
|
$u-car-keyboard-button-height:80rpx !default;
|
||||||
$u-car-keyboard-button-inner-box-shadow:0 1px 0px #999992 !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-border-radius:4px !default;
|
||||||
$u-car-keyboard-button-inner-margin:8rpx 5rpx !default;
|
$u-car-keyboard-button-inner-margin:8rpx 5rpx !default;
|
||||||
$u-car-keyboard-button-text-font-size:16px !default;
|
$u-car-keyboard-button-text-font-size:16px !default;
|
||||||
$u-car-keyboard-button-text-color:var(--up-main-color, #303133) !default;
|
$u-car-keyboard-button-text-color:$u-main-color !default;
|
||||||
$u-car-keyboard-center-inner-margin: 0 4rpx !default;
|
$u-car-keyboard-center-inner-margin: 0 4rpx !default;
|
||||||
$u-car-keyboard-special-button-width:134rpx !default;
|
$u-car-keyboard-special-button-width:134rpx !default;
|
||||||
$u-car-keyboard-lang-font-size:16px !default;
|
$u-car-keyboard-lang-font-size:16px !default;
|
||||||
$u-car-keyboard-lang-color:var(--up-main-color, #303133) !default;
|
$u-car-keyboard-lang-color:$u-main-color !default;
|
||||||
$u-car-keyboard-active-color:$u-primary !default;
|
$u-car-keyboard-active-color:$u-primary !default;
|
||||||
$u-car-keyboard-line-font-size:15px !default;
|
$u-car-keyboard-line-font-size:15px !default;
|
||||||
$u-car-keyboard-line-color:var(--up-main-color, #303133) !default;
|
$u-car-keyboard-line-color:$u-main-color !default;
|
||||||
$u-car-keyboard-line-margin:0 1px !default;
|
$u-car-keyboard-line-margin:0 1px !default;
|
||||||
$u-car-keyboard-u-hover-class-background-color:var(--up-border-color, #BBBCC6) !default;
|
$u-car-keyboard-u-hover-class-background-color:#BBBCC6 !default;
|
||||||
|
|
||||||
.u-keyboard {
|
.u-keyboard {
|
||||||
@include flex(column);
|
@include flex(column);
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
/*
|
|
||||||
* @Author : jry
|
|
||||||
* @Description :
|
|
||||||
* @version : 3.0
|
|
||||||
* @Date : 2025-04-26 16:37:21
|
|
||||||
* @LastAuthor : jry
|
|
||||||
* @lastTime : 2025-04-26 16:37:21
|
|
||||||
* @FilePath : /uview-plus/libs/config/props/card.js
|
|
||||||
*/
|
|
||||||
export default {
|
|
||||||
// card组件的props
|
|
||||||
card: {
|
|
||||||
full: false,
|
|
||||||
title: '',
|
|
||||||
titleColor: '#303133',
|
|
||||||
titleSize: '15px',
|
|
||||||
subTitle: '',
|
|
||||||
subTitleColor: '#909399',
|
|
||||||
subTitleSize: '13px',
|
|
||||||
border: true,
|
|
||||||
index: '',
|
|
||||||
margin: '15px',
|
|
||||||
borderRadius: '8px',
|
|
||||||
headStyle: {},
|
|
||||||
bodyStyle: {},
|
|
||||||
footStyle: {},
|
|
||||||
headBorderBottom: true,
|
|
||||||
footBorderTop: true,
|
|
||||||
thumb: '',
|
|
||||||
thumbWidth: '30px',
|
|
||||||
thumbCircle: false,
|
|
||||||
padding: '15px',
|
|
||||||
paddingHead: '',
|
|
||||||
paddingBody: '',
|
|
||||||
paddingFoot: '',
|
|
||||||
showHead: true,
|
|
||||||
showFoot: true,
|
|
||||||
boxShadow: 'none'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,136 +1,140 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CardDefaultProps from './card'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CardDefaultProps)
|
|
||||||
export const propsCard = defineMixin({
|
export const propsCard = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 与屏幕两侧是否留空隙
|
// 与屏幕两侧是否留空隙
|
||||||
full: {
|
full: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => defProps.card.full
|
default: false
|
||||||
},
|
},
|
||||||
// 标题
|
// 标题
|
||||||
title: {
|
title: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => defProps.card.title
|
default: ''
|
||||||
},
|
},
|
||||||
// 标题颜色
|
// 标题颜色
|
||||||
titleColor: {
|
titleColor: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => defProps.card.titleColor
|
default: '#303133'
|
||||||
},
|
},
|
||||||
// 标题字体大小
|
// 标题字体大小
|
||||||
titleSize: {
|
titleSize: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: () => defProps.card.titleSize
|
default: '15px'
|
||||||
},
|
},
|
||||||
// 副标题
|
// 副标题
|
||||||
subTitle: {
|
subTitle: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => defProps.card.subTitle
|
default: ''
|
||||||
},
|
},
|
||||||
// 副标题颜色
|
// 副标题颜色
|
||||||
subTitleColor: {
|
subTitleColor: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => defProps.card.subTitleColor
|
default: '#909399'
|
||||||
},
|
},
|
||||||
// 副标题字体大小
|
// 副标题字体大小
|
||||||
subTitleSize: {
|
subTitleSize: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: () => defProps.card.subTitleSize
|
default: '13'
|
||||||
},
|
},
|
||||||
// 是否显示外部边框,只对full=false时有效(卡片与边框有空隙时)
|
// 是否显示外部边框,只对full=false时有效(卡片与边框有空隙时)
|
||||||
border: {
|
border: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => defProps.card.border
|
default: true
|
||||||
},
|
},
|
||||||
// 用于标识点击了第几个
|
// 用于标识点击了第几个
|
||||||
index: {
|
index: {
|
||||||
type: [Number, String, Object],
|
type: [Number, String, Object],
|
||||||
default: () => defProps.card.index
|
default: ''
|
||||||
},
|
},
|
||||||
// 用于隔开上下左右的边距,带单位的写法,如:"30px 30px","20px 20px 30px 30px"
|
// 用于隔开上下左右的边距,带单位的写法,如:"30px 30px","20px 20px 30px 30px"
|
||||||
margin: {
|
margin: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => defProps.card.margin
|
default: '15px'
|
||||||
},
|
},
|
||||||
// card卡片的圆角
|
// card卡片的圆角
|
||||||
borderRadius: {
|
borderRadius: {
|
||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
default: () => defProps.card.borderRadius
|
default: '8px'
|
||||||
},
|
},
|
||||||
// 头部自定义样式,对象形式
|
// 头部自定义样式,对象形式
|
||||||
headStyle: {
|
headStyle: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => defProps.card.headStyle
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// 主体自定义样式,对象形式
|
// 主体自定义样式,对象形式
|
||||||
bodyStyle: {
|
bodyStyle: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => defProps.card.bodyStyle
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// 底部自定义样式,对象形式
|
// 底部自定义样式,对象形式
|
||||||
footStyle: {
|
footStyle: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => defProps.card.footStyle
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// 头部是否下边框
|
// 头部是否下边框
|
||||||
headBorderBottom: {
|
headBorderBottom: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => defProps.card.headBorderBottom
|
default: true
|
||||||
},
|
},
|
||||||
// 底部是否有上边框
|
// 底部是否有上边框
|
||||||
footBorderTop: {
|
footBorderTop: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => defProps.card.footBorderTop
|
default: true
|
||||||
},
|
},
|
||||||
// 标题左边的缩略图
|
// 标题左边的缩略图
|
||||||
thumb: {
|
thumb: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => defProps.card.thumb
|
default: ''
|
||||||
},
|
},
|
||||||
// 缩略图宽高
|
// 缩略图宽高
|
||||||
thumbWidth: {
|
thumbWidth: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
default: () => defProps.card.thumbWidth
|
default: '30px'
|
||||||
},
|
},
|
||||||
// 缩略图是否为圆形
|
// 缩略图是否为圆形
|
||||||
thumbCircle: {
|
thumbCircle: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => defProps.card.thumbCircle
|
default: false
|
||||||
},
|
},
|
||||||
// 给head,body,foot的内边距
|
// 给head,body,foot的内边距
|
||||||
padding: {
|
padding: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
default: () => defProps.card.padding
|
default: '15px'
|
||||||
},
|
},
|
||||||
paddingHead: {
|
paddingHead: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
default: () => defProps.card.paddingHead
|
default: ''
|
||||||
},
|
},
|
||||||
paddingBody: {
|
paddingBody: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
default: () => defProps.card.paddingBody
|
default: ''
|
||||||
},
|
},
|
||||||
paddingFoot: {
|
paddingFoot: {
|
||||||
type: [String, Number],
|
type: [String, Number],
|
||||||
default: () => defProps.card.paddingFoot
|
default: ''
|
||||||
},
|
},
|
||||||
// 是否显示头部
|
// 是否显示头部
|
||||||
showHead: {
|
showHead: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => defProps.card.showHead
|
default: true
|
||||||
},
|
},
|
||||||
// 是否显示尾部
|
// 是否显示尾部
|
||||||
showFoot: {
|
showFoot: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => defProps.card.showFoot
|
default: true
|
||||||
},
|
},
|
||||||
// 卡片外围阴影,字符串形式
|
// 卡片外围阴影,字符串形式
|
||||||
boxShadow: {
|
boxShadow: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => defProps.card.boxShadow
|
default: 'none'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -136,11 +136,13 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-card {
|
.u-card {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
background-color: var(--up-card-bg-color, #ffffff);
|
background-color: #ffffff;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
&-full {
|
&-full {
|
||||||
|
|||||||
@@ -1,371 +0,0 @@
|
|||||||
<template>
|
|
||||||
<up-popup :show="popupShow" mode="bottom" :popup="false"
|
|
||||||
:mask="true" :closeable="closeable" :safe-area-inset-bottom="true"
|
|
||||||
:close-icon-color="closeIconColor" :z-index="uZIndex"
|
|
||||||
:maskCloseAble="maskCloseAble" @close="close">
|
|
||||||
<view class="up-p-t-30 up-p-l-20 up-m-b-10" v-if="headerDirection ==='column'">
|
|
||||||
<up-steps v-if="popupShow" dot direction="column" v-model:current="tabsIndex">
|
|
||||||
<view v-for="(item, index) in genTabsList" @click="toFatherIndex(index)">
|
|
||||||
<up-steps-item
|
|
||||||
:title="item.name"/>
|
|
||||||
</view>
|
|
||||||
</up-steps>
|
|
||||||
</view>
|
|
||||||
<view class="up-p-t-20 up-m-b-10" v-else>
|
|
||||||
<up-tabs v-if="popupShow" :list="genTabsList"
|
|
||||||
:scrollable="true" v-model:current="tabsIndex" @change="tabsChange" ref="tabs"></up-tabs>
|
|
||||||
</view>
|
|
||||||
<view class="area-box">
|
|
||||||
<view class="u-flex" :class="{ 'change':isChange }"
|
|
||||||
:style="{transform: optionsCols == 2 && isChange ? 'translateX(-33.3333333%)' : ''}">
|
|
||||||
<template v-for="(levelData, levelIndex) in levelList" :key="levelIndex">
|
|
||||||
<view v-if="optionsCols == 2 || levelIndex == tabsIndex" class="area-item"
|
|
||||||
:style="{ width: optionsCols == 2 ? '33.33333%' : '750rpx'}">
|
|
||||||
<view class="u-padding-10" :style="[levelPaneStyle, { height: '100%' }]">
|
|
||||||
<scroll-view :scroll-y="true" style="height: 100%">
|
|
||||||
<up-cell-group v-if="levelIndex === 0 || selectedValueIndexs[levelIndex - 1] !== undefined">
|
|
||||||
<up-cell v-for="(item,index) in levelData"
|
|
||||||
:title="item[labelKey]" :arrow="false"
|
|
||||||
:index="index" :key="index"
|
|
||||||
@click="levelChange(levelIndex, index)">
|
|
||||||
<template v-slot:right-icon>
|
|
||||||
<up-icon v-if="selectedValueIndexs[levelIndex] === index"
|
|
||||||
size="17" name="checkbox-mark"></up-icon>
|
|
||||||
</template>
|
|
||||||
</up-cell>
|
|
||||||
</up-cell-group>
|
|
||||||
</scroll-view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<!-- 添加按钮区域 -->
|
|
||||||
<view class="u-cascader-action up-flex up-flex-between">
|
|
||||||
<view class="u-padding-20 up-flex-fill">
|
|
||||||
<up-button @click="handleCancel" type="default">{{ t("up.common.cancel") }}</up-button>
|
|
||||||
</view>
|
|
||||||
<view class="u-padding-20 up-flex-fill">
|
|
||||||
<up-button @click="handleConfirm" type="primary">{{ t("up.common.confirm") }}</up-button>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</up-popup>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
/**
|
|
||||||
* u-cascader 通用无限级联选择器
|
|
||||||
* @property {String Number} z-index 弹出时的z-index值(默认1075)
|
|
||||||
* @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭Picker(默认true)
|
|
||||||
* @property {Array} data 级联数据
|
|
||||||
* @property {Array} default-value 默认选中的值
|
|
||||||
* @property {String} valueKey 指定选项的值为选项对象中的哪个属性值
|
|
||||||
* @property {String} labelKey 指定选项标签为选项对象中的哪个属性值
|
|
||||||
* @property {String} childrenKey 指定选项的子选项为选项对象中的哪个属性值
|
|
||||||
* @property {Boolean} autoClose 是否在选择最后一级时自动关闭并触发confirm(默认false)
|
|
||||||
* @property {Boolean} closeable 是否显示关闭图标(默认true)
|
|
||||||
*/
|
|
||||||
import { t } from '../../libs/i18n'
|
|
||||||
export default {
|
|
||||||
name: 'up-cascader',
|
|
||||||
props: {
|
|
||||||
// 通过双向绑定控制组件的弹出与收起
|
|
||||||
show: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 级联数据
|
|
||||||
data: {
|
|
||||||
type: Array,
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 默认选中的值
|
|
||||||
modelValue: {
|
|
||||||
type: Array,
|
|
||||||
default() {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 指定选项的值为选项对象中的哪个属性值
|
|
||||||
valueKey: {
|
|
||||||
type: String,
|
|
||||||
default: 'value'
|
|
||||||
},
|
|
||||||
// 指定选项标签为选项对象中的哪个属性值
|
|
||||||
labelKey: {
|
|
||||||
type: String,
|
|
||||||
default: 'label'
|
|
||||||
},
|
|
||||||
// 指定选项的子选项为选项对象中的哪个属性值
|
|
||||||
childrenKey: {
|
|
||||||
type: String,
|
|
||||||
default: 'children'
|
|
||||||
},
|
|
||||||
// 是否允许通过点击遮罩关闭Picker
|
|
||||||
maskCloseAble: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
// 弹出的z-index值
|
|
||||||
zIndex: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: 0
|
|
||||||
},
|
|
||||||
// 是否在选择最后一级时自动关闭并触发confirm
|
|
||||||
autoClose: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 选中项目的展示方向direction垂直方向适合文字长度过长
|
|
||||||
headerDirection: {
|
|
||||||
type: String,
|
|
||||||
default: 'row'
|
|
||||||
},
|
|
||||||
// 选项区域列数,支持1列和2列,默认为2列
|
|
||||||
optionsCols: {
|
|
||||||
type: [Number],
|
|
||||||
default: 2
|
|
||||||
},
|
|
||||||
// 是否显示关闭图标
|
|
||||||
closeable: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
// 存储每一级的数据
|
|
||||||
levelList: [],
|
|
||||||
// 存储每一级选中的索引
|
|
||||||
selectedValueIndexs: [],
|
|
||||||
tabsIndex: 0,
|
|
||||||
popupShow: false,
|
|
||||||
// 新增confirmValues用于存储确认的值
|
|
||||||
confirmValues: []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
data: {
|
|
||||||
handler() {
|
|
||||||
this.initLevelList();
|
|
||||||
this.setDefaultValue();
|
|
||||||
},
|
|
||||||
immediate: true
|
|
||||||
},
|
|
||||||
show() {
|
|
||||||
this.popupShow = this.show;
|
|
||||||
},
|
|
||||||
modelValue: {
|
|
||||||
handler() {
|
|
||||||
// 初始化选中值
|
|
||||||
this.setDefaultValue();
|
|
||||||
},
|
|
||||||
immediate: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
isChange() {
|
|
||||||
return this.tabsIndex > 1;
|
|
||||||
},
|
|
||||||
genTabsList() {
|
|
||||||
let tabsList = [{
|
|
||||||
name: "请选择"
|
|
||||||
}];
|
|
||||||
|
|
||||||
// 根据选中的值动态生成tabs
|
|
||||||
for (let i = 0; i < this.selectedValueIndexs.length; i++) {
|
|
||||||
if (this.selectedValueIndexs[i] !== undefined && this.levelList[i]) {
|
|
||||||
const selectedItem = this.levelList[i][this.selectedValueIndexs[i]];
|
|
||||||
if (selectedItem) {
|
|
||||||
tabsList[i] = {
|
|
||||||
name: selectedItem[this.labelKey]
|
|
||||||
};
|
|
||||||
// 如果还有下一级,则添加"请选择"
|
|
||||||
if (i === this.selectedValueIndexs.length - 1 &&
|
|
||||||
selectedItem[this.childrenKey] &&
|
|
||||||
selectedItem[this.childrenKey].length > 0) {
|
|
||||||
tabsList.push({
|
|
||||||
name: "请选择"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tabsList;
|
|
||||||
},
|
|
||||||
uZIndex() {
|
|
||||||
// 如果用户有传递z-index值,优先使用
|
|
||||||
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
|
|
||||||
},
|
|
||||||
closeIconColor() {
|
|
||||||
return 'var(--up-main-color, #303133)';
|
|
||||||
},
|
|
||||||
levelPaneStyle() {
|
|
||||||
return {
|
|
||||||
backgroundColor: 'var(--up-bg-color, #f7f7f7)'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 新增confirm事件
|
|
||||||
emits: ['update:modelValue', 'update:show', 'change', 'confirm', 'cancel'],
|
|
||||||
methods: {
|
|
||||||
t,
|
|
||||||
getSelectedValues() {
|
|
||||||
const result = [];
|
|
||||||
for (let i = 0; i < this.selectedValueIndexs.length; i++) {
|
|
||||||
const selectedIndex = this.selectedValueIndexs[i];
|
|
||||||
if (selectedIndex === undefined) continue;
|
|
||||||
if (!this.levelList[i] || !this.levelList[i][selectedIndex]) continue;
|
|
||||||
result.push(this.levelList[i][selectedIndex][this.valueKey]);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
initLevelList() {
|
|
||||||
// 初始化第一级数据
|
|
||||||
if (this.data && this.data.length > 0) {
|
|
||||||
this.levelList = [this.data];
|
|
||||||
this.selectedValueIndexs = [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setDefaultValue() {
|
|
||||||
// 检查data是否为空
|
|
||||||
if (!this.data || this.data.length == 0) return;
|
|
||||||
// 检查modelValue是否为空
|
|
||||||
if (!this.modelValue || this.modelValue.length == 0) {
|
|
||||||
this.confirmValues = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 根据默认值设置选中项
|
|
||||||
// 根据modelValue获取indexs给selectedValueIndexs
|
|
||||||
this.selectedValueIndexs = [];
|
|
||||||
this.levelList = []; // 设置层级数据为空
|
|
||||||
let currentLevelData = this.data;
|
|
||||||
|
|
||||||
for (let i = 0; i < this.modelValue.length; i++) {
|
|
||||||
const value = this.modelValue[i];
|
|
||||||
const index = currentLevelData.findIndex(item => item[this.valueKey] === value);
|
|
||||||
this.levelList[i] = currentLevelData; // 设置每一层级的数据
|
|
||||||
|
|
||||||
if (index !== -1) {
|
|
||||||
this.selectedValueIndexs.push(index);
|
|
||||||
// 更新下一级的数据
|
|
||||||
if (currentLevelData[index][this.childrenKey]) {
|
|
||||||
currentLevelData = currentLevelData[index][this.childrenKey];
|
|
||||||
} else {
|
|
||||||
// 如果没有子级数据,则停止处理
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 如果找不到匹配项,则停止处理
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 同步确认值,避免“仅回显未改动时确认返回空数组”
|
|
||||||
this.confirmValues = this.getSelectedValues();
|
|
||||||
},
|
|
||||||
close() {
|
|
||||||
this.$emit('cancel');
|
|
||||||
this.$emit('update:show', false);
|
|
||||||
},
|
|
||||||
tabsChange(item) {
|
|
||||||
},
|
|
||||||
levelChange(levelIndex, index) {
|
|
||||||
// 设置当前级的选中值
|
|
||||||
this.$set(this.selectedValueIndexs, levelIndex, index);
|
|
||||||
|
|
||||||
// 清除后续级别的选中值
|
|
||||||
this.selectedValueIndexs.splice(levelIndex + 1);
|
|
||||||
this.tabsIndex = Math.min(this.tabsIndex, levelIndex);
|
|
||||||
|
|
||||||
// 清除后续级别的列表
|
|
||||||
this.levelList.splice(levelIndex + 1);
|
|
||||||
|
|
||||||
// 获取当前选中项
|
|
||||||
const currentItem = this.levelList[levelIndex][index];
|
|
||||||
|
|
||||||
// 如果有子级数据,则初始化下一级
|
|
||||||
if (currentItem && currentItem[this.childrenKey] && currentItem[this.childrenKey].length > 0) {
|
|
||||||
// 确保levelList数组足够长
|
|
||||||
if (this.levelList.length <= levelIndex + 1) {
|
|
||||||
this.levelList.push(currentItem[this.childrenKey]);
|
|
||||||
} else {
|
|
||||||
this.$set(this.levelList, levelIndex + 1, currentItem[this.childrenKey]);
|
|
||||||
}
|
|
||||||
// 切换到下一级tab
|
|
||||||
this.tabsIndex = levelIndex + 1;
|
|
||||||
} else {
|
|
||||||
// 没有子级数据,说明是最后一级
|
|
||||||
if (this.autoClose) {
|
|
||||||
// 如果启用自动关闭,则触发change事件并关闭
|
|
||||||
this.emitChange();
|
|
||||||
this.handleConfirm();
|
|
||||||
} else {
|
|
||||||
// 否则只触发change事件,不关闭
|
|
||||||
this.emitChange(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 修改emitChange方法,增加closePopup参数
|
|
||||||
emitChange(closePopup = true) {
|
|
||||||
// 构造选中结果
|
|
||||||
const result = this.getSelectedValues();
|
|
||||||
|
|
||||||
// 更新confirmValues
|
|
||||||
this.confirmValues = [...result];
|
|
||||||
|
|
||||||
// 触发change事件,返回value数组
|
|
||||||
this.$emit('change', this.confirmValues);
|
|
||||||
|
|
||||||
// 根据参数决定是否关闭弹窗
|
|
||||||
if (closePopup) {
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleCancel() {
|
|
||||||
this.close();
|
|
||||||
},
|
|
||||||
handleConfirm() {
|
|
||||||
const values = this.confirmValues.length ? this.confirmValues : this.getSelectedValues();
|
|
||||||
this.confirmValues = [...values];
|
|
||||||
// 确认时触发confirm事件
|
|
||||||
this.$emit('update:modelValue', values);
|
|
||||||
this.$emit('confirm', values);
|
|
||||||
this.close();
|
|
||||||
},
|
|
||||||
// 跳转父节点
|
|
||||||
toFatherIndex(index){
|
|
||||||
this.tabsIndex = index;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="scss">
|
|
||||||
.area-box {
|
|
||||||
width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
height: 800rpx;
|
|
||||||
|
|
||||||
>view {
|
|
||||||
width: 150%;
|
|
||||||
transition: transform 0.3s ease-in-out 0s;
|
|
||||||
transform: translateX(0);
|
|
||||||
|
|
||||||
&.change {
|
|
||||||
// transform: translateX(-33.3333333%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.area-item {
|
|
||||||
// width: 750rpx;
|
|
||||||
height: 800rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加按钮区域样式
|
|
||||||
.u-cascader-action {
|
|
||||||
border-top: 1px solid var(--up-border-color, #eee);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,64 +1,49 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="u-cate-tab" :style="{ height: addUnit(height) }">
|
<view class="u-cate-tab">
|
||||||
<view class="u-cate-tab__wrap">
|
<view class="u-cate-tab__wrap">
|
||||||
<scroll-view class="u-cate-tab__view u-cate-tab__menu-scroll-view"
|
<scroll-view class="u-cate-tab__view u-cate-tab__menu-scroll-view"
|
||||||
scroll-y scroll-with-animation :scroll-top="scrollTop"
|
scroll-y scroll-with-animation :scroll-top="scrollTop"
|
||||||
:scroll-into-view="itemId">
|
:scroll-into-view="itemId">
|
||||||
<view v-for="(item, index) in tabList" :key="index" class="u-cate-tab__item"
|
<view v-for="(item, index) in tabList" :key="index" class="u-cate-tab__item"
|
||||||
:class="[innerCurrent == index ? 'u-cate-tab__item-active' : '']"
|
:class="[current == index ? 'u-cate-tab__item-active' : '']"
|
||||||
@tap.stop="swichMenu(index)">
|
@tap.stop="swichMenu(index)">
|
||||||
<slot name="tabItem" :item="item">
|
<slot name="tabItem" :item="item">
|
||||||
</slot>
|
</slot>
|
||||||
<text v-if="!$slots['tabItem']" class="u-line-1">{{item[tabKeyName]}}</text>
|
<text v-if="!$slots['tabItem']" class="u-line-1">{{item[tabKeyName]}}</text>
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
<scroll-view :scroll-top="scrollRightTop" scroll-with-animation :scroll-into-view="scrollIntoView"
|
<scroll-view :scroll-top="scrollRightTop" scroll-with-animation
|
||||||
scroll-y class="u-cate-tab__right-box" @scroll="rightScroll">
|
scroll-y class="u-cate-tab__right-box" @scroll="rightScroll">
|
||||||
<view class="u-cate-tab__right-top">
|
|
||||||
<slot name="rightTop" :tabList="tabList">
|
|
||||||
</slot>
|
|
||||||
</view>
|
|
||||||
<view class="u-cate-tab__page-view">
|
<view class="u-cate-tab__page-view">
|
||||||
<template :key="index" v-for="(item , index) in tabList">
|
<view class="u-cate-tab__page-item" :id="'item' + index"
|
||||||
<view v-if="mode == 'follow' || ( mode == 'tab' && index == innerCurrent)"
|
v-for="(item , index) in tabList" :key="index">
|
||||||
class="u-cate-tab__page-item" :id="'item' + index">
|
<slot name="itemList" :item="item">
|
||||||
<slot name="itemList" :item="item">
|
</slot>
|
||||||
</slot>
|
<template v-if="!$slots['itemList']">
|
||||||
<template v-if="!$slots['itemList']">
|
<view class="item-title">
|
||||||
<view class="item-title">
|
<text>{{item[tabKeyName]}}</text>
|
||||||
<text>{{item[tabKeyName]}}</text>
|
</view>
|
||||||
</view>
|
<view class="item-container">
|
||||||
<view class="item-container">
|
<template v-for="(item1, index1) in item.children" :key="index1">
|
||||||
<template v-for="(item1, index1) in item.children" :key="index1">
|
<slot name="pageItem" :pageItem="item1">
|
||||||
<slot name="pageItem" :pageItem="item1">
|
<view class="thumb-box" >
|
||||||
<view class="thumb-box" >
|
<image class="item-menu-image" :src="item1.icon" mode=""></image>
|
||||||
<image class="item-menu-image" :src="item1.icon" mode=""></image>
|
<view class="item-menu-name">{{item1[itemKeyName]}}</view>
|
||||||
<view class="item-menu-name">{{item1[itemKeyName]}}</view>
|
</view>
|
||||||
</view>
|
</slot>
|
||||||
</slot>
|
</template>
|
||||||
</template>
|
</view>
|
||||||
</view>
|
</template>
|
||||||
</template>
|
</view>
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
</view>
|
</view>
|
||||||
</scroll-view>
|
</scroll-view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { addUnit, sleep } from '../../libs/function/index';
|
|
||||||
export default {
|
export default {
|
||||||
name: 'up-cate-tab',
|
name: 'up-cate-tab',
|
||||||
props: {
|
props: {
|
||||||
mode: {
|
|
||||||
type: String,
|
|
||||||
default: 'follow' // follo跟随联动, tab单一显示。
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
type: String,
|
|
||||||
default: '100%'
|
|
||||||
},
|
|
||||||
tabList: {
|
tabList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => {
|
default: () => {
|
||||||
@@ -72,43 +57,18 @@
|
|||||||
itemKeyName: {
|
itemKeyName: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'name'
|
default: 'name'
|
||||||
},
|
|
||||||
current: {
|
|
||||||
type: Number,
|
|
||||||
default: 0
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
tabList: {
|
tabList() {
|
||||||
deep: true,
|
this.getMenuItemTop()
|
||||||
handler(newVal, oldVal) {
|
}
|
||||||
// this.observer();
|
|
||||||
sleep(30).then(() => {
|
|
||||||
this.getMenuItemTop();
|
|
||||||
this.leftMenuStatus(this.innerCurrent);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
current(nval) {
|
|
||||||
this.innerCurrent = nval;
|
|
||||||
this.leftMenuStatus(this.innerCurrent);
|
|
||||||
sleep(30).then(() => {
|
|
||||||
this.swichMenu(this.innerCurrent)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
height() {
|
|
||||||
// console.log('height change');
|
|
||||||
this.getMenuItemTop();
|
|
||||||
this.leftMenuStatus(this.innerCurrent);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
emits: ['update:current'],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
scrollTop: 0, //tab标题的滚动条位置
|
scrollTop: 0, //tab标题的滚动条位置
|
||||||
scrollIntoView: '', // 滚动至哪个元素
|
|
||||||
oldScrollTop: 0,
|
oldScrollTop: 0,
|
||||||
innerCurrent: 0, // 预设当前项的值
|
current: 0, // 预设当前项的值
|
||||||
menuHeight: 0, // 左边菜单的高度
|
menuHeight: 0, // 左边菜单的高度
|
||||||
menuItemHeight: 0, // 左边菜单item的高度
|
menuItemHeight: 0, // 左边菜单item的高度
|
||||||
itemId: '', // 栏目右边scroll-view用于滚动的id
|
itemId: '', // 栏目右边scroll-view用于滚动的id
|
||||||
@@ -119,38 +79,26 @@
|
|||||||
timer: null, // 定时器
|
timer: null, // 定时器
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
onMounted() {
|
||||||
// this.observer();
|
|
||||||
this.innerCurrent = this.current;
|
|
||||||
this.leftMenuStatus(this.innerCurrent);
|
|
||||||
this.getMenuItemTop()
|
this.getMenuItemTop()
|
||||||
// 设置默认index
|
|
||||||
sleep(50).then(() => {
|
|
||||||
this.swichMenu(this.innerCurrent)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
addUnit,
|
|
||||||
// 点击左边的栏目切换
|
// 点击左边的栏目切换
|
||||||
async swichMenu(index) {
|
async swichMenu(index) {
|
||||||
if (this.mode == 'follow') {
|
if(this.arr.length == 0) {
|
||||||
if(this.arr.length == 0) {
|
await this.getMenuItemTop();
|
||||||
await this.getMenuItemTop();
|
|
||||||
}
|
|
||||||
if (this.scrollIntoView != 'item' + index) {
|
|
||||||
this.scrollIntoView = 'item' + index;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (index == this.current) return;
|
||||||
if (index == this.innerCurrent) return;
|
this.scrollRightTop = this.oldScrollTop;
|
||||||
this.$nextTick(function(){
|
this.$nextTick(function(){
|
||||||
this.innerCurrent = index;
|
this.scrollRightTop = this.arr[index];
|
||||||
this.$emit('update:current', index);
|
this.current = index;
|
||||||
|
this.leftMenuStatus(index);
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// 获取一个目标元素的高度
|
// 获取一个目标元素的高度
|
||||||
getElRect(elClass, dataVal) {
|
getElRect(elClass, dataVal) {
|
||||||
return new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
const query = uni.createSelectorQuery().in(this);
|
const query = uni.createSelectorQuery().in(this);
|
||||||
query.select('.' + elClass).fields({
|
query.select('.' + elClass).fields({
|
||||||
size: true
|
size: true
|
||||||
@@ -169,73 +117,54 @@
|
|||||||
},
|
},
|
||||||
// 观测元素相交状态
|
// 观测元素相交状态
|
||||||
async observer() {
|
async observer() {
|
||||||
await this.$nextTick();
|
|
||||||
// 清除之前的观察器
|
|
||||||
if (this._observerList) {
|
|
||||||
this._observerList.forEach(observer => {
|
|
||||||
observer.disconnect();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this._observerList = [];
|
|
||||||
|
|
||||||
this.tabList.map((val, index) => {
|
this.tabList.map((val, index) => {
|
||||||
let observer = uni.createIntersectionObserver(this);
|
let observer = uni.createIntersectionObserver(this);
|
||||||
this._observerList.push(observer);
|
// 检测右边scroll-view的id为itemxx的元素与u-cate-tab__right-box的相交状态
|
||||||
// 检测相交状态
|
// 如果跟.u-cate-tab__right-box底部相交,就动态设置左边栏目的活动状态
|
||||||
observer.relativeTo('.u-cate-tab__right-box', {
|
observer.relativeTo('.u-cate-tab__right-box', {
|
||||||
top: 10
|
top: 0
|
||||||
}).observe('#item' + index, (res) => {
|
}).observe('#item' + index, res => {
|
||||||
if (res.intersectionRatio > 0) {
|
if (res.intersectionRatio > 0) {
|
||||||
console.log('res', res);
|
let id = res.id.substring(4);
|
||||||
// 修复:确保正确获取索引
|
this.leftMenuStatus(id);
|
||||||
let id = res.id ? res.id.substring(4) : index;
|
|
||||||
this.leftMenuStatus(parseInt(id));
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// 设置左边菜单的滚动状态
|
// 设置左边菜单的滚动状态
|
||||||
async leftMenuStatus(index) {
|
async leftMenuStatus(index) {
|
||||||
this.innerCurrent = index;
|
this.current = index;
|
||||||
this.$emit('update:current', index);
|
|
||||||
// 如果为0,意味着尚未初始化
|
// 如果为0,意味着尚未初始化
|
||||||
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
|
if (this.menuHeight == 0 || this.menuItemHeight == 0) {
|
||||||
await this.getElRect('u-cate-tab__menu-scroll-view', 'menuHeight');
|
await this.getElRect('u-cate-tab__menu-scroll-view', 'menuHeight');
|
||||||
await this.getElRect('u-cate-tab__item', 'menuItemHeight');
|
await this.getElRect('u-cate-tab__item', 'menuItemHeight');
|
||||||
}
|
}
|
||||||
// console.log(this.menuHeight, this.menuItemHeight)
|
|
||||||
// 将菜单活动item垂直居中
|
// 将菜单活动item垂直居中
|
||||||
this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
|
this.scrollTop = index * this.menuItemHeight + this.menuItemHeight / 2 - this.menuHeight / 2;
|
||||||
},
|
},
|
||||||
// 获取右边菜单每个item到顶部的距离
|
// 获取右边菜单每个item到顶部的距离
|
||||||
async getMenuItemTop() {
|
getMenuItemTop() {
|
||||||
// await this.$nextTick();
|
new Promise(resolve => {
|
||||||
// console.log('getMenuItemTop')
|
|
||||||
return new Promise(resolve => {
|
|
||||||
let selectorQuery = uni.createSelectorQuery().in(this);
|
let selectorQuery = uni.createSelectorQuery().in(this);
|
||||||
selectorQuery.selectAll('.u-cate-tab__page-item').boundingClientRect((rects) => {
|
selectorQuery.selectAll('.u-cate-tab__page-item').boundingClientRect((rects) => {
|
||||||
// 如果节点尚未生成,rects值为[](因为用selectAll,所以返回的是数组),循环调用执行
|
// 如果节点尚未生成,rects值为[](因为用selectAll,所以返回的是数组),循环调用执行
|
||||||
if(!rects.length) {
|
if(!rects.length) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.getMenuItemTop();
|
this.getMenuItemTop();
|
||||||
}, 100);
|
}, 10);
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
// console.log(rects)
|
|
||||||
this.rects = rects;
|
this.rects = rects;
|
||||||
this.arr = [];
|
|
||||||
rects.forEach((rect) => {
|
rects.forEach((rect) => {
|
||||||
// 这里减去rects[0].top,是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)
|
// 这里减去rects[0].top,是因为第一项顶部可能不是贴到导航栏(比如有个搜索框的情况)
|
||||||
this.arr.push(rect.top - rects[0].top);
|
this.arr.push(rect.top - rects[0].top);
|
||||||
|
resolve();
|
||||||
})
|
})
|
||||||
// console.log(this.arr)
|
|
||||||
resolve();
|
|
||||||
}).exec()
|
}).exec()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
// 右边菜单滚动
|
// 右边菜单滚动
|
||||||
async rightScroll(e) {
|
async rightScroll(e) {
|
||||||
if (this.mode !== 'follow') return;
|
|
||||||
this.oldScrollTop = e.detail.scrollTop;
|
this.oldScrollTop = e.detail.scrollTop;
|
||||||
// console.log(e.detail.scrollTop)
|
// console.log(e.detail.scrollTop)
|
||||||
// console.log(JSON.stringify(this.arr))
|
// console.log(JSON.stringify(this.arr))
|
||||||
@@ -266,7 +195,7 @@
|
|||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 100)
|
}, 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,12 +210,11 @@
|
|||||||
.u-cate-tab__wrap {
|
.u-cate-tab__wrap {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.u-search-inner {
|
.u-search-inner {
|
||||||
background-color: var(--up-bg-color, rgb(234, 234, 234));
|
background-color: rgb(234, 234, 234);
|
||||||
border-radius: 100rpx;
|
border-radius: 100rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -306,23 +234,23 @@
|
|||||||
|
|
||||||
.u-cate-tab__item {
|
.u-cate-tab__item {
|
||||||
height: 110rpx;
|
height: 110rpx;
|
||||||
background: var(--up-bg-color, #f6f6f6);
|
background: #f6f6f6;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
color: var(--up-content-color, #444);
|
color: #444;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.u-cate-tab__item-active {
|
.u-cate-tab__item-active {
|
||||||
position: relative;
|
position: relative;
|
||||||
color: var(--up-main-color, #000);
|
color: #000;
|
||||||
font-size: 30rpx;
|
font-size: 30rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background: var(--up-card-bg-color, #fff);
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.u-cate-tab__item-active::before {
|
.u-cate-tab__item-active::before {
|
||||||
@@ -340,7 +268,7 @@
|
|||||||
|
|
||||||
.u-cate-tab__right-box {
|
.u-cate-tab__right-box {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
background-color: var(--up-page-bg-color, var(--up-bg-color, rgb(250, 250, 250)));
|
background-color: rgb(250, 250, 250);
|
||||||
}
|
}
|
||||||
|
|
||||||
.u-cate-tab__page-view {
|
.u-cate-tab__page-view {
|
||||||
@@ -349,8 +277,7 @@
|
|||||||
|
|
||||||
.u-cate-tab__page-item {
|
.u-cate-tab__page-item {
|
||||||
margin-bottom: 30rpx;
|
margin-bottom: 30rpx;
|
||||||
background-color: var(--up-card-bg-color, #fff);
|
background-color: #fff;
|
||||||
border: 1px solid var(--up-border-color, #e5e7eb);
|
|
||||||
padding: 16rpx;
|
padding: 16rpx;
|
||||||
border-radius: 8rpx;
|
border-radius: 8rpx;
|
||||||
}
|
}
|
||||||
@@ -361,14 +288,14 @@
|
|||||||
|
|
||||||
.item-title {
|
.item-title {
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
color: var(--up-main-color, $u-main-color);
|
color: $u-main-color;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-menu-name {
|
.item-menu-name {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: var(--up-main-color, $u-main-color);
|
color: $u-main-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-container {
|
.item-container {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:54:16
|
||||||
* @FilePath : /uview-plus/libs/config/props/cellGroup.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/cellGroup.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// cell-group组件的props
|
// cell-group组件的props
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CellGroupDefaultProps from './cellGroup'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CellGroupDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 分组标题
|
// 分组标题
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<view :style="[groupStyle, addStyle(customStyle)]" :class="[customClass]" class="u-cell-group">
|
<view :style="[addStyle(customStyle)]" :class="[customClass]" class="u-cell-group">
|
||||||
<view v-if="title" class="u-cell-group__title">
|
<view v-if="title" class="u-cell-group__title">
|
||||||
<slot name="title">
|
<slot name="title">
|
||||||
<text class="u-cell-group__title__text" :style="{ color: upThemeVar('--up-main-color', '#303133') }">{{ title }}</text>
|
<text class="u-cell-group__title__text">{{ title }}</text>
|
||||||
</slot>
|
</slot>
|
||||||
</view>
|
</view>
|
||||||
<view class="u-cell-group__wrapper">
|
<view class="u-cell-group__wrapper">
|
||||||
@@ -32,14 +32,6 @@
|
|||||||
export default {
|
export default {
|
||||||
name: 'u-cell-group',
|
name: 'u-cell-group',
|
||||||
mixins: [mpMixin, mixin, props],
|
mixins: [mpMixin, mixin, props],
|
||||||
computed: {
|
|
||||||
groupStyle() {
|
|
||||||
const fallbackBg = this.upThemeIsDark ? '#1c1c1e' : '#ffffff'
|
|
||||||
return {
|
|
||||||
backgroundColor: this.upThemeVar('--up-card-bg-color', fallbackBg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
addStyle
|
addStyle
|
||||||
}
|
}
|
||||||
@@ -47,6 +39,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
$u-cell-group-title-padding: 16px 16px 8px !default;
|
$u-cell-group-title-padding: 16px 16px 8px !default;
|
||||||
$u-cell-group-title-font-size: 15px !default;
|
$u-cell-group-title-font-size: 15px !default;
|
||||||
@@ -71,3 +64,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-23 20:53:09
|
||||||
* @FilePath : /uview-plus/libs/config/props/cell.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/cell.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// cell组件的props
|
// cell组件的props
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CellDefaultProps from './cell'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CellDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 标题
|
// 标题
|
||||||
|
|||||||
@@ -7,34 +7,32 @@
|
|||||||
<view class="u-cell__left-icon-wrap" v-if="$slots.icon || icon">
|
<view class="u-cell__left-icon-wrap" v-if="$slots.icon || icon">
|
||||||
<slot name="icon" v-if="$slots.icon">
|
<slot name="icon" v-if="$slots.icon">
|
||||||
</slot>
|
</slot>
|
||||||
<up-icon v-else :name="icon"
|
<u-icon v-else :name="icon"
|
||||||
:custom-style="iconStyle"
|
:custom-style="iconStyle"
|
||||||
:size="size === 'large' ? 22 : 18"></up-icon>
|
:size="size === 'large' ? 22 : 18"></u-icon>
|
||||||
</view>
|
</view>
|
||||||
<view class="u-cell__title">
|
<view class="u-cell__title">
|
||||||
<!-- 将slot与默认内容用if/else分开主要是因为微信小程序不支持slot嵌套传递,这样才能解决collapse组件的slot不失效问题,label暂时未用到。 -->
|
<!-- 将slot与默认内容用if/else分开主要是因为微信小程序不支持slot嵌套传递,这样才能解决collapse组件的slot不失效问题,label暂时未用到。 -->
|
||||||
<slot name="title" v-if="$slots.title || !title">
|
<slot name="title" v-if="$slots.title || !title">
|
||||||
</slot>
|
</slot>
|
||||||
<text v-else class="u-cell__title-text" :style="[cellTitleDynamicStyle, titleTextStyle]"
|
<text v-else class="u-cell__title-text" :style="[titleTextStyle]"
|
||||||
:class="[required && 'u-cell--required', disabled && 'u-cell--disabled', size === 'large' && 'u-cell__title-text--large']">{{ title }}</text>
|
:class="[required && 'u-cell--required', disabled && 'u-cell--disabled', size === 'large' && 'u-cell__title-text--large']">{{ title }}</text>
|
||||||
<slot name="label">
|
<slot name="label">
|
||||||
<text class="u-cell__label" v-if="label"
|
<text class="u-cell__label" v-if="label"
|
||||||
:style="[cellLabelDynamicStyle]"
|
|
||||||
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__label--large']">{{ label }}</text>
|
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__label--large']">{{ label }}</text>
|
||||||
</slot>
|
</slot>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<slot name="value">
|
<slot name="value">
|
||||||
<text class="u-cell__value"
|
<text class="u-cell__value"
|
||||||
:style="[cellValueDynamicStyle]"
|
|
||||||
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__value--large']"
|
:class="[disabled && 'u-cell--disabled', size === 'large' && 'u-cell__value--large']"
|
||||||
v-if="!testEmpty(value)">{{ value }}</text>
|
v-if="!testEmpty(value)">{{ value }}</text>
|
||||||
</slot>
|
</slot>
|
||||||
<view class="u-cell__right-icon-wrap" v-if="$slots['right-icon'] || isLink"
|
<view class="u-cell__right-icon-wrap" v-if="$slots['right-icon'] || isLink"
|
||||||
:class="[`u-cell__right-icon-wrap--${arrowDirection}`]">
|
:class="[`u-cell__right-icon-wrap--${arrowDirection}`]">
|
||||||
<up-icon v-if="rightIcon && !$slots['right-icon']" :name="rightIcon"
|
<u-icon v-if="rightIcon && !$slots['right-icon']" :name="rightIcon"
|
||||||
:custom-style="rightIconStyle" :color="disabled ? cellDisabledColor : 'info'"
|
:custom-style="rightIconStyle" :color="disabled ? '#c8c9cc' : 'info'"
|
||||||
:size="size === 'large' ? 18 : 16"></up-icon>
|
:size="size === 'large' ? 18 : 16"></u-icon>
|
||||||
<slot v-else name="right-icon">
|
<slot v-else name="right-icon">
|
||||||
</slot>
|
</slot>
|
||||||
</view>
|
</view>
|
||||||
@@ -93,24 +91,6 @@
|
|||||||
computed: {
|
computed: {
|
||||||
titleTextStyle() {
|
titleTextStyle() {
|
||||||
return addStyle(this.titleStyle)
|
return addStyle(this.titleStyle)
|
||||||
},
|
|
||||||
cellDisabledColor() {
|
|
||||||
return this.upThemeVar('--up-disabled-color', '#c8c9cc')
|
|
||||||
},
|
|
||||||
cellTitleDynamicStyle() {
|
|
||||||
return {
|
|
||||||
color: this.upThemeVar('--up-main-color', '#303133')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cellLabelDynamicStyle() {
|
|
||||||
return {
|
|
||||||
color: this.upThemeVar('--up-tips-color', '#909399')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
cellValueDynamicStyle() {
|
|
||||||
return {
|
|
||||||
color: this.upThemeVar('--up-content-color', '#606266')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['click'],
|
emits: ['click'],
|
||||||
@@ -133,6 +113,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
$u-cell-padding: 13px 15px !default;
|
$u-cell-padding: 13px 15px !default;
|
||||||
$u-cell-font-size: 15px !default;
|
$u-cell-font-size: 15px !default;
|
||||||
@@ -147,8 +128,8 @@
|
|||||||
$u-cell-label-line-height: 18px !default;
|
$u-cell-label-line-height: 18px !default;
|
||||||
$u-cell-value-font-size: 14px !default;
|
$u-cell-value-font-size: 14px !default;
|
||||||
$u-cell-value-color: $u-content-color !default;
|
$u-cell-value-color: $u-content-color !default;
|
||||||
$u-cell-clickable-color: var(--up-hover-bg-color, #f1f1f1) !default;
|
$u-cell-clickable-color: $u-bg-color !default;
|
||||||
$u-cell-disabled-color: $u-disabled-color !default;
|
$u-cell-disabled-color: #c8c9cc !default;
|
||||||
$u-cell-padding-top-large: 13px !default;
|
$u-cell-padding-top-large: 13px !default;
|
||||||
$u-cell-padding-bottom-large: 13px !default;
|
$u-cell-padding-bottom-large: 13px !default;
|
||||||
$u-cell-value-font-size-large: 15px !default;
|
$u-cell-value-font-size-large: 15px !default;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:54:47
|
||||||
* @FilePath : /uview-plus/libs/config/props/checkboxGroup.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/checkboxGroup.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// checkbox-group组件
|
// checkbox-group组件
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CheckboxGroupDefaultProps from './checkboxGroup'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CheckboxGroupDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 标识符
|
// 标识符
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
/**
|
/**
|
||||||
* checkboxGroup 复选框组
|
* checkboxGroup 复选框组
|
||||||
* @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
|
* @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/checkbox.html
|
* @tutorial https://ijry.github.io/uview-plus/components/checkbox.html
|
||||||
* @property {String} name 标识符
|
* @property {String} name 标识符
|
||||||
* @property {Array} value 绑定的值
|
* @property {Array} value 绑定的值
|
||||||
* @property {String} shape 形状,circle-圆形,square-方形 (默认 'square' )
|
* @property {String} shape 形状,circle-圆形,square-方形 (默认 'square' )
|
||||||
@@ -108,17 +108,15 @@
|
|||||||
// #ifdef VUE2
|
// #ifdef VUE2
|
||||||
this.$emit("input", values);
|
this.$emit("input", values);
|
||||||
// #endif
|
// #endif
|
||||||
// 放在最后更新,否则change事件传出去的values不会更新
|
// 放在最后更新,否则change事件传出去的values不会更新
|
||||||
this.$emit('change', values, {
|
this.$emit('change', values)
|
||||||
isChecked: childInstance.$data['isChecked'],
|
|
||||||
name: childInstance.$props['name'] // 当前变动的checkbox的name值
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-checkbox-group {
|
.u-checkbox-group {
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-23 21:06:59
|
||||||
* @FilePath : /uview-plus/libs/config/props/checkbox.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/checkbox.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// checkbox组件
|
// checkbox组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CheckboxDefaultProps from './checkbox'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CheckboxDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// checkbox的名称
|
// checkbox的名称
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
:class="iconClasses"
|
:class="iconClasses"
|
||||||
:style="[iconWrapStyle]"
|
:style="[iconWrapStyle]"
|
||||||
>
|
>
|
||||||
<slot name="icon" :elIconSize="elIconSize" :elIconColor="elIconColor" :checked="isChecked" :elDisabled="elDisabled">
|
<slot name="icon" :elIconSize="elIconSize" :elIconColor="elIconColor">
|
||||||
<up-icon
|
<u-icon
|
||||||
class="u-checkbox__icon-wrap__icon"
|
class="u-checkbox__icon-wrap__icon"
|
||||||
name="checkbox-mark"
|
name="checkbox-mark"
|
||||||
:size="elIconSize"
|
:size="elIconSize"
|
||||||
@@ -111,16 +111,16 @@
|
|||||||
},
|
},
|
||||||
// 组件选中激活时的颜色
|
// 组件选中激活时的颜色
|
||||||
elActiveColor() {
|
elActiveColor() {
|
||||||
return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : this.upThemeVar('--up-primary', '#2979ff'));
|
return this.activeColor ? this.activeColor : (this.parentData.activeColor ? this.parentData.activeColor : '#2979ff');
|
||||||
},
|
},
|
||||||
// 组件选未中激活时的颜色
|
// 组件选未中激活时的颜色
|
||||||
elInactiveColor() {
|
elInactiveColor() {
|
||||||
return this.inactiveColor ? this.inactiveColor : (this.parentData.inactiveColor ? this.parentData.inactiveColor :
|
return this.inactiveColor ? this.inactiveColor : (this.parentData.inactiveColor ? this.parentData.inactiveColor :
|
||||||
this.upThemeVar('--up-border-color', '#c8c9cc'));
|
'#c8c9cc');
|
||||||
},
|
},
|
||||||
// label的颜色
|
// label的颜色
|
||||||
elLabelColor() {
|
elLabelColor() {
|
||||||
return this.labelColor ? this.labelColor : (this.parentData.labelColor ? this.parentData.labelColor : this.upThemeVar('--up-content-color', '#606266'))
|
return this.labelColor ? this.labelColor : (this.parentData.labelColor ? this.parentData.labelColor : '#606266')
|
||||||
},
|
},
|
||||||
// 组件的形状
|
// 组件的形状
|
||||||
elShape() {
|
elShape() {
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
},
|
},
|
||||||
elIconColor() {
|
elIconColor() {
|
||||||
const iconColor = this.iconColor ? this.iconColor : (this.parentData.iconColor ? this.parentData.iconColor :
|
const iconColor = this.iconColor ? this.iconColor : (this.parentData.iconColor ? this.parentData.iconColor :
|
||||||
this.upThemeVar('--up-card-bg-color', '#ffffff'));
|
'#ffffff');
|
||||||
// 图标的颜色
|
// 图标的颜色
|
||||||
if (this.elDisabled) {
|
if (this.elDisabled) {
|
||||||
// disabled状态下,已勾选的checkbox图标改为elInactiveColor
|
// disabled状态下,已勾选的checkbox图标改为elInactiveColor
|
||||||
@@ -149,12 +149,8 @@
|
|||||||
if (this.elDisabled) {
|
if (this.elDisabled) {
|
||||||
classes.push('u-checkbox__icon-wrap--disabled')
|
classes.push('u-checkbox__icon-wrap--disabled')
|
||||||
}
|
}
|
||||||
if (this.isChecked) {
|
if (this.isChecked && this.elDisabled) {
|
||||||
if (this.elDisabled) {
|
classes.push('u-checkbox__icon-wrap--disabled--checked')
|
||||||
classes.push('u-checkbox__icon-wrap--disabled--checked')
|
|
||||||
} else {
|
|
||||||
classes.push('u-checkbox__icon-wrap--checked')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
|
// 支付宝,头条小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
|
||||||
// #ifdef MP-ALIPAY || MP-TOUTIAO
|
// #ifdef MP-ALIPAY || MP-TOUTIAO
|
||||||
@@ -165,7 +161,7 @@
|
|||||||
iconWrapStyle() {
|
iconWrapStyle() {
|
||||||
// checkbox的整体样式
|
// checkbox的整体样式
|
||||||
const style = {}
|
const style = {}
|
||||||
style.backgroundColor = this.isChecked && !this.elDisabled ? this.elActiveColor : this.upThemeVar('--up-card-bg-color', '#ffffff')
|
style.backgroundColor = this.isChecked && !this.elDisabled ? this.elActiveColor : '#ffffff'
|
||||||
style.borderColor = this.isChecked && !this.elDisabled ? this.elActiveColor : this.elInactiveColor
|
style.borderColor = this.isChecked && !this.elDisabled ? this.elActiveColor : this.elInactiveColor
|
||||||
style.width = addUnit(this.elSize)
|
style.width = addUnit(this.elSize)
|
||||||
style.height = addUnit(this.elSize)
|
style.height = addUnit(this.elSize)
|
||||||
@@ -181,7 +177,7 @@
|
|||||||
const style = {}
|
const style = {}
|
||||||
if (!this.usedAlone) {
|
if (!this.usedAlone) {
|
||||||
if (this.parentData.borderBottom && this.parentData.placement === 'row') {
|
if (this.parentData.borderBottom && this.parentData.placement === 'row') {
|
||||||
error('检测到您将borderBottom设置为true,需要同时将up-checkbox-group的placement设置为column才有效')
|
error('检测到您将borderBottom设置为true,需要同时将u-checkbox-group的placement设置为column才有效')
|
||||||
}
|
}
|
||||||
// 当父组件设置了显示下边框并且排列形式为纵向时,给内容和边框之间加上一定间隔
|
// 当父组件设置了显示下边框并且排列形式为纵向时,给内容和边框之间加上一定间隔
|
||||||
if (this.parentData.borderBottom && this.parentData.placement === 'column') {
|
if (this.parentData.borderBottom && this.parentData.placement === 'column') {
|
||||||
@@ -201,14 +197,13 @@
|
|||||||
// 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环引用
|
// 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环引用
|
||||||
this.updateParentData()
|
this.updateParentData()
|
||||||
if (!this.parent) {
|
if (!this.parent) {
|
||||||
error('up-checkbox必须搭配up-checkbox-group组件使用')
|
error('u-checkbox必须搭配u-checkbox-group组件使用')
|
||||||
}
|
}
|
||||||
let value = '';
|
|
||||||
// #ifdef VUE2
|
// #ifdef VUE2
|
||||||
value = this.parentData.value
|
const value = this.parentData.value
|
||||||
// #endif
|
// #endif
|
||||||
// #ifdef VUE3
|
// #ifdef VUE3
|
||||||
value = this.parentData.modelValue
|
const value = this.parentData.modelValue
|
||||||
// #endif
|
// #endif
|
||||||
// 设置初始化时,是否默认选中的状态,父组件u-checkbox-group的value可能是array,所以额外判断
|
// 设置初始化时,是否默认选中的状态,父组件u-checkbox-group的value可能是array,所以额外判断
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
@@ -253,9 +248,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
emitEvent() {
|
emitEvent() {
|
||||||
this.$emit('change', this.isChecked, {
|
this.$emit('change', this.isChecked)
|
||||||
name: this.name
|
|
||||||
})
|
|
||||||
// 双向绑定
|
// 双向绑定
|
||||||
if (this.usedAlone) {
|
if (this.usedAlone) {
|
||||||
this.$emit('update:checked', this.isChecked)
|
this.$emit('update:checked', this.isChecked)
|
||||||
@@ -288,6 +281,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
$u-checkbox-icon-wrap-margin-right:6px !default;
|
$u-checkbox-icon-wrap-margin-right:6px !default;
|
||||||
$u-checkbox-icon-wrap-font-size:6px !default;
|
$u-checkbox-icon-wrap-font-size:6px !default;
|
||||||
$u-checkbox-icon-wrap-border-width:1px !default;
|
$u-checkbox-icon-wrap-border-width:1px !default;
|
||||||
@@ -298,7 +292,7 @@
|
|||||||
$u-checkbox-icon-wrap-checked-color:#fff !default;
|
$u-checkbox-icon-wrap-checked-color:#fff !default;
|
||||||
$u-checkbox-icon-wrap-checked-background-color:red !default;
|
$u-checkbox-icon-wrap-checked-background-color:red !default;
|
||||||
$u-checkbox-icon-wrap-checked-border-color:#2979ff !default;
|
$u-checkbox-icon-wrap-checked-border-color:#2979ff !default;
|
||||||
$u-checkbox-icon-wrap-disabled-background-color:var(--up-bg-color, #ebedf0) !default;
|
$u-checkbox-icon-wrap-disabled-background-color:#ebedf0 !default;
|
||||||
$u-checkbox-icon-wrap-disabled-checked-color:#c8c9cc !default;
|
$u-checkbox-icon-wrap-disabled-checked-color:#c8c9cc !default;
|
||||||
$u-checkbox-label-margin-left:5px !default;
|
$u-checkbox-label-margin-left:5px !default;
|
||||||
$u-checkbox-label-margin-right:12px !default;
|
$u-checkbox-label-margin-right:12px !default;
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
<style scoped lang="scss">
|
|
||||||
.up-choose {
|
|
||||||
::v-deep .up-tag {
|
|
||||||
font-weight: 600;
|
|
||||||
}
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.up-choose-wrap {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.up-choose-nowrap {
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<scroll-view
|
|
||||||
:scroll-x="wrap === false"
|
|
||||||
:class="['up-choose', wrap ? 'up-choose-wrap' : 'up-choose-nowrap']">
|
|
||||||
<template :key="item.id" v-for="(item,index) in options">
|
|
||||||
<view :style="{width: itemWidth, display: 'inline-block'}">
|
|
||||||
<slot :item="item" :index="index">
|
|
||||||
<up-tag :type="index == currentIndex ? 'primary' : 'info'"
|
|
||||||
size="large" :plain="index == currentIndex ? false : true"
|
|
||||||
:class="currentIndex === index ? 'active': ''" :height="itemHeight"
|
|
||||||
:style="{width: itemWidth, padding: itemPadding}"
|
|
||||||
@click="change(index)">
|
|
||||||
{{item[labelName]}}
|
|
||||||
</up-tag>
|
|
||||||
</slot>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
</scroll-view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'up-choose',
|
|
||||||
props: {
|
|
||||||
options:{
|
|
||||||
type: Array,
|
|
||||||
default: ()=>{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modelValue: {
|
|
||||||
type: [Number,String,Array],
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
type: {
|
|
||||||
type: [String],
|
|
||||||
default: 'radio'
|
|
||||||
},
|
|
||||||
itemWidth: {
|
|
||||||
type: [String],
|
|
||||||
default: 'auto'
|
|
||||||
},
|
|
||||||
itemHeight: {
|
|
||||||
type: [String],
|
|
||||||
default: '50px'
|
|
||||||
},
|
|
||||||
itemPadding: {
|
|
||||||
type: [String],
|
|
||||||
default: '8px'
|
|
||||||
},
|
|
||||||
labelName: {
|
|
||||||
type: String,
|
|
||||||
default: 'title'
|
|
||||||
},
|
|
||||||
valueName: {
|
|
||||||
type: String,
|
|
||||||
default: 'value'
|
|
||||||
},
|
|
||||||
customClick: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 是否换行
|
|
||||||
wrap: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
currentIndex: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
modelValue: {
|
|
||||||
immediate: true,
|
|
||||||
handler(newVal) {
|
|
||||||
this.currentIndex = newVal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['update:modelValue', 'custom-click'],
|
|
||||||
methods: {
|
|
||||||
change(index){
|
|
||||||
if (this.customClick) {
|
|
||||||
this.$emit('custom-click', index);
|
|
||||||
} else {
|
|
||||||
this.currentIndex = index;
|
|
||||||
this.$emit('update:modelValue', index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:55:02
|
||||||
* @FilePath : /uview-plus/libs/config/props/circleProgress.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/circleProgress.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// circleProgress 组件
|
// circleProgress 组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CircleProgressDefaultProps from './circleProgress'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CircleProgressDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
percentage: {
|
percentage: {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
/**
|
/**
|
||||||
* CircleProgress 圆形进度条 TODO: 待完善
|
* CircleProgress 圆形进度条 TODO: 待完善
|
||||||
* @description 展示操作或任务的当前进度,比如上传文件,是一个圆形的进度环。
|
* @description 展示操作或任务的当前进度,比如上传文件,是一个圆形的进度环。
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/circleProgress.html
|
* @tutorial https://ijry.github.io/uview-plus/components/circleProgress.html
|
||||||
* @property {String | Number} percentage 圆环进度百分比值,为数值类型,0-100 (默认 30 )
|
* @property {String | Number} percentage 圆环进度百分比值,为数值类型,0-100 (默认 30 )
|
||||||
* @example
|
* @example
|
||||||
*/
|
*/
|
||||||
@@ -112,6 +112,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-circle-progress {
|
.u-circle-progress {
|
||||||
@include flex(row);
|
@include flex(row);
|
||||||
|
|||||||
@@ -1,169 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view class="u-city-locate">
|
|
||||||
<up-index-list :indexList="indexList">
|
|
||||||
<template #header>
|
|
||||||
<view class="u-current-city-wrap">
|
|
||||||
<view class="u-current-city-title">{{ t("up.cityLocate.locateCity") }}</view>
|
|
||||||
<view class="u-current-city-item" @tap="location">
|
|
||||||
<view class="u-location-city">{{locationCity}}</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
<template :key="index" v-for="(item, index) in cityList">
|
|
||||||
<!-- #ifdef APP-NVUE -->
|
|
||||||
<up-index-anchor :text="indexList[index]"></up-index-anchor>
|
|
||||||
<!-- #endif -->
|
|
||||||
<up-index-item>
|
|
||||||
<!-- #ifndef APP-NVUE -->
|
|
||||||
<up-index-anchor :text="indexList[index]"></up-index-anchor>
|
|
||||||
<!-- #endif -->
|
|
||||||
<view class="hot-city-list" v-if="index == 0">
|
|
||||||
<view class="" v-for="(item1, index1) in item" @tap="selectedCity(item1)">
|
|
||||||
<view class="hot-city-item">{{ item1[nameKey] }}</view>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
<view v-else class="item-list" v-for="(item1, index1) in item" :key="index1">
|
|
||||||
<view class="list__item" @tap="selectedCity(item1)">
|
|
||||||
<text class="list__item__city-name">{{item1[nameKey]}}</text>
|
|
||||||
</view>
|
|
||||||
<up-line></up-line>
|
|
||||||
</view>
|
|
||||||
</up-index-item>
|
|
||||||
</template>
|
|
||||||
<template #footer>
|
|
||||||
<view class="u-safe-area-inset--bottom">
|
|
||||||
<text class="list__footer"></text>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
</up-index-list>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { t } from '../../libs/i18n'
|
|
||||||
export default{
|
|
||||||
name: 'u-city-locate',
|
|
||||||
props:{
|
|
||||||
indexList: {
|
|
||||||
type: Array,
|
|
||||||
default: ['🔥']
|
|
||||||
},
|
|
||||||
cityList:{
|
|
||||||
type: Array,
|
|
||||||
default: () => {
|
|
||||||
return [
|
|
||||||
[{
|
|
||||||
name: '北京',
|
|
||||||
value: 'beijing'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '上海',
|
|
||||||
value: 'shanghai'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '广州',
|
|
||||||
value: 'guangzhou'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '深圳',
|
|
||||||
value: 'shenzhen'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '杭州',
|
|
||||||
value: 'hangzhou'
|
|
||||||
}]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
locationType: {
|
|
||||||
type: String,
|
|
||||||
default: 'wgs84'
|
|
||||||
},
|
|
||||||
currentCity: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
nameKey: {
|
|
||||||
type: String,
|
|
||||||
default: 'name'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed:{
|
|
||||||
},
|
|
||||||
watch:{
|
|
||||||
currentCity(val) {
|
|
||||||
this.locationCity = val;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data(){
|
|
||||||
return{
|
|
||||||
locationCity: t("up.cityLocate.locating") + '....'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
emits: ['location-success', 'select-city'],
|
|
||||||
methods:{
|
|
||||||
t,
|
|
||||||
// 获取城市
|
|
||||||
selectedCity(city){
|
|
||||||
this.locationCity = city[this.nameKey];
|
|
||||||
this.$emit('select-city', {
|
|
||||||
locationCity: this.locationCity
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 定位操作
|
|
||||||
location(){
|
|
||||||
let That = this;
|
|
||||||
uni.getLocation({
|
|
||||||
type: this.locationType,
|
|
||||||
geocode:true,
|
|
||||||
success(res){
|
|
||||||
console.log(res);
|
|
||||||
That.locationCity = res.address && res.address.city;
|
|
||||||
That.$emit('location-success', {
|
|
||||||
...res,
|
|
||||||
locationCity: That.locationCity
|
|
||||||
});
|
|
||||||
},
|
|
||||||
fail(){
|
|
||||||
That.locationCity = t("up.cityLocate.fail");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// 页面挂载后进行异步操作
|
|
||||||
created(){
|
|
||||||
},
|
|
||||||
mounted(){
|
|
||||||
this.location();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.list__item {
|
|
||||||
padding: 8px 1px;
|
|
||||||
}
|
|
||||||
.u-current-city-title {
|
|
||||||
color: var(--up-tips-color, #909399);
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
.u-location-city,
|
|
||||||
.list__item__city-name {
|
|
||||||
color: var(--up-main-color, #303133);
|
|
||||||
}
|
|
||||||
.u-current-city-item {
|
|
||||||
height: 30px;
|
|
||||||
}
|
|
||||||
.hot-city-list {
|
|
||||||
display: flex !important;
|
|
||||||
flex-direction: row !important;
|
|
||||||
padding: 12px 0;
|
|
||||||
.hot-city-item {
|
|
||||||
padding: 6px 12px;
|
|
||||||
margin: 5px;
|
|
||||||
color: var(--up-main-color, #303133);
|
|
||||||
border: 1px solid var(--up-border-color, #ededed);
|
|
||||||
background-color: var(--up-card-bg-color, #ffffff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:55:58
|
||||||
* @FilePath : /uview-plus/libs/config/props/codeInput.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/codeInput.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// codeInput 组件
|
// codeInput 组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CodeInputDefaultProps from './codeInput'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CodeInputDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 键盘弹起时,是否自动上推页面
|
// 键盘弹起时,是否自动上推页面
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
/**
|
/**
|
||||||
* CodeInput 验证码输入
|
* CodeInput 验证码输入
|
||||||
* @description 该组件一般用于验证用户短信验证码的场景,也可以结合uview-plus的键盘组件使用
|
* @description 该组件一般用于验证用户短信验证码的场景,也可以结合uview-plus的键盘组件使用
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/codeInput.html
|
* @tutorial https://ijry.github.io/uview-plus/components/codeInput.html
|
||||||
* @property {String | Number} maxlength 最大输入长度 (默认 6 )
|
* @property {String | Number} maxlength 最大输入长度 (默认 6 )
|
||||||
* @property {Boolean} dot 是否用圆点填充 (默认 false )
|
* @property {Boolean} dot 是否用圆点填充 (默认 false )
|
||||||
* @property {String} mode 显示模式,box-盒子模式,line-底部横线模式 (默认 'box' )
|
* @property {String} mode 显示模式,box-盒子模式,line-底部横线模式 (默认 'box' )
|
||||||
@@ -220,6 +220,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
$u-code-input-cursor-width: 1px;
|
$u-code-input-cursor-width: 1px;
|
||||||
$u-code-input-cursor-height: 20px;
|
$u-code-input-cursor-height: 20px;
|
||||||
$u-code-input-cursor-animation-duration: 1s;
|
$u-code-input-cursor-animation-duration: 1s;
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:55:27
|
||||||
* @FilePath : /uview-plus/libs/config/props/code.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/code.js
|
||||||
*/
|
*/
|
||||||
import { t } from '../../libs/i18n'
|
|
||||||
export default {
|
export default {
|
||||||
// code 组件
|
// code 组件
|
||||||
code: {
|
code: {
|
||||||
seconds: 60,
|
seconds: 60,
|
||||||
startText: t("up.code.send"),
|
startText: '获取验证码',
|
||||||
changeText: t("up.code.resendAfter"),
|
changeText: 'X秒重新获取',
|
||||||
endText: t("up.code.resend"),
|
endText: '重新获取',
|
||||||
keepRunning: false,
|
keepRunning: false,
|
||||||
uniqueKey: ''
|
uniqueKey: ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CodeDefaultProps from './code'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CodeDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 倒计时总秒数
|
// 倒计时总秒数
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
/**
|
/**
|
||||||
* Code 验证码输入框
|
* Code 验证码输入框
|
||||||
* @description 考虑到用户实际发送验证码的场景,可能是一个按钮,也可能是一段文字,提示语各有不同,所以本组件 不提供界面显示,只提供提示语,由用户将提示语嵌入到具体的场景
|
* @description 考虑到用户实际发送验证码的场景,可能是一个按钮,也可能是一段文字,提示语各有不同,所以本组件 不提供界面显示,只提供提示语,由用户将提示语嵌入到具体的场景
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/code.html
|
* @tutorial https://ijry.github.io/uview-plus/components/code.html
|
||||||
* @property {String | Number} seconds 倒计时所需的秒数(默认 60 )
|
* @property {String | Number} seconds 倒计时所需的秒数(默认 60 )
|
||||||
* @property {String} startText 开始前的提示语,见官网说明(默认 '获取验证码' )
|
* @property {String} startText 开始前的提示语,见官网说明(默认 '获取验证码' )
|
||||||
* @property {String} changeText 倒计时期间的提示语,必须带有字母"x",见官网说明(默认 'X秒重新获取' )
|
* @property {String} changeText 倒计时期间的提示语,必须带有字母"x",见官网说明(默认 'X秒重新获取' )
|
||||||
@@ -128,4 +128,5 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:56:12
|
||||||
* @FilePath : /uview-plus/libs/config/props/col.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/col.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// col 组件
|
// col 组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import ColDefaultProps from './col'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(ColDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 占父容器宽度的多少等分,总分为12份
|
// 占父容器宽度的多少等分,总分为12份
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
/**
|
/**
|
||||||
* CodeInput 栅格系统的列
|
* CodeInput 栅格系统的列
|
||||||
* @description 该组件一般用于Layout 布局 通过基础的 12 分栏,迅速简便地创建布局
|
* @description 该组件一般用于Layout 布局 通过基础的 12 分栏,迅速简便地创建布局
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/Layout.html
|
* @tutorial https://ijry.github.io/uview-plus/components/Layout.html
|
||||||
* @property {String | Number} span 栅格占据的列数,总12等份 (默认 12 )
|
* @property {String | Number} span 栅格占据的列数,总12等份 (默认 12 )
|
||||||
* @property {String | Number} offset 分栏左边偏移,计算方式与span相同 (默认 0 )
|
* @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} justify 水平排列方式,可选值为`start`(或`flex-start`)、`end`(或`flex-end`)、`center`、`around`(或`space-around`)、`between`(或`space-between`) (默认 'start' )
|
||||||
@@ -100,6 +100,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-col {
|
.u-col {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:56:42
|
||||||
* @FilePath : /uview-plus/libs/config/props/collapseItem.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/collapseItem.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// collapseItem 组件
|
// collapseItem 组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CollapseItemDefaultProps from './collapseItem'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CollapseItemDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 标题
|
// 标题
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<slot name="icon">
|
<slot name="icon">
|
||||||
<up-icon v-if="!$slots.icon && icon" :size="22" :name="icon"></up-icon>
|
<u-icon v-if="!$slots.icon && icon" :size="22" :name="icon"></u-icon>
|
||||||
</slot>
|
</slot>
|
||||||
</template>
|
</template>
|
||||||
<template #value>
|
<template #value>
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<template #right-icon>
|
<template #right-icon>
|
||||||
<template v-if="showRight">
|
<template v-if="showRight">
|
||||||
<up-icon v-if="!$slots['right-icon']" :size="16" name="arrow-right"></up-icon>
|
<u-icon v-if="!$slots['right-icon']" :size="16" name="arrow-right"></u-icon>
|
||||||
<slot name="right-icon">
|
<slot name="right-icon">
|
||||||
</slot>
|
</slot>
|
||||||
</template>
|
</template>
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
/**
|
/**
|
||||||
* collapseItem 折叠面板Item
|
* collapseItem 折叠面板Item
|
||||||
* @description 通过折叠面板收纳内容区域(搭配u-collapse使用)
|
* @description 通过折叠面板收纳内容区域(搭配u-collapse使用)
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/collapse.html
|
* @tutorial https://ijry.github.io/uview-plus/components/collapse.html
|
||||||
* @property {String} title 标题
|
* @property {String} title 标题
|
||||||
* @property {String} value 标题右侧内容
|
* @property {String} value 标题右侧内容
|
||||||
* @property {String} label 标题下方的描述信息
|
* @property {String} label 标题下方的描述信息
|
||||||
@@ -201,7 +201,7 @@
|
|||||||
// 查询内容高度
|
// 查询内容高度
|
||||||
queryRect() {
|
queryRect() {
|
||||||
// #ifndef APP-NVUE
|
// #ifndef APP-NVUE
|
||||||
// $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://uview-plus.jiangruyi.com/js/getRect.html
|
// $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://ijry.github.io/uview-plus/js/getRect.html
|
||||||
// 组件内部一般用this.$uGetRect,对外的为uni.$u.getRect,二者功能一致,名称不同
|
// 组件内部一般用this.$uGetRect,对外的为uni.$u.getRect,二者功能一致,名称不同
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
this.$uGetRect(`#${this.elId}`).then(size => {
|
this.$uGetRect(`#${this.elId}`).then(size => {
|
||||||
@@ -225,6 +225,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-collapse-item {
|
.u-collapse-item {
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:56:30
|
||||||
* @FilePath : /uview-plus/libs/config/props/collapse.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/collapse.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// collapse 组件
|
// collapse 组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CollapseDefaultProps from './collapse'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CollapseDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 当前展开面板的name,非手风琴模式:[<string | number>],手风琴模式:string | number
|
// 当前展开面板的name,非手风琴模式:[<string | number>],手风琴模式:string | number
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
/**
|
/**
|
||||||
* collapse 折叠面板
|
* collapse 折叠面板
|
||||||
* @description 通过折叠面板收纳内容区域
|
* @description 通过折叠面板收纳内容区域
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/collapse.html
|
* @tutorial https://ijry.github.io/uview-plus/components/collapse.html
|
||||||
* @property {String | Number | Array} value 当前展开面板的name,非手风琴模式:[<string | number>],手风琴模式:string | number
|
* @property {String | Number | Array} value 当前展开面板的name,非手风琴模式:[<string | number>],手风琴模式:string | number
|
||||||
* @property {Boolean} accordion 是否手风琴模式( 默认 false )
|
* @property {Boolean} accordion 是否手风琴模式( 默认 false )
|
||||||
* @property {Boolean} border 是否显示外边框 ( 默认 true )
|
* @property {Boolean} border 是否显示外边框 ( 默认 true )
|
||||||
@@ -87,4 +87,5 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:57:16
|
||||||
* @FilePath : /uview-plus/libs/config/props/columnNotice.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/columnNotice.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// columnNotice 组件
|
// columnNotice 组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import ColumnNoticeDefaultProps from './columnNotice'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(ColumnNoticeDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 显示的内容,字符串
|
// 显示的内容,字符串
|
||||||
|
|||||||
@@ -8,11 +8,11 @@
|
|||||||
class="u-notice__left-icon"
|
class="u-notice__left-icon"
|
||||||
v-if="icon"
|
v-if="icon"
|
||||||
>
|
>
|
||||||
<up-icon
|
<u-icon
|
||||||
:name="icon"
|
:name="icon"
|
||||||
:color="color"
|
:color="color"
|
||||||
size="19"
|
size="19"
|
||||||
></up-icon>
|
></u-icon>
|
||||||
</view>
|
</view>
|
||||||
</slot>
|
</slot>
|
||||||
<swiper
|
<swiper
|
||||||
@@ -40,19 +40,19 @@
|
|||||||
class="u-notice__right-icon"
|
class="u-notice__right-icon"
|
||||||
v-if="['link', 'closable'].includes(mode)"
|
v-if="['link', 'closable'].includes(mode)"
|
||||||
>
|
>
|
||||||
<up-icon
|
<u-icon
|
||||||
v-if="mode === 'link'"
|
v-if="mode === 'link'"
|
||||||
name="arrow-right"
|
name="arrow-right"
|
||||||
:size="17"
|
:size="17"
|
||||||
:color="color"
|
:color="color"
|
||||||
></up-icon>
|
></u-icon>
|
||||||
<up-icon
|
<u-icon
|
||||||
v-if="mode === 'closable'"
|
v-if="mode === 'closable'"
|
||||||
name="close"
|
name="close"
|
||||||
:size="16"
|
:size="16"
|
||||||
:color="color"
|
:color="color"
|
||||||
@click="close"
|
@click="close"
|
||||||
></up-icon>
|
></u-icon>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -66,7 +66,7 @@
|
|||||||
/**
|
/**
|
||||||
* ColumnNotice 滚动通知中的垂直滚动 内部组件
|
* ColumnNotice 滚动通知中的垂直滚动 内部组件
|
||||||
* @description 该组件用于滚动通告场景,是其中的垂直滚动方式
|
* @description 该组件用于滚动通告场景,是其中的垂直滚动方式
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/noticeBar.html
|
* @tutorial https://ijry.github.io/uview-plus/components/noticeBar.html
|
||||||
* @property {Array} text 显示的内容,字符串
|
* @property {Array} text 显示的内容,字符串
|
||||||
* @property {String} icon 是否显示左侧的音量图标 ( 默认 'volume' )
|
* @property {String} icon 是否显示左侧的音量图标 ( 默认 'volume' )
|
||||||
* @property {String} mode 通告模式,link-显示右箭头,closable-显示右侧关闭图标
|
* @property {String} mode 通告模式,link-显示右箭头,closable-显示右侧关闭图标
|
||||||
@@ -128,6 +128,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-notice {
|
.u-notice {
|
||||||
@include flex;
|
@include flex;
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<view @click="handleClick">
|
<view @click="handleClick">
|
||||||
<slot>{{ t("up.common.copy") }}</slot>
|
<slot>复制</slot>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { t } from '../../libs/i18n'
|
|
||||||
export default {
|
export default {
|
||||||
name: "up-copy",
|
name: "up-copy",
|
||||||
props: {
|
props: {
|
||||||
@@ -18,17 +17,16 @@ export default {
|
|||||||
},
|
},
|
||||||
notice: {
|
notice: {
|
||||||
type: String,
|
type: String,
|
||||||
default: t("up.common.copy") + t("up.common.success")
|
default: '复制成功'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: ['success'],
|
emits: ['success'],
|
||||||
methods: {
|
methods: {
|
||||||
t,
|
|
||||||
handleClick() {
|
handleClick() {
|
||||||
let content = this.content;
|
let content = this.content;
|
||||||
if (!content) {
|
if (!content) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: t("up.common.none"),
|
title: '暂无',
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
duration: 2000,
|
duration: 2000,
|
||||||
});
|
});
|
||||||
@@ -36,7 +34,7 @@ export default {
|
|||||||
}
|
}
|
||||||
content = typeof content === 'string' ? content : content.toString() // 复制内容,必须字符串,数字需要转换为字符串
|
content = typeof content === 'string' ? content : content.toString() // 复制内容,必须字符串,数字需要转换为字符串
|
||||||
/**
|
/**
|
||||||
* 复制逻辑
|
* 小程序端 和 app端的复制逻辑
|
||||||
*/
|
*/
|
||||||
let that = this;
|
let that = this;
|
||||||
uni.setClipboardData({
|
uni.setClipboardData({
|
||||||
@@ -44,7 +42,7 @@ export default {
|
|||||||
success: function() {
|
success: function() {
|
||||||
if (that.alertStyle == 'modal') {
|
if (that.alertStyle == 'modal') {
|
||||||
uni.showModal({
|
uni.showModal({
|
||||||
title: "up.common.tip",
|
title: '提示',
|
||||||
content: that.notice
|
content: that.notice
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -57,7 +55,7 @@ export default {
|
|||||||
},
|
},
|
||||||
fail:function(){
|
fail:function(){
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: t("up.common.copy") + t("up.common.fail"),
|
title: '复制失败',
|
||||||
icon: 'none',
|
icon: 'none',
|
||||||
duration:3000,
|
duration:3000,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 17:11:29
|
||||||
* @FilePath : /uview-plus/libs/config/props/countDown.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/countDown.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// u-count-down 计时器组件
|
// u-count-down 计时器组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CountDownDefaultProps from './countDown'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CountDownDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 倒计时时长,单位ms
|
// 倒计时时长,单位ms
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="u-count-down">
|
<view class="u-count-down">
|
||||||
<slot :days="timeData.days" :hours="timeData.hours"
|
<slot>
|
||||||
:minutes="timeData.minutes" :seconds="timeData.seconds">
|
|
||||||
<text class="u-count-down__text">{{ formattedTime }}</text>
|
<text class="u-count-down__text">{{ formattedTime }}</text>
|
||||||
</slot>
|
</slot>
|
||||||
</view>
|
</view>
|
||||||
@@ -113,7 +112,6 @@
|
|||||||
this.remainTime = remain
|
this.remainTime = remain
|
||||||
// 根据剩余的毫秒时间,得出该有天,小时,分钟等的值,返回一个对象
|
// 根据剩余的毫秒时间,得出该有天,小时,分钟等的值,返回一个对象
|
||||||
const timeData = parseTimeData(remain)
|
const timeData = parseTimeData(remain)
|
||||||
this.timeData = timeData;
|
|
||||||
this.$emit('change', timeData)
|
this.$emit('change', timeData)
|
||||||
// 得出格式化后的时间
|
// 得出格式化后的时间
|
||||||
this.formattedTime = parseFormat(this.format, timeData)
|
this.formattedTime = parseFormat(this.format, timeData)
|
||||||
@@ -153,6 +151,7 @@
|
|||||||
lang="scss"
|
lang="scss"
|
||||||
scoped
|
scoped
|
||||||
>
|
>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
$u-count-down-text-color:$u-content-color !default;
|
$u-count-down-text-color:$u-content-color !default;
|
||||||
$u-count-down-text-font-size:15px !default;
|
$u-count-down-text-font-size:15px !default;
|
||||||
$u-count-down-text-line-height:22px !default;
|
$u-count-down-text-line-height:22px !default;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:57:32
|
||||||
* @FilePath : /uview-plus/libs/config/props/countTo.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/countTo.js
|
||||||
*/
|
*/
|
||||||
export default {
|
export default {
|
||||||
// countTo 组件
|
// countTo 组件
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import CountToDefaultProps from './countTo'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(CountToDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 开始的数值,默认从0增长到某一个数
|
// 开始的数值,默认从0增长到某一个数
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { addUnit } from '../../libs/function/index';
|
|||||||
/**
|
/**
|
||||||
* countTo 数字滚动
|
* countTo 数字滚动
|
||||||
* @description 该组件一般用于需要滚动数字到某一个值的场景,目标要求是一个递增的值。
|
* @description 该组件一般用于需要滚动数字到某一个值的场景,目标要求是一个递增的值。
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/countTo.html
|
* @tutorial https://ijry.github.io/uview-plus/components/countTo.html
|
||||||
* @property {String | Number} startVal 开始的数值,默认从0增长到某一个数(默认 0 )
|
* @property {String | Number} startVal 开始的数值,默认从0增长到某一个数(默认 0 )
|
||||||
* @property {String | Number} endVal 要滚动的目标数值,必须 (默认 0 )
|
* @property {String | Number} endVal 要滚动的目标数值,必须 (默认 0 )
|
||||||
* @property {String | Number} duration 滚动到目标数值的动画持续时间,单位为毫秒(ms) (默认 2000 )
|
* @property {String | Number} duration 滚动到目标数值的动画持续时间,单位为毫秒(ms) (默认 2000 )
|
||||||
@@ -178,6 +178,8 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/components.scss";
|
||||||
|
|
||||||
.u-count-num {
|
.u-count-num {
|
||||||
/* #ifndef APP-NVUE */
|
/* #ifndef APP-NVUE */
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|||||||
@@ -1,405 +0,0 @@
|
|||||||
<template>
|
|
||||||
<view class="up-coupon" :class="[`up-coupon--${shape}`, `up-coupon--${type}`, `up-coupon--${size}`, {'up-coupon--disabled': disabled}]"
|
|
||||||
:style="[couponStyle]" @click="handleClick">
|
|
||||||
<view class="up-coupon__content">
|
|
||||||
<!-- 左侧金额区域 -->
|
|
||||||
<view class="up-coupon__amount">
|
|
||||||
<slot name="unit" :unit="unit" :unitPosition="unitPosition" v-if="unitPosition === 'left'">
|
|
||||||
<text class="up-coupon__amount-unit" v-if="unitPosition === 'left'">{{ unit }}</text>
|
|
||||||
</slot>
|
|
||||||
<slot name="amount" :amount="amount">
|
|
||||||
<text class="up-coupon__amount-value">{{ amount }}</text>
|
|
||||||
</slot>
|
|
||||||
<slot name="unit" :unit="unit" :unitPosition="unitPosition" v-if="unitPosition === 'right'">
|
|
||||||
<text class="up-coupon__amount-unit" v-if="unitPosition === 'right'">{{ unit }}</text>
|
|
||||||
</slot>
|
|
||||||
<slot name="limit" :limit="limit">
|
|
||||||
<text class="up-coupon__amount-limit" v-if="limit">{{ limit }}</text>
|
|
||||||
</slot>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 中间描述区域 -->
|
|
||||||
<view class="up-coupon__info">
|
|
||||||
<slot name="title" :title="title">
|
|
||||||
<text class="up-coupon__info-title">{{ title }}</text>
|
|
||||||
</slot>
|
|
||||||
<slot name="desc" :desc="desc">
|
|
||||||
<text class="up-coupon__info-desc" v-if="desc">{{ desc }}</text>
|
|
||||||
</slot>
|
|
||||||
<slot name="time" :time="time">
|
|
||||||
<text class="up-coupon__info-time" v-if="time">{{ time }}</text>
|
|
||||||
</slot>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 右侧操作区域 -->
|
|
||||||
<view class="up-coupon__action u-padding-right-20">
|
|
||||||
<slot name="action" :actionText="actionText" :circle="circle">
|
|
||||||
<up-tag type="error" :bgColor="type ? 'transparent' : '#eb433d'"
|
|
||||||
:borderColor="type ? '#eee' : '#eb433d'" borderRadius="6px"
|
|
||||||
size="medium" class="up-coupon__action-text"
|
|
||||||
:shape="circle ? 'circle': 'circle'">{{ actionText }}</up-tag>
|
|
||||||
</slot>
|
|
||||||
</view>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<!-- 红包绳子效果 -->
|
|
||||||
<view v-if="shape === 'envelope'" class="up-coupon__rope"></view>
|
|
||||||
|
|
||||||
<!-- 默认插槽,可用于添加额外内容 -->
|
|
||||||
<slot></slot>
|
|
||||||
</view>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'up-coupon',
|
|
||||||
props: {
|
|
||||||
// 金额
|
|
||||||
amount: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
// 金额单位
|
|
||||||
unit: {
|
|
||||||
type: String,
|
|
||||||
default: '¥'
|
|
||||||
},
|
|
||||||
// 单位位置
|
|
||||||
unitPosition: {
|
|
||||||
type: String,
|
|
||||||
default: 'left'
|
|
||||||
},
|
|
||||||
// 使用限制
|
|
||||||
limit: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
// 标题
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: '优惠券'
|
|
||||||
},
|
|
||||||
// 描述
|
|
||||||
desc: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
// 有效期
|
|
||||||
time: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
// 操作按钮文字
|
|
||||||
actionText: {
|
|
||||||
type: String,
|
|
||||||
default: '使用'
|
|
||||||
},
|
|
||||||
// 形状:coupon-优惠券, envelope-红包, card-卡片
|
|
||||||
shape: {
|
|
||||||
type: String,
|
|
||||||
default: 'coupon'
|
|
||||||
},
|
|
||||||
// 尺寸:small, medium, large
|
|
||||||
size: {
|
|
||||||
type: String,
|
|
||||||
default: 'medium'
|
|
||||||
},
|
|
||||||
// 是否圆形按钮
|
|
||||||
circle: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 是否禁用
|
|
||||||
disabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 背景颜色
|
|
||||||
bgColor: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
// 文字颜色
|
|
||||||
color: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
// 内置背景类型
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
couponStyle() {
|
|
||||||
const style = {};
|
|
||||||
if (this.bgColor) style.background = this.bgColor;
|
|
||||||
if (this.color) style.color = this.color;
|
|
||||||
return style;
|
|
||||||
},
|
|
||||||
dotCount() {
|
|
||||||
// 根据尺寸计算锯齿数量
|
|
||||||
const map = {
|
|
||||||
small: 8,
|
|
||||||
medium: 10,
|
|
||||||
large: 12
|
|
||||||
};
|
|
||||||
return map[this.size] || 10;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
handleClick() {
|
|
||||||
if (this.disabled) return;
|
|
||||||
this.$emit('click');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.up-coupon {
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
border-radius: 8rpx;
|
|
||||||
background: #ffebf0;
|
|
||||||
color: $u-main-color;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&--coupon {
|
|
||||||
border-radius: 16rpx;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
left: -24rpx;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
width: 48rpx;
|
|
||||||
height: 48rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
right: -24rpx;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
width: 48rpx;
|
|
||||||
height: 48rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--envelope {
|
|
||||||
border-radius: 16rpx;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
height: 20rpx;
|
|
||||||
background: repeating-linear-gradient(-45deg, #ffd000, #ffd000 10rpx, #ffa000 10rpx, #ffa000 20rpx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--card {
|
|
||||||
border-radius: 16rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--small {
|
|
||||||
// width: 520rpx;
|
|
||||||
height: 160rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--medium {
|
|
||||||
// width: 600rpx;
|
|
||||||
height: 180rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--large {
|
|
||||||
// width: 700rpx;
|
|
||||||
height: 220rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0 30rpx;
|
|
||||||
position: relative;
|
|
||||||
z-index: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__amount {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
padding-left: 10rpx;
|
|
||||||
padding-right: 30rpx;
|
|
||||||
border-right: 1px dashed #ccc;
|
|
||||||
|
|
||||||
&-unit {
|
|
||||||
font-size: 24rpx;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-value {
|
|
||||||
font-size: 56rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
color: red;
|
|
||||||
line-height: 1;
|
|
||||||
margin: 10rpx 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-limit {
|
|
||||||
font-size: 24rpx;
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__info {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
padding-left: 30rpx;
|
|
||||||
|
|
||||||
&-title {
|
|
||||||
font-size: 32rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 10rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-desc {
|
|
||||||
font-size: 24rpx;
|
|
||||||
opacity: 0.9;
|
|
||||||
margin-bottom: 10rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-time {
|
|
||||||
font-size: 20rpx;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__action {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__dots {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 30rpx 0;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__dot {
|
|
||||||
width: 32rpx;
|
|
||||||
height: 32rpx;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 50%;
|
|
||||||
margin: 0 -16rpx;
|
|
||||||
z-index: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__rope {
|
|
||||||
position: absolute;
|
|
||||||
top: -40rpx;
|
|
||||||
left: 50%;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
width: 80rpx;
|
|
||||||
height: 80rpx;
|
|
||||||
background: linear-gradient(to right, #ffd000, #ffa000);
|
|
||||||
border-radius: 40rpx 40rpx 0 0;
|
|
||||||
z-index: 1;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: -20rpx;
|
|
||||||
width: 20rpx;
|
|
||||||
height: 40rpx;
|
|
||||||
background: linear-gradient(to bottom, #ffd000, #ffa000);
|
|
||||||
border-radius: 10rpx 0 0 10rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: -20rpx;
|
|
||||||
width: 20rpx;
|
|
||||||
height: 40rpx;
|
|
||||||
background: linear-gradient(to bottom, #ffd000, #ffa000);
|
|
||||||
border-radius: 0 10rpx 10rpx 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 不同主题样式
|
|
||||||
&--primary {
|
|
||||||
background: linear-gradient(90deg, #43afff, #3b8cff);
|
|
||||||
color: #fff;
|
|
||||||
.up-coupon__amount {
|
|
||||||
border-right: 1px dashed #eee;
|
|
||||||
}
|
|
||||||
.up-coupon__amount-value {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--success {
|
|
||||||
background: linear-gradient(90deg, #67dda9, #19be6b);
|
|
||||||
color: #fff !important;
|
|
||||||
.up-coupon__amount {
|
|
||||||
border-right: 1px dashed #eee;
|
|
||||||
}
|
|
||||||
.up-coupon__amount-value {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--warning {
|
|
||||||
background: linear-gradient(90deg, #ff9739, #ff6a39);
|
|
||||||
color: #fff;
|
|
||||||
.up-coupon__amount {
|
|
||||||
border-right: 1px dashed #eee;
|
|
||||||
}
|
|
||||||
.up-coupon__amount-value {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--error {
|
|
||||||
background: linear-gradient(90deg, #ff7070, #ff4747);
|
|
||||||
color: #fff;
|
|
||||||
.up-coupon__amount {
|
|
||||||
border-right: 1px dashed #eee;
|
|
||||||
}
|
|
||||||
.up-coupon__amount-value {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* @Author : LQ
|
* @Author : LQ
|
||||||
* @Description :
|
* @Description :
|
||||||
* @version : 3.0
|
* @version : 1.0
|
||||||
* @Date : 2021-08-20 16:44:21
|
* @Date : 2021-08-20 16:44:21
|
||||||
* @LastAuthor : jry
|
* @LastAuthor : LQ
|
||||||
* @lastTime : 2025-12-19 08:55:21
|
* @lastTime : 2021-08-20 16:57:48
|
||||||
* @FilePath : /uview-plus/libs/config/props/datetimePicker.js
|
* @FilePath : /u-view2.0/uview-ui/libs/config/props/datetimePicker.js
|
||||||
*/
|
*/
|
||||||
import { t } from '../../libs/i18n'
|
|
||||||
export default {
|
export default {
|
||||||
// datetimePicker 组件
|
// datetimePicker 组件
|
||||||
datetimePicker: {
|
datetimePicker: {
|
||||||
@@ -23,24 +22,16 @@ export default {
|
|||||||
maxHour: 23,
|
maxHour: 23,
|
||||||
minMinute: 0,
|
minMinute: 0,
|
||||||
maxMinute: 59,
|
maxMinute: 59,
|
||||||
minSecond: 0,
|
|
||||||
maxSecond: 59,
|
|
||||||
filter: null,
|
filter: null,
|
||||||
formatter: null,
|
formatter: null,
|
||||||
loading: false,
|
loading: false,
|
||||||
itemHeight: 44,
|
itemHeight: 44,
|
||||||
cancelText: t("up.common.cancel"),
|
cancelText: '取消',
|
||||||
confirmText: t("up.common.confirm"),
|
confirmText: '确认',
|
||||||
cancelColor: '#909193',
|
cancelColor: '#909193',
|
||||||
confirmColor: '#3c9cff',
|
confirmColor: '#3c9cff',
|
||||||
visibleItemCount: 5,
|
visibleItemCount: 5,
|
||||||
closeOnClickOverlay: false,
|
closeOnClickOverlay: false,
|
||||||
defaultIndex: [],
|
defaultIndex: []
|
||||||
inputBorder: 'surround',
|
|
||||||
disabled: false,
|
|
||||||
disabledColor: '',
|
|
||||||
placeholder: t("up.common.pleaseChoose"),
|
|
||||||
inputProps: {},
|
|
||||||
pageInline: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,28 +1,15 @@
|
|||||||
import { defineMixin } from '../../libs/vue'
|
import { defineMixin } from '../../libs/vue'
|
||||||
import DatetimePickerDefaultProps from './datetimePicker'
|
import defProps from '../../libs/config/props.js'
|
||||||
import { registerComponentProps } from '../../libs/config/props.js'
|
|
||||||
|
|
||||||
const defProps = registerComponentProps(DatetimePickerDefaultProps)
|
|
||||||
export const props = defineMixin({
|
export const props = defineMixin({
|
||||||
props: {
|
props: {
|
||||||
// 是否显示input
|
// 是否显示input
|
||||||
hasInput: {
|
hasInput: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: () => false
|
||||||
},
|
|
||||||
inputProps: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inputBorder: {
|
|
||||||
type: String,
|
|
||||||
default: () => defProps.input.inputBorder
|
|
||||||
},
|
},
|
||||||
disabled: {
|
disabled: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: () => defProps.input.disabled
|
default: () => false
|
||||||
},
|
},
|
||||||
disabledColor:{
|
disabledColor:{
|
||||||
type: String,
|
type: String,
|
||||||
@@ -30,7 +17,7 @@ export const props = defineMixin({
|
|||||||
},
|
},
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => defProps.input.placeholder
|
default: () => '请选择'
|
||||||
},
|
},
|
||||||
format: {
|
format: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -75,7 +62,7 @@ export const props = defineMixin({
|
|||||||
type: String,
|
type: String,
|
||||||
default: () => defProps.datetimePicker.title
|
default: () => defProps.datetimePicker.title
|
||||||
},
|
},
|
||||||
// 展示格式,支持date、time、year-month、datetime、datehour、timesecond、datetimesecond
|
// 展示格式,mode=date为日期选择,mode=time为时间选择,mode=year-month为年月选择,mode=datetime为日期时间选择
|
||||||
mode: {
|
mode: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => defProps.datetimePicker.mode
|
default: () => defProps.datetimePicker.mode
|
||||||
@@ -92,36 +79,26 @@ export const props = defineMixin({
|
|||||||
// 最小默认值为前10年
|
// 最小默认值为前10年
|
||||||
default: () => defProps.datetimePicker.minDate
|
default: () => defProps.datetimePicker.minDate
|
||||||
},
|
},
|
||||||
// 可选的最小小时,仅mode=time/timesecond有效
|
// 可选的最小小时,仅mode=time有效
|
||||||
minHour: {
|
minHour: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: () => defProps.datetimePicker.minHour
|
default: () => defProps.datetimePicker.minHour
|
||||||
},
|
},
|
||||||
// 可选的最大小时,仅mode=time/timesecond有效
|
// 可选的最大小时,仅mode=time有效
|
||||||
maxHour: {
|
maxHour: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: () => defProps.datetimePicker.maxHour
|
default: () => defProps.datetimePicker.maxHour
|
||||||
},
|
},
|
||||||
// 可选的最小分钟,仅mode=time/timesecond有效
|
// 可选的最小分钟,仅mode=time有效
|
||||||
minMinute: {
|
minMinute: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: () => defProps.datetimePicker.minMinute
|
default: () => defProps.datetimePicker.minMinute
|
||||||
},
|
},
|
||||||
// 可选的最大分钟,仅mode=time/timesecond有效
|
// 可选的最大分钟,仅mode=time有效
|
||||||
maxMinute: {
|
maxMinute: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: () => defProps.datetimePicker.maxMinute
|
default: () => defProps.datetimePicker.maxMinute
|
||||||
},
|
},
|
||||||
// 可选的最小秒,仅mode=timesecond有效
|
|
||||||
minSecond: {
|
|
||||||
type: Number,
|
|
||||||
default: () => defProps.datetimePicker.minSecond
|
|
||||||
},
|
|
||||||
// 可选的最大秒,仅mode=timesecond有效
|
|
||||||
maxSecond: {
|
|
||||||
type: Number,
|
|
||||||
default: () => defProps.datetimePicker.maxSecond
|
|
||||||
},
|
|
||||||
// 选项过滤函数
|
// 选项过滤函数
|
||||||
filter: {
|
filter: {
|
||||||
type: [Function, null],
|
type: [Function, null],
|
||||||
@@ -176,21 +153,6 @@ export const props = defineMixin({
|
|||||||
defaultIndex: {
|
defaultIndex: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => defProps.datetimePicker.defaultIndex
|
default: () => defProps.datetimePicker.defaultIndex
|
||||||
},
|
}
|
||||||
// 是否页面内展示
|
|
||||||
pageInline:{
|
|
||||||
type: Boolean,
|
|
||||||
default: () => defProps.datetimePicker.pageInline
|
|
||||||
},
|
|
||||||
// 蒙层样式样式
|
|
||||||
maskClass: {
|
|
||||||
type: String,
|
|
||||||
defualt: ''
|
|
||||||
},
|
|
||||||
// 蒙层样式样式
|
|
||||||
maskStyle: {
|
|
||||||
type: String,
|
|
||||||
defualt: ''
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,17 +5,20 @@
|
|||||||
>
|
>
|
||||||
<slot name="trigger" :value="inputValue">
|
<slot name="trigger" :value="inputValue">
|
||||||
<up-input
|
<up-input
|
||||||
|
:placeholder="placeholder"
|
||||||
:readonly="!!showByClickInput"
|
:readonly="!!showByClickInput"
|
||||||
|
border="surround"
|
||||||
v-model="inputValue"
|
v-model="inputValue"
|
||||||
v-bind="inputPropsInner"
|
:disabled="disabled"
|
||||||
|
:disabledColor="disabledColor"
|
||||||
></up-input>
|
></up-input>
|
||||||
<cover-view class="input-cover">
|
<div class="input-cover">
|
||||||
</cover-view>
|
</div>
|
||||||
</slot>
|
</slot>
|
||||||
</view>
|
</view>
|
||||||
<u-picker
|
<u-picker
|
||||||
ref="picker"
|
ref="picker"
|
||||||
:show="pageInline || show || (hasInput && showByClickInput)"
|
:show="show || (hasInput && showByClickInput)"
|
||||||
:popupMode="popupMode"
|
:popupMode="popupMode"
|
||||||
:closeOnClickOverlay="closeOnClickOverlay"
|
:closeOnClickOverlay="closeOnClickOverlay"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
@@ -29,9 +32,6 @@
|
|||||||
:cancelColor="cancelColor"
|
:cancelColor="cancelColor"
|
||||||
:confirmColor="confirmColor"
|
:confirmColor="confirmColor"
|
||||||
:toolbarRightSlot="toolbarRightSlot"
|
:toolbarRightSlot="toolbarRightSlot"
|
||||||
:pageInline="pageInline"
|
|
||||||
:maskClass="maskClass"
|
|
||||||
:maskStyle="resolvedMaskStyle"
|
|
||||||
@close="close"
|
@close="close"
|
||||||
@cancel="cancel"
|
@cancel="cancel"
|
||||||
@confirm="confirm"
|
@confirm="confirm"
|
||||||
@@ -61,26 +61,24 @@
|
|||||||
import { props } from './props';
|
import { props } from './props';
|
||||||
import { mpMixin } from '../../libs/mixin/mpMixin';
|
import { mpMixin } from '../../libs/mixin/mpMixin';
|
||||||
import { mixin } from '../../libs/mixin/mixin';
|
import { mixin } from '../../libs/mixin/mixin';
|
||||||
import dayjs from './dayjs.esm.min.js';
|
import dayjs from 'dayjs/esm/index';
|
||||||
import { range, error, padZero } from '../../libs/function/index';
|
import { range, error, padZero } from '../../libs/function/index';
|
||||||
import test from '../../libs/function/test';
|
import test from '../../libs/function/test';
|
||||||
/**
|
/**
|
||||||
* DatetimePicker 时间日期选择器
|
* DatetimePicker 时间日期选择器
|
||||||
* @description 此选择器用于时间日期
|
* @description 此选择器用于时间日期
|
||||||
* @tutorial https://uview-plus.jiangruyi.com/components/datetimePicker.html
|
* @tutorial https://ijry.github.io/uview-plus/components/datetimePicker.html
|
||||||
* @property {Boolean} show 用于控制选择器的弹出与收起 ( 默认 false )
|
* @property {Boolean} show 用于控制选择器的弹出与收起 ( 默认 false )
|
||||||
* @property {Boolean} showToolbar 是否显示顶部的操作栏 ( 默认 true )
|
* @property {Boolean} showToolbar 是否显示顶部的操作栏 ( 默认 true )
|
||||||
* @property {String | Number} modelValue 绑定值
|
* @property {String | Number} modelValue 绑定值
|
||||||
* @property {String} title 顶部标题
|
* @property {String} title 顶部标题
|
||||||
* @property {String} mode 展示格式 mode=date为日期选择,mode=time为时间选择,mode=year-month为年月选择,mode=datetime为日期时间选择,mode=datehour为日期小时选择,mode=timesecond为时分秒选择,mode=datetimesecond为日期时分秒选择 ( 默认 ‘datetime )
|
* @property {String} mode 展示格式 mode=date为日期选择,mode=time为时间选择,mode=year-month为年月选择,mode=datetime为日期时间选择 ( 默认 ‘datetime )
|
||||||
* @property {Number} maxDate 可选的最大时间 默认值为后10年
|
* @property {Number} maxDate 可选的最大时间 默认值为后10年
|
||||||
* @property {Number} minDate 可选的最小时间 默认值为前10年
|
* @property {Number} minDate 可选的最小时间 默认值为前10年
|
||||||
* @property {Number} minHour 可选的最小小时,仅mode=time/timesecond有效 ( 默认 0 )
|
* @property {Number} minHour 可选的最小小时,仅mode=time有效 ( 默认 0 )
|
||||||
* @property {Number} maxHour 可选的最大小时,仅mode=time/timesecond有效 ( 默认 23 )
|
* @property {Number} maxHour 可选的最大小时,仅mode=time有效 ( 默认 23 )
|
||||||
* @property {Number} minMinute 可选的最小分钟,仅mode=time/timesecond有效 ( 默认 0 )
|
* @property {Number} minMinute 可选的最小分钟,仅mode=time有效 ( 默认 0 )
|
||||||
* @property {Number} maxMinute 可选的最大分钟,仅mode=time/timesecond有效 ( 默认 59 )
|
* @property {Number} maxMinute 可选的最大分钟,仅mode=time有效 ( 默认 59 )
|
||||||
* @property {Number} minSecond 可选的最小秒,仅mode=timesecond有效 ( 默认 0 )
|
|
||||||
* @property {Number} maxSecond 可选的最大秒,仅mode=timesecond有效 ( 默认 59 )
|
|
||||||
* @property {Function} filter 选项过滤函数
|
* @property {Function} filter 选项过滤函数
|
||||||
* @property {Function} formatter 选项格式化函数
|
* @property {Function} formatter 选项格式化函数
|
||||||
* @property {Boolean} loading 是否显示加载中状态 ( 默认 false )
|
* @property {Boolean} loading 是否显示加载中状态 ( 默认 false )
|
||||||
@@ -113,16 +111,7 @@
|
|||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
show(newValue, oldValue) {
|
show(newValue, oldValue) {
|
||||||
if (!newValue && this.hasInput) {
|
|
||||||
this.showByClickInput = false
|
|
||||||
}
|
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
// #ifdef VUE3
|
|
||||||
this.innerValue = this.correctValue(this.modelValue)
|
|
||||||
// #endif
|
|
||||||
// #ifdef VUE2
|
|
||||||
this.innerValue = this.correctValue(this.value)
|
|
||||||
// #endif
|
|
||||||
this.updateColumnValue(this.innerValue)
|
this.updateColumnValue(this.innerValue)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -145,64 +134,22 @@
|
|||||||
computed: {
|
computed: {
|
||||||
// 如果以下这些变量发生了变化,意味着需要重新初始化各列的值
|
// 如果以下这些变量发生了变化,意味着需要重新初始化各列的值
|
||||||
propsChange() {
|
propsChange() {
|
||||||
return [this.mode, this.maxDate, this.minDate, this.minHour, this.maxHour, this.minMinute, this.maxMinute, this.minSecond, this.maxSecond, this.filter, this.modelValue]
|
return [this.mode, this.maxDate, this.minDate, this.minHour, this.maxHour, this.minMinute, this.maxMinute, this.filter, ]
|
||||||
},
|
|
||||||
resolvedMaskStyle() {
|
|
||||||
if (this.upHasProp('maskStyle')) {
|
|
||||||
return this.maskStyle || ''
|
|
||||||
}
|
|
||||||
if (this.upThemeIsDark) {
|
|
||||||
const topBottomStrong = 'rgba(28, 28, 30, 0.95)'
|
|
||||||
const topBottomWeak = 'rgba(28, 28, 30, 0.6)'
|
|
||||||
return `background-image: linear-gradient(180deg, ${topBottomStrong}, ${topBottomWeak}), linear-gradient(0deg, ${topBottomStrong}, ${topBottomWeak});`
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
},
|
|
||||||
// input的props
|
|
||||||
inputPropsInner() {
|
|
||||||
return {
|
|
||||||
border: this.inputBorder,
|
|
||||||
placeholder: this.placeholder,
|
|
||||||
disabled: this.disabled,
|
|
||||||
disabledColor: this.disabledColor,
|
|
||||||
...this.inputProps
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.init()
|
this.init()
|
||||||
// pageInline模式下picker-view常驻显示,在原生端(Android/HarmonyOS)需要
|
|
||||||
// 等待原生picker-view组件完成初始化后再重新设置选中值,否则滚动位置可能不生效
|
|
||||||
if (this.pageInline) {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.updateIndexs(this.innerValue)
|
|
||||||
}, 200)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
// #ifdef VUE3
|
// #ifdef VUE3
|
||||||
emits: ['close', 'cancel', 'confirm', 'change', 'update:modelValue'],
|
emits: ['close', 'cancel', 'confirm', 'change', 'update:modelValue'],
|
||||||
// #endif
|
// #endif
|
||||||
methods: {
|
methods: {
|
||||||
toInt(value, fallback = 0) {
|
|
||||||
const num = parseInt(value, 10)
|
|
||||||
return Number.isFinite(num) ? num : fallback
|
|
||||||
},
|
|
||||||
// 按列安全读取 picker 值,避免快速滚动时出现越界/空值
|
|
||||||
safeColumnValue(values, columnIndex, optionIndex, fallback = '') {
|
|
||||||
const column = Array.isArray(values[columnIndex]) ? values[columnIndex] : []
|
|
||||||
if (!column.length) return fallback
|
|
||||||
let index = Number(optionIndex)
|
|
||||||
if (!Number.isFinite(index)) index = 0
|
|
||||||
index = range(0, column.length - 1, index)
|
|
||||||
const value = column[index]
|
|
||||||
return value == null ? fallback : value
|
|
||||||
},
|
|
||||||
getInputValue(newValue) {
|
getInputValue(newValue) {
|
||||||
if (newValue == '' || !newValue || newValue == undefined) {
|
if (newValue == '' || !newValue || newValue == undefined) {
|
||||||
this.inputValue = ''
|
this.inputValue = ''
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (this.mode === 'time' || this.mode === 'timesecond') {
|
if (this.mode == 'time') {
|
||||||
this.inputValue = newValue
|
this.inputValue = newValue
|
||||||
} else {
|
} else {
|
||||||
if (this.format) {
|
if (this.format) {
|
||||||
@@ -216,21 +163,12 @@
|
|||||||
case 'year-month':
|
case 'year-month':
|
||||||
format = 'YYYY-MM'
|
format = 'YYYY-MM'
|
||||||
break;
|
break;
|
||||||
case 'datehour':
|
|
||||||
format = 'YYYY-MM-DD HH'
|
|
||||||
break;
|
|
||||||
case 'datetime':
|
case 'datetime':
|
||||||
format = 'YYYY-MM-DD HH:mm'
|
format = 'YYYY-MM-DD HH:mm'
|
||||||
break;
|
break;
|
||||||
case 'datetimesecond':
|
|
||||||
format = 'YYYY-MM-DD HH:mm:ss'
|
|
||||||
break;
|
|
||||||
case 'time':
|
case 'time':
|
||||||
format = 'HH:mm'
|
format = 'HH:mm'
|
||||||
break;
|
break;
|
||||||
case 'timesecond':
|
|
||||||
format = 'HH:mm:ss'
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -256,13 +194,7 @@
|
|||||||
},
|
},
|
||||||
// 关闭选择器
|
// 关闭选择器
|
||||||
close() {
|
close() {
|
||||||
if (this.hasInput) {
|
|
||||||
this.showByClickInput = false
|
|
||||||
}
|
|
||||||
if (this.closeOnClickOverlay) {
|
if (this.closeOnClickOverlay) {
|
||||||
if (this.hasInput) {
|
|
||||||
this.showByClickInput = false
|
|
||||||
}
|
|
||||||
this.$emit('close')
|
this.$emit('close')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -292,13 +224,7 @@
|
|||||||
},
|
},
|
||||||
//用正则截取输出值,当出现多组数字时,抛出错误
|
//用正则截取输出值,当出现多组数字时,抛出错误
|
||||||
intercept(e,type){
|
intercept(e,type){
|
||||||
if (e === undefined || e === null) {
|
let judge = e.match(/\d+/g)
|
||||||
return type ? '0000' : '00'
|
|
||||||
}
|
|
||||||
let judge = String(e).match(/\d+/g)
|
|
||||||
if (!judge || judge.length === 0) {
|
|
||||||
return type ? '0000' : '00'
|
|
||||||
}
|
|
||||||
//判断是否掺杂数字
|
//判断是否掺杂数字
|
||||||
if(judge.length>1){
|
if(judge.length>1){
|
||||||
error("请勿在过滤或格式化函数时添加数字")
|
error("请勿在过滤或格式化函数时添加数字")
|
||||||
@@ -315,66 +241,30 @@
|
|||||||
// 列发生变化时触发
|
// 列发生变化时触发
|
||||||
change(e) {
|
change(e) {
|
||||||
const { indexs, values } = e
|
const { indexs, values } = e
|
||||||
const safeValues = Array.isArray(values) ? values : []
|
|
||||||
let selectValue = ''
|
let selectValue = ''
|
||||||
if (this.mode === 'time' || this.mode === 'timesecond') {
|
if(this.mode === 'time') {
|
||||||
// 根据value各列索引,从各列数组中,取出当前时间的选中值
|
// 根据value各列索引,从各列数组中,取出当前时间的选中值
|
||||||
const hourText = this.safeColumnValue(safeValues, 0, indexs[0], padZero(this.minHour))
|
selectValue = `${this.intercept(values[0][indexs[0]])}:${this.intercept(values[1][indexs[1]])}`
|
||||||
const minuteText = this.safeColumnValue(safeValues, 1, indexs[1], padZero(this.minMinute))
|
|
||||||
let hour = this.toInt(this.intercept(hourText), this.minHour)
|
|
||||||
let minute = this.toInt(this.intercept(minuteText), this.minMinute)
|
|
||||||
let second = this.minSecond
|
|
||||||
hour = range(this.minHour, this.maxHour, hour)
|
|
||||||
minute = range(this.minMinute, this.maxMinute, minute)
|
|
||||||
selectValue = `${padZero(hour)}:${padZero(minute)}`
|
|
||||||
if (this.mode === 'timesecond') {
|
|
||||||
const secondText = this.safeColumnValue(safeValues, 2, indexs[2], padZero(this.minSecond))
|
|
||||||
second = range(this.minSecond, this.maxSecond, this.toInt(this.intercept(secondText), this.minSecond))
|
|
||||||
selectValue = `${selectValue}:${padZero(second)}`
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const validCurrent = dayjs(this.innerValue).isValid() ? dayjs(this.innerValue) : dayjs(this.minDate)
|
|
||||||
const currentYear = validCurrent.year()
|
|
||||||
const currentMonth = validCurrent.month() + 1
|
|
||||||
const currentDate = validCurrent.date()
|
|
||||||
const currentHour = validCurrent.hour()
|
|
||||||
const currentMinute = validCurrent.minute()
|
|
||||||
const currentSecond = validCurrent.second()
|
|
||||||
|
|
||||||
const yearText = this.safeColumnValue(safeValues, 0, indexs[0], `${currentYear}`)
|
|
||||||
const monthText = this.safeColumnValue(safeValues, 1, indexs[1], padZero(currentMonth))
|
|
||||||
// 将选择的值转为数值,比如'03'转为数值的3,'2019'转为数值的2019
|
// 将选择的值转为数值,比如'03'转为数值的3,'2019'转为数值的2019
|
||||||
let year = this.toInt(this.intercept(yearText, 'year'), currentYear)
|
const year = parseInt(this.intercept(values[0][indexs[0]],'year'))
|
||||||
let month = this.toInt(this.intercept(monthText), currentMonth)
|
const month = parseInt(this.intercept(values[1][indexs[1]]))
|
||||||
let hour = 0, minute = 0, second = 0
|
let date = parseInt(values[2] ? this.intercept(values[2][indexs[2]]) : 1)
|
||||||
month = range(1, 12, month)
|
let hour = 0, minute = 0
|
||||||
// 此月份的最大天数
|
// 此月份的最大天数
|
||||||
const maxDate = dayjs(`${year}-${month}`).daysInMonth()
|
const maxDate = dayjs(`${year}-${month}`).daysInMonth()
|
||||||
const dayText = this.safeColumnValue(safeValues, 2, indexs[2], padZero(Math.min(currentDate, maxDate)))
|
|
||||||
let date = this.toInt(this.intercept(dayText), Math.min(currentDate, maxDate))
|
|
||||||
// year-month模式下,date不会出现在列中,设置为1,为了符合后边需要减1的需求
|
// year-month模式下,date不会出现在列中,设置为1,为了符合后边需要减1的需求
|
||||||
if (this.mode === 'year-month') {
|
if (this.mode === 'year-month') {
|
||||||
date = 1
|
date = 1
|
||||||
}
|
}
|
||||||
// 不允许超过maxDate值
|
// 不允许超过maxDate值
|
||||||
date = range(1, maxDate, date)
|
date = Math.min(maxDate, date)
|
||||||
if (this.mode === 'datehour' || this.mode === 'datetime' || this.mode === 'datetimesecond') {
|
if (this.mode === 'datetime') {
|
||||||
const hourText = this.safeColumnValue(safeValues, 3, indexs[3], padZero(currentHour))
|
hour = parseInt(this.intercept(values[3][indexs[3]]))
|
||||||
hour = range(0, 23, this.toInt(this.intercept(hourText), currentHour))
|
minute = parseInt(this.intercept(values[4][indexs[4]]))
|
||||||
}
|
|
||||||
if (this.mode === 'datetime' || this.mode === 'datetimesecond') {
|
|
||||||
const minuteText = this.safeColumnValue(safeValues, 4, indexs[4], padZero(currentMinute))
|
|
||||||
minute = range(0, 59, this.toInt(this.intercept(minuteText), currentMinute))
|
|
||||||
}
|
|
||||||
if (this.mode === 'datetimesecond') {
|
|
||||||
const secondText = this.safeColumnValue(safeValues, 5, indexs[5], padZero(currentSecond))
|
|
||||||
second = range(0, 59, this.toInt(this.intercept(secondText), currentSecond))
|
|
||||||
}
|
}
|
||||||
// 转为时间模式
|
// 转为时间模式
|
||||||
selectValue = Number(new Date(year, month - 1, date, hour, minute, second))
|
selectValue = Number(new Date(year, month - 1, date, hour, minute))
|
||||||
if (!Number.isFinite(selectValue)) {
|
|
||||||
selectValue = this.correctValue(this.innerValue)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 取出准确的合法值,防止超越边界的情况
|
// 取出准确的合法值,防止超越边界的情况
|
||||||
selectValue = this.correctValue(selectValue)
|
selectValue = this.correctValue(selectValue)
|
||||||
@@ -395,44 +285,33 @@
|
|||||||
this.innerValue = value
|
this.innerValue = value
|
||||||
this.updateColumns()
|
this.updateColumns()
|
||||||
// 延迟执行,等待u-picker组件列数据更新完后再设置选中值索引
|
// 延迟执行,等待u-picker组件列数据更新完后再设置选中值索引
|
||||||
// pageInline模式下picker-view常驻显示,需额外等待原生组件滚动到位
|
setTimeout(() => {
|
||||||
this.$nextTick(() => {
|
this.updateIndexs(value)
|
||||||
setTimeout(() => {
|
}, 0);
|
||||||
this.updateIndexs(value)
|
|
||||||
}, this.pageInline ? 100 : 0)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
// 更新索引
|
// 更新索引
|
||||||
updateIndexs(value) {
|
updateIndexs(value) {
|
||||||
let values = []
|
let values = []
|
||||||
const formatter = this.formatter || this.innerFormatter
|
const formatter = this.formatter || this.innerFormatter
|
||||||
if (this.mode === 'time' || this.mode === 'timesecond') {
|
if (this.mode === 'time') {
|
||||||
// 将time模式的时间用:分隔成数组
|
// 将time模式的时间用:分隔成数组
|
||||||
const timeArr = value.split(':')
|
const timeArr = value.split(':')
|
||||||
// 使用formatter格式化方法进行管道处理
|
// 使用formatter格式化方法进行管道处理
|
||||||
values = [formatter('hour', timeArr[0]), formatter('minute', timeArr[1])]
|
values = [formatter('hour', timeArr[0]), formatter('minute', timeArr[1])]
|
||||||
if (this.mode === 'timesecond') {
|
|
||||||
values.push(formatter('second', timeArr[2]))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
const date = new Date(value)
|
||||||
values = [
|
values = [
|
||||||
formatter('year', `${dayjs(value).year()}`),
|
formatter('year', `${dayjs(value).year()}`),
|
||||||
// 月份补0
|
// 月份补0
|
||||||
formatter('month', padZero(dayjs(value).month() + 1))
|
formatter('month', padZero(dayjs(value).month() + 1))
|
||||||
]
|
]
|
||||||
if (this.mode === 'date' || this.mode === 'datehour' || this.mode === 'datetime' || this.mode === 'datetimesecond') {
|
if (this.mode === 'date') {
|
||||||
// date模式,需要添加天列
|
// date模式,需要添加天列
|
||||||
values.push(formatter('day', padZero(dayjs(value).date())))
|
values.push(formatter('day', padZero(dayjs(value).date())))
|
||||||
}
|
}
|
||||||
if (this.mode === 'datehour' || this.mode === 'datetime' || this.mode === 'datetimesecond') {
|
if (this.mode === 'datetime') {
|
||||||
values.push(formatter('hour', padZero(dayjs(value).hour())))
|
|
||||||
}
|
|
||||||
if (this.mode === 'datetime' || this.mode === 'datetimesecond') {
|
|
||||||
// 数组的push方法,可以写入多个参数
|
// 数组的push方法,可以写入多个参数
|
||||||
values.push(formatter('minute', padZero(dayjs(value).minute())))
|
values.push(formatter('day', padZero(dayjs(value).date())), formatter('hour', padZero(dayjs(value).hour())), formatter('minute', padZero(dayjs(value).minute())))
|
||||||
}
|
|
||||||
if (this.mode === 'datetimesecond') {
|
|
||||||
values.push(formatter('second', padZero(dayjs(value).second())))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,35 +359,23 @@
|
|||||||
},
|
},
|
||||||
// 得出合法的时间
|
// 得出合法的时间
|
||||||
correctValue(value) {
|
correctValue(value) {
|
||||||
const isDateMode = !['time', 'timesecond'].includes(this.mode)
|
const isDateMode = this.mode !== 'time'
|
||||||
// if (isDateMode && !test.date(value)) {
|
// if (isDateMode && !test.date(value)) {
|
||||||
if (isDateMode && !dayjs.unix(value).isValid()) {
|
if (isDateMode && !dayjs.unix(value).isValid()) {
|
||||||
// 如果是日期类型,但是又没有设置合法的当前时间的话,使用最小时间为当前时间
|
// 如果是日期类型,但是又没有设置合法的当前时间的话,使用最小时间为当前时间
|
||||||
value = this.minDate
|
value = this.minDate
|
||||||
} else if (!isDateMode && !value) {
|
} else if (!isDateMode && !value) {
|
||||||
// 如果是时间类型,而又没有默认值的话,就用最小时间
|
// 如果是时间类型,而又没有默认值的话,就用最小时间
|
||||||
value = this.mode === 'timesecond'
|
value = `${padZero(this.minHour)}:${padZero(this.minMinute)}`
|
||||||
? `${padZero(this.minHour)}:${padZero(this.minMinute)}:${padZero(this.minSecond)}`
|
|
||||||
: `${padZero(this.minHour)}:${padZero(this.minMinute)}`
|
|
||||||
}
|
}
|
||||||
// 时间类型
|
// 时间类型
|
||||||
if (!isDateMode) {
|
if (!isDateMode) {
|
||||||
if (String(value).indexOf(':') === -1) return error('时间错误,请传递如12:24的格式')
|
if (String(value).indexOf(':') === -1) return error('时间错误,请传递如12:24的格式')
|
||||||
const timeArr = String(value).split(':')
|
let [hour, minute] = value.split(':')
|
||||||
let hour = timeArr[0]
|
|
||||||
let minute = timeArr[1]
|
|
||||||
let second = timeArr[2]
|
|
||||||
// 对时间补零,同时控制在最小值和最大值之间
|
// 对时间补零,同时控制在最小值和最大值之间
|
||||||
const hourNum = Number(hour)
|
hour = padZero(range(this.minHour, this.maxHour, Number(hour)))
|
||||||
const minuteNum = Number(minute)
|
minute = padZero(range(this.minMinute, this.maxMinute, Number(minute)))
|
||||||
hour = padZero(range(this.minHour, this.maxHour, Number.isNaN(hourNum) ? this.minHour : hourNum))
|
return `${ hour }:${ minute }`
|
||||||
minute = padZero(range(this.minMinute, this.maxMinute, Number.isNaN(minuteNum) ? this.minMinute : minuteNum))
|
|
||||||
if (this.mode === 'timesecond') {
|
|
||||||
const secondNum = Number(second)
|
|
||||||
second = padZero(range(this.minSecond, this.maxSecond, Number.isNaN(secondNum) ? this.minSecond : secondNum))
|
|
||||||
return `${hour}:${minute}:${second}`
|
|
||||||
}
|
|
||||||
return `${hour}:${minute}`
|
|
||||||
} else {
|
} else {
|
||||||
// 如果是日期格式,控制在最小日期和最大日期之间
|
// 如果是日期格式,控制在最小日期和最大日期之间
|
||||||
value = dayjs(value).isBefore(dayjs(this.minDate)) ? this.minDate : value
|
value = dayjs(value).isBefore(dayjs(this.minDate)) ? this.minDate : value
|
||||||
@@ -518,27 +385,20 @@
|
|||||||
},
|
},
|
||||||
// 获取每列的最大和最小值
|
// 获取每列的最大和最小值
|
||||||
getRanges() {
|
getRanges() {
|
||||||
if (this.mode === 'time' || this.mode === 'timesecond') {
|
if (this.mode === 'time') {
|
||||||
const timeColumns = [
|
return [
|
||||||
{
|
{
|
||||||
type: 'hour',
|
type: 'hour',
|
||||||
range: [this.minHour, this.maxHour],
|
range: [this.minHour, this.maxHour],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'minute',
|
type: 'minute',
|
||||||
range: [this.minMinute, this.maxMinute],
|
range: [this.minMinute, this.maxMinute],
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
if (this.mode === 'timesecond') {
|
|
||||||
timeColumns.push({
|
|
||||||
type: 'second',
|
|
||||||
range: [this.minSecond, this.maxSecond],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return timeColumns
|
|
||||||
}
|
}
|
||||||
const { maxYear, maxDate, maxMonth, maxHour, maxMinute, maxSecond } = this.getBoundary('max', this.innerValue);
|
const { maxYear, maxDate, maxMonth, maxHour, maxMinute, } = this.getBoundary('max', this.innerValue);
|
||||||
const { minYear, minDate, minMonth, minHour, minMinute, minSecond } = this.getBoundary('min', this.innerValue);
|
const { minYear, minDate, minMonth, minHour, minMinute, } = this.getBoundary('min', this.innerValue);
|
||||||
const result = [
|
const result = [
|
||||||
{
|
{
|
||||||
type: 'year',
|
type: 'year',
|
||||||
@@ -560,50 +420,28 @@
|
|||||||
type: 'minute',
|
type: 'minute',
|
||||||
range: [minMinute, maxMinute],
|
range: [minMinute, maxMinute],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
type: 'second',
|
|
||||||
range: [minSecond, maxSecond],
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
// 兜底:防止边界计算异常导致日列出现空范围(快速滚动场景)
|
|
||||||
if (result[2] && result[2].type === 'day') {
|
|
||||||
const start = Number(result[2].range[0])
|
|
||||||
const end = Number(result[2].range[1])
|
|
||||||
if (!Number.isFinite(start) || !Number.isFinite(end) || start > end) {
|
|
||||||
const fallbackDays = dayjs(this.innerValue).isValid() ? dayjs(this.innerValue).daysInMonth() : 31
|
|
||||||
result[2].range = [1, fallbackDays]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.mode === 'date')
|
if (this.mode === 'date')
|
||||||
result.splice(3, 3);
|
result.splice(3, 2);
|
||||||
if (this.mode === 'datehour')
|
|
||||||
result.splice(4, 2);
|
|
||||||
if (this.mode === 'datetime')
|
|
||||||
result.splice(5, 1);
|
|
||||||
if (this.mode === 'year-month')
|
if (this.mode === 'year-month')
|
||||||
result.splice(2, 4);
|
result.splice(2, 3);
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
// 根据minDate、maxDate、minHour、maxHour等边界值,判断各列的开始和结束边界值
|
// 根据minDate、maxDate、minHour、maxHour等边界值,判断各列的开始和结束边界值
|
||||||
getBoundary(type, innerValue) {
|
getBoundary(type, innerValue) {
|
||||||
let value = new Date(innerValue)
|
const value = new Date(innerValue)
|
||||||
if(isNaN(value.getTime())){
|
|
||||||
value = new Date()
|
|
||||||
}
|
|
||||||
const boundary = new Date(this[`${type}Date`])
|
const boundary = new Date(this[`${type}Date`])
|
||||||
const year = dayjs(boundary).year()
|
const year = dayjs(boundary).year()
|
||||||
let month = 1
|
let month = 1
|
||||||
let date = 1
|
let date = 1
|
||||||
let hour = 0
|
let hour = 0
|
||||||
let minute = 0
|
let minute = 0
|
||||||
let second = 0
|
|
||||||
if (type === 'max') {
|
if (type === 'max') {
|
||||||
month = 12
|
month = 12
|
||||||
// 月份的天数
|
// 月份的天数
|
||||||
date = dayjs(value).daysInMonth()
|
date = dayjs(value).daysInMonth()
|
||||||
hour = 23
|
hour = 23
|
||||||
minute = 59
|
minute = 59
|
||||||
second = 59
|
|
||||||
}
|
}
|
||||||
// 获取边界值,逻辑是:当年达到了边界值(最大或最小年),就检查月允许的最大和最小值,以此类推
|
// 获取边界值,逻辑是:当年达到了边界值(最大或最小年),就检查月允许的最大和最小值,以此类推
|
||||||
if (dayjs(value).year() === year) {
|
if (dayjs(value).year() === year) {
|
||||||
@@ -614,9 +452,6 @@
|
|||||||
hour = dayjs(boundary).hour()
|
hour = dayjs(boundary).hour()
|
||||||
if (dayjs(value).hour() === hour) {
|
if (dayjs(value).hour() === hour) {
|
||||||
minute = dayjs(boundary).minute()
|
minute = dayjs(boundary).minute()
|
||||||
if (dayjs(value).minute() === minute) {
|
|
||||||
second = dayjs(boundary).second()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -626,8 +461,7 @@
|
|||||||
[`${type}Month`]: month,
|
[`${type}Month`]: month,
|
||||||
[`${type}Date`]: date,
|
[`${type}Date`]: date,
|
||||||
[`${type}Hour`]: hour,
|
[`${type}Hour`]: hour,
|
||||||
[`${type}Minute`]: minute,
|
[`${type}Minute`]: minute
|
||||||
[`${type}Second`]: second
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onShowByClickInput(){
|
onShowByClickInput(){
|
||||||
@@ -641,6 +475,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@import '../../libs/css/components.scss';
|
||||||
.u-datetime-picker {
|
.u-datetime-picker {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
&__has-input {
|
&__has-input {
|
||||||
@@ -662,7 +497,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid var(--up-border-color, #eee);
|
border: 1px solid #eee;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user