Compare commits

..

19 Commits

Author SHA1 Message Date
aisen
d355989fcf [fix] 修复switch组件交互模式,严格遵守mvvm思想,直接使用v-model绑定值后,切换按钮直接改绑定的值,不再需要@change里面去获取,简化了开发工作量 2026-01-28 10:23:14 +08:00
aisen
5b1e863066 [fix] 修复input 为选择框时没有提示问题 2025-12-01 14:41:53 +08:00
aisen
9c161727ff [fix] 修复input 为选择框时没有提示问题 2025-12-01 14:20:38 +08:00
aisen
71e58907a9 Merge remote-tracking branch 'origin/master' 2025-11-05 15:51:16 +08:00
aisen
8629754e50 [fix] 修复日历选中后下一个月份出现字体色出现空白问题 2025-11-05 15:51:10 +08:00
Mandy
d95276c469 update README.md.
Signed-off-by: Mandy <784454+bruce_qiq@user.noreply.gitee.com>
2025-10-25 01:55:14 +00:00
aisen
5186a277e1 [add] tn-input 加入防抖功能 2025-09-17 18:22:40 +08:00
aisen
5ba0d32004 [fix] 修复吸附组件的背景颜色bug 2025-03-27 16:01:13 +08:00
aisen
e87317d52e [fix] 修复车牌号的最后输入为0无法保存的问题 2025-02-26 23:21:26 +08:00
aisen
24f83965b5 [fix] 修复日历组件close事件问题 2025-01-09 15:28:27 +08:00
aisen
c001636b3a fix:图片上传拖拽排序判断是否移动端 2024-11-26 15:54:07 +08:00
aisen
b503f3610f fix:图片上传拖拽排序判断是否移动端 2024-11-26 15:43:43 +08:00
aisen
f3471b2646 fix:图片上传拖拽排序,在h5下保持和小程序一致体验,禁用长按菜单 2024-11-26 15:34:11 +08:00
Aisen
43c99c1fd9 [fix]修复图片裁剪不剧中的bug 2024-09-20 15:15:50 +08:00
Aisen
013f69a102 [fix]修复不同级数据,导致空报错问题 2024-07-03 15:04:51 +08:00
Aisen
b44bb802ed Merge remote-tracking branch 'origin/master' 2024-06-21 19:01:16 +08:00
Aisen
9dd0ea76b5 [add] input 左边图标,新增2个prop:leftIcon 左边图标、showLeftIcon是否显示左边图标,新增一个事件,leftClick:点击左边的触发 2024-06-21 19:01:05 +08:00
Aisen
125866d0e1 !10 删除console调试信息
感谢
2024-06-21 10:33:24 +00:00
wssam
c6bbf0a829 删除console调试信息
Signed-off-by: wssam <573616439@qq.com>
2024-04-25 09:15:50 +00:00
10 changed files with 159 additions and 65 deletions

View File

@@ -22,7 +22,7 @@
- 包含基础常用的布局元素flex、grid、浮动 - 包含基础常用的布局元素flex、grid、浮动
- 完整一体的配色体系包含4种色深模式同时包含4套渐变配色 - 完整一体的配色体系包含4种色深模式同时包含4套渐变配色
- 700+风格统一的图标icon60+精选组件,让开发者可以快速进行开发 - 800+风格统一的图标icon60+精选组件,让开发者可以快速进行开发
- 酷炫常用的页面模板,更有让你眼前一亮的界面效果 - 酷炫常用的页面模板,更有让你眼前一亮的界面效果
- 图片素材语雀便捷下载,图鸟生态共同成长 - 图片素材语雀便捷下载,图鸟生态共同成长
- 使用文档详尽说明让你一文读懂图鸟UI - 使用文档详尽说明让你一文读懂图鸟UI
@@ -33,8 +33,6 @@
[使用文档 vue2](https://vue2.tuniaokj.com/) [使用文档 vue2](https://vue2.tuniaokj.com/)
[图鸟ICON演示](https://tnicon.tuniaokj.com/)
## 快速上手 ## 快速上手
#### 1.复制文件到项目的根目录 #### 1.复制文件到项目的根目录
@@ -81,7 +79,7 @@ const app = new Vue({
```js ```js
// 引入TuniaoUI提供的vuex简写方法 // 引入TuniaoUI提供的vuex简写方法
let vuexStore = require('@/store/$tn.mixin.js') let vuexStore = require('@/store/$t.mixin.js')
Vue.mixin(vuexStore) Vue.mixin(vuexStore)
``` ```
@@ -115,7 +113,7 @@ Vue.mixin(vuexStore)
#### 6.配置easycom组件模式 #### 6.配置easycom组件模式
此配置需要在根目录的`pages.json`中进行。 此配置需要在根目录的`page.json`中进行。
::: tip 温馨提示 ::: tip 温馨提示
@@ -140,13 +138,13 @@ Vue.mixin(vuexStore)
## 图鸟UI开源项目图鸟UI、图鸟vue3、模板1234 已上传模板5678、图表暂未上传) ## 图鸟UI开源项目图鸟UI、图鸟vue3、图鸟模板1 2 3 4 5 、图鸟图表 已上传图鸟模板6 7 8 9 10 11 12 13 14 15 16 17 18 19 20暂未上传)
[![开源项目](https://resource.tuniaokj.com/images/uniapp_market/qr-code-all1.jpg "开源项目")](https://resource.tuniaokj.com/images/uniapp_market/qr-code-all1.jpg "开源项目") [![开源项目](https://resource.tuniaokj.com/images/uniapp_market/qr-code-all3.jpg "开源项目")](https://resource.tuniaokj.com/images/uniapp_market/qr-code-all3.jpg "开源项目")
## 图鸟UI-vue3开源项目[Github下载](https://github.com/tuniaoTech/tuniaoui-rc-vue3-uniapp)[Dcloud插件市场下载](https://ext.dcloud.net.cn/plugin?id=13530) ## 图鸟UI-vue3开源项目[建议Github下载](https://github.com/tuniaoTech/tuniaoui-rc-vue3-uniapp)[Dcloud插件市场下载](https://ext.dcloud.net.cn/plugin?id=13530)
[![开源项目](https://resource.tuniaokj.com/images/vue3/market/vue3-banner-min.jpg "开源项目")](https://resource.tuniaokj.com/images/vue3/market/vue3-banner-min.jpg "开源项目") [![开源项目](https://resource.tuniaokj.com/images/vue3/market/vue3-banner-min.jpg "开源项目")](https://resource.tuniaokj.com/images/vue3/market/vue3-banner-min.jpg "开源项目")
@@ -164,6 +162,7 @@ Vue.mixin(vuexStore)
## 联系作者 ## 联系作者
微信 tnkewo 微信 tnkewo
@@ -172,8 +171,10 @@ Vue.mixin(vuexStore)
[![作者微信 tnkewo](https://resource.tuniaokj.com/images/uniapp_market/tn_author_qrcode.jpg)](https://resource.tuniaokj.com/images/uniapp_market/tn_author_qrcode.jpg) [![作者微信 tnkewo](https://resource.tuniaokj.com/images/uniapp_market/tn_author_qrcode.jpg)](https://resource.tuniaokj.com/images/uniapp_market/tn_author_qrcode.jpg)
[![图鸟微信群](https://resource.tuniaokj.com/images/tuniao_group_info/qrcode_24-0124.jpg "图鸟微信群")](https://resource.tuniaokj.com/images/tuniao_group_info/qrcode_24-0124.jpg "图鸟微信群")
## 版权信息 ## 版权信息
`TuniaoUI开源版`遵循`Apache`协议意味着您无需支付任何费用也无需授权即可将TuniaoUI开源版应用到您的产品中但是需要保留TuniaoUI的信息。 `TuniaoUI开源版`遵循`Apache`协议意味着您无需支付任何费用也无需授权即可将TuniaoUI开源版应用到您的产品中但是需要保留TuniaoUI的信息。

View File

@@ -200,7 +200,7 @@
return return
} }
// this.licensePlateValue[this.currentLicensePlateIndex] = e // this.licensePlateValue[this.currentLicensePlateIndex] = e
this.$set(this.licensePlateValue, this.currentLicensePlateIndex, e) this.$set(this.licensePlateValue, this.currentLicensePlateIndex, e+"")
this.currentLicensePlateIndex++ this.currentLicensePlateIndex++
// 判断车牌是否已经选择完成 // 判断车牌是否已经选择完成
if (this.currentLicensePlateIndex === 8) { if (this.currentLicensePlateIndex === 8) {

View File

@@ -248,6 +248,7 @@
return (index, type) => { return (index, type) => {
let color = type === 'bg' ? '' : this.color let color = type === 'bg' ? '' : this.color
let day = index + 1 let day = index + 1
let date = `${this.year}-${this.month}-${day}` let date = `${this.year}-${this.month}-${day}`
let timestamp = new Date(date.replace(/\-/g,'/')).getTime() let timestamp = new Date(date.replace(/\-/g,'/')).getTime()
let start = this.startDate.replace(/\-/g,'/') let start = this.startDate.replace(/\-/g,'/')
@@ -487,8 +488,9 @@
let daysArr = days.map((item) => { let daysArr = days.map((item) => {
let bottomInfo = this.showLunar ? Calendar.solar2lunar(this.year, this.month, item).IDayCn : '' let bottomInfo = this.showLunar ? Calendar.solar2lunar(this.year, this.month, item).IDayCn : ''
let color = this.showLunar ? this.lunarColor : this.activeColor let color = this.showLunar ? this.lunarColor : this.activeColor
let date = `${this.year}-${this.month}-${item}`
if ( if (
(this.mode === 'date' && this.day == item) || (this.mode === 'date' && date == this.activeDate) ||
(this.mode === 'range' && (this.startDay == item || this.endDay == item)) (this.mode === 'range' && (this.startDay == item || this.endDay == item))
) { ) {
color = this.activeColor color = this.activeColor
@@ -501,7 +503,7 @@
bottomInfo = this.endText bottomInfo = this.endText
} }
} }
return { return {
day: item, day: item,
color: color, color: color,
@@ -534,7 +536,9 @@
}, },
// 关闭窗口 // 关闭窗口
close() { close() {
this.$emit('input', false) this.$emit('input', false);
//传递事件
this.$emit('close');
} }
} }
} }

View File

@@ -46,8 +46,8 @@ function propChange(prop, oldProp, ownerInstance, instance) {
cropper.canvasHeight = +dataset.height cropper.canvasHeight = +dataset.height
cropper.imgTop = +dataset.windowheight / 2 cropper.imgTop = +dataset.windowheight / 2
cropper.imgLeft = +dataset.windowwidth / 2 cropper.imgLeft = +dataset.windowwidth / 2
cropper.imgWidth = +dataset.imgwidth cropper.imgWidth = +dataset.width
cropper.imgHeight = +dataset.imgheight cropper.imgHeight = +dataset.height
cropper.windowHeight = +dataset.windowheight cropper.windowHeight = +dataset.windowheight
cropper.windowWidth = +dataset.windowwidth cropper.windowWidth = +dataset.windowwidth
cropper.init = false cropper.init = false

View File

@@ -300,7 +300,9 @@
}, },
timer: null, timer: null,
dragging: false, dragging: false,
show:true show:true,
h5LongPress:false,
h5StarDragging:false
} }
}, },
watch: { watch: {
@@ -329,7 +331,11 @@
mounted() { mounted() {
this.$nextTick(() => { this.$nextTick(() => {
this.updateDragInfo() this.updateDragInfo()
}) });
// #ifdef H5
const userAgent = navigator.userAgent.toLowerCase();
this.h5LongPress = /ipad|iphone|midp|rv:1.2.3.4|ucweb|android|windows ce|windows mobile/.test(userAgent);
// #endif
}, },
methods: { methods: {
// 清除列表 // 清除列表
@@ -738,6 +744,11 @@
// #endif // #endif
}, },
movableLongPress(item) { movableLongPress(item) {
// #ifdef H5
//h5必须长按后才允许拖拽
this.h5StarDragging = true;
this.movableStart(item);
// #endif
// #ifndef H5 // #ifndef H5
uni.vibrateShort() uni.vibrateShort()
// console.log("LongPress--------------------------------------------------------------"); // console.log("LongPress--------------------------------------------------------------");
@@ -804,7 +815,10 @@
} }
}, },
movableStart (item) { movableStart (item) {
// console.log("movableStart"); if (this.h5LongPress && !this.h5StarDragging){
return
}
//console.log("movableStart");
this.lists.forEach(item => { this.lists.forEach(item => {
item.zIndex = 1 item.zIndex = 1
// #ifdef H5 // #ifdef H5
@@ -825,8 +839,9 @@
// #endif // #endif
}, },
movableEnd (item) { movableEnd (item) {
this.h5StarDragging = false;
if (!this.dragging) return if (!this.dragging) return
// console.log("movableEnd"); //console.log("movableEnd");
const index = this.lists.findIndex(obj => { const index = this.lists.findIndex(obj => {
return obj.id === item.id return obj.id === item.id
}) })
@@ -892,6 +907,9 @@
.tn-image-upload { .tn-image-upload {
position: relative; position: relative;
/* #ifdef H5 */
-webkit-touch-callout:none;
/* #endif */
&__movable-area { &__movable-area {
width: 100%; width: 100%;

View File

@@ -12,6 +12,12 @@
}" }"
@tap.stop="inputClick" @tap.stop="inputClick"
> >
<view
v-if="showLeftIcon"
class="tn-input__left-icon__item tn-input__left-icon__clear"
>
<tn-button shape="icon" :scene="scene" :block-time="blockTime" @click="leftIconClick"><view class="icon" :class="[`tn-icon-${leftIcon}`]"></view></tn-button>
</view>
<textarea <textarea
v-if="type === 'textarea'" v-if="type === 'textarea'"
class="tn-input__input tn-input__textarea" class="tn-input__input tn-input__textarea"
@@ -39,7 +45,7 @@
v-if="type === 'select'" v-if="type === 'select'"
class="tn-input__text" class="tn-input__text"
> >
{{defaultValue}} <text :class="defaultValue == undefined || defaultValue == '' ? 'tn-input__placeholder':''">{{defaultValue == undefined || defaultValue == '' ? placeholder : defaultValue }}</text>
</view> </view>
<input <input
@@ -108,6 +114,9 @@
<script> <script>
import Emitter from '../../libs/utils/emitter.js' import Emitter from '../../libs/utils/emitter.js'
import {
debounceFun
} from '../../libs/function/applyEven.js'
export default { export default {
mixins: [Emitter], mixins: [Emitter],
@@ -240,6 +249,16 @@
type: String, type: String,
default: '' default: ''
}, },
// 是否在输入框内最左边显示图标
showLeftIcon: {
type: Boolean,
default: false
},
// 最左边图标的名称
leftIcon: {
type: String,
default: ''
},
//场景debounce :防抖模式 throttle节流模式 //场景debounce :防抖模式 throttle节流模式
scene:{ scene:{
type: String, type: String,
@@ -309,34 +328,16 @@
this.$on("on-form-item-error", this.onFormItemError) this.$on("on-form-item-error", this.onFormItemError)
}, },
methods: { methods: {
leftIconClick(){
this.$emit('leftClick', this.defaultValue)
},
rightIconClick(){ rightIconClick(){
this.$emit('rightClick', this.defaultValue) this.$emit('rightClick', this.defaultValue)
}, },
/** /**
* input事件 * input事件
*/ */
handleInput(event) { handleInput:()=>{},
let value = event.detail.value
// 是否需要去掉空格
if (this.trim) value = this.$tn.string.trim(value)
// 原生事件
this.$emit('input', value)
// model赋值
this.defaultValue = value
// 过一个生命周期再发送事件给tn-form-item否则this.$emit('input')更新了父组件的值,但是微信小程序上
// 尚未更新到tn-form-item导致获取的值为空从而校验混论
// 这里不能延时时间太短或者使用this.$nextTick否则在头条上会造成混乱
setTimeout(() => {
// 头条小程序由于自身bug导致中文下每按下一个键(尚未完成输入),都会触发一次@input导致错误这里进行判断处理
// #ifdef MP-TOUTIAO
if (this.$tn.string.trim(value) === this.lastValue) return
this.lastValue = value
// #endif
// 发送当前的值到form-item进行校验
this.dispatch('tn-form-item','on-form-change', value)
}, 40)
},
/** /**
* blur事件 * blur事件
*/ */
@@ -385,7 +386,35 @@
inputClick() { inputClick() {
this.$emit('click') this.$emit('click')
} }
} },
mounted() {
let that = this;
that.handleInput = debounceFun(function(event){
let value = event.detail.value
// 是否需要去掉空格
try {
if (that.trim) value = that.$tn.string.trim(value)
}catch (e){
}
// 原生事件
that.$emit('input', value)
// model赋值
that.defaultValue = value
// 过一个生命周期再发送事件给tn-form-item否则this.$emit('input')更新了父组件的值,但是微信小程序上
// 尚未更新到tn-form-item导致获取的值为空从而校验混论
// 这里不能延时时间太短或者使用this.$nextTick否则在头条上会造成混乱
setTimeout(() => {
// 头条小程序由于自身bug导致中文下每按下一个键(尚未完成输入),都会触发一次@input导致错误这里进行判断处理
// #ifdef MP-TOUTIAO
if (that.$tn.string.trim(value) === that.lastValue) return
that.lastValue = value
// #endif
// 发送当前的值到form-item进行校验
that.dispatch('tn-form-item','on-form-change', value)
}, 40)
},that.blockTime);
},
} }
</script> </script>
@@ -395,7 +424,11 @@
flex-direction: row; flex-direction: row;
position: relative; position: relative;
flex: 1; flex: 1;
&__placeholder{
color: $tn-font-sub-color;
}
&__input { &__input {
font-size: 28rpx; font-size: 28rpx;
color: $tn-font-color; color: $tn-font-color;
@@ -428,7 +461,8 @@
&--error { &--error {
border-color: $tn-color-red !important; border-color: $tn-color-red !important;
} }
&__right-icon { &__right-icon {
line-height: 1; line-height: 1;
.icon { .icon {
@@ -457,5 +491,32 @@
} }
} }
} }
&__left-icon {
line-height: 1;
&__item {
margin-left: 0rpx;
margin-top: 4rpx;
}
&__clear {
.icon {
font-size: 32rpx;
color: $tn-font-sub-color;
}
}
&__select {
transition: transform .4s;
.icon {
font-size: 26rpx;
}
&--reverse {
transform: rotate(-180deg);
}
}
}
} }
</style> </style>

View File

@@ -317,13 +317,15 @@
// 在历遍的过程中可能由于上一步修改this.columnData导致产生连锁反应程序触发columnChange会有多次调用 // 在历遍的过程中可能由于上一步修改this.columnData导致产生连锁反应程序触发columnChange会有多次调用
// 只有在最后一次数据稳定后的结果是正确的此前的历遍中可能会产生undefined故需要判断 // 只有在最后一次数据稳定后的结果是正确的此前的历遍中可能会产生undefined故需要判断
columnIndex.map((item, index) => { columnIndex.map((item, index) => {
let data = this.columnData[index][columnIndex[index]] if (this.columnData[index]){
let tmp = { let data = this.columnData[index][columnIndex[index]]
value: data ? data[this.valueName] : null, let tmp = {
label: data ? data[this.labelName] : null value: data ? data[this.valueName] : null,
label: data ? data[this.labelName] : null
}
if (data && data.extra !== undefined) tmp.extra = data.extra
this.selectValue.push(tmp)
} }
if (data && data.extra !== undefined) tmp.extra = data.extra
this.selectValue.push(tmp)
}) })
this.lastSelectIndex = columnIndex this.lastSelectIndex = columnIndex
} else if (this.mode === 'single') { } else if (this.mode === 'single') {

View File

@@ -12,7 +12,8 @@
top: stickyTop + 'px', top: stickyTop + 'px',
left: left + 'px', left: left + 'px',
width: width === 'auto' ? 'auto' : width + 'px', width: width === 'auto' ? 'auto' : width + 'px',
zIndex: elZIndex zIndex: elZIndex,
backgroundColor: backgroundColorStyle
}" }"
> >
<slot></slot> <slot></slot>
@@ -83,9 +84,6 @@
stickyStyle() { stickyStyle() {
let style = {} let style = {}
style.height = this.fixed ? this.height + 'px' : 'auto' style.height = this.fixed ? this.height + 'px' : 'auto'
if (this.backgroundColorStyle) {
style.color = this.backgroundColorStyle
}
if (this.elZIndex) { if (this.elZIndex) {
style.zIndex = this.elZIndex style.zIndex = this.elZIndex
} }

View File

@@ -2,7 +2,7 @@
<view <view
class="tn-switch-class tn-switch" class="tn-switch-class tn-switch"
:class="[ :class="[
value ? 'tn-switch--on' : '', switchState ? 'tn-switch--on' : '',
disabled ? 'tn-switch--disabled' : '', disabled ? 'tn-switch--disabled' : '',
`tn-switch--${shape}` `tn-switch--${shape}`
]" ]"
@@ -22,7 +22,7 @@
class="tn-switch__icon tn-switch__icon--left" class="tn-switch__icon tn-switch__icon--left"
:class="[ :class="[
`tn-icon-${leftIcon}`, `tn-icon-${leftIcon}`,
value ? 'tn-switch__icon--show' : '' switchState ? 'tn-switch__icon--show' : ''
]" ]"
:style="[iconStyle]"></view> :style="[iconStyle]"></view>
<!-- 右图标 --> <!-- 右图标 -->
@@ -31,7 +31,7 @@
class="tn-switch__icon tn-switch__icon--right" class="tn-switch__icon tn-switch__icon--right"
:class="[ :class="[
`tn-icon-${rightIcon}`, `tn-icon-${rightIcon}`,
!value ? 'tn-switch__icon--show' : '' !switchState ? 'tn-switch__icon--show' : ''
]" ]"
:style="[iconStyle]"></view> :style="[iconStyle]"></view>
</view> </view>
@@ -42,7 +42,7 @@
name: 'tn-switch', name: 'tn-switch',
props: { props: {
value: { value: {
type: Boolean, type: [Number, String, Boolean],
default: false default: false
}, },
// 按钮的样式 // 按钮的样式
@@ -106,7 +106,7 @@
switchStyle() { switchStyle() {
let style = {} let style = {}
style.fontSize = this.$tn.string.getLengthUnitValue(this.size) style.fontSize = this.$tn.string.getLengthUnitValue(this.size)
style.backgroundColor = this.value ? style.backgroundColor = this.switchState ?
this.activeColor ? this.activeColor : '#01BEFF' : this.activeColor ? this.activeColor : '#01BEFF' :
this.inactiveColor ? this.inactiveColor : '#AAAAAA' this.inactiveColor ? this.inactiveColor : '#AAAAAA'
return style return style
@@ -124,22 +124,33 @@
return style return style
}, },
loadingColor() { loadingColor() {
return this.value ? this.activeColor : '' return this.switchState ? this.activeColor : ''
}
},
watch:{
value:{
handler(newVal,oldVal){
this.switchState = (this.value == this.activeValue);
}
} }
}, },
data() { data() {
return { return {
switchState:false
} }
}, },
mounted() {
this.switchState = (this.value == this.activeValue);
},
methods: { methods: {
click() { click() {
this.switchState = !this.switchState;
if (!this.disabled && !this.loading) { if (!this.disabled && !this.loading) {
if (this.vibrateShort) uni.vibrateShort() if (this.vibrateShort) uni.vibrateShort()
this.$emit('input', !this.value) this.$emit('input', this.switchState ? this.activeValue : this.inactiveValue)
// 放到下一个生命周期因为双向绑定的value修改父组件状态需要时间且是异步的 // 放到下一个生命周期因为双向绑定的value修改父组件状态需要时间且是异步的
this.$nextTick(() => { this.$nextTick(() => {
this.$emit('change', this.value ? this.activeValue : this.inactiveValue); this.$emit('change', this.switchState ? this.activeValue : this.inactiveValue);
}) })
} }
} }

View File

@@ -20,7 +20,6 @@ export function throttleFun(func, delay=500) {
timer = setTimeout(() => { timer = setTimeout(() => {
//执行前清空 //执行前清空
timer = null; timer = null;
console.log("执行了")
func.apply(this, args); func.apply(this, args);
}, delay); }, delay);
} }