You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

253 lines
5.6 KiB
Vue

1 year ago
<!-- 开关 -->
<template>
<view @click="onclick" class="d-inline-block tm-switch " >
<view class="tm-switch-wk relative " :style="[{width:width+'rpx',height:(height+4)+'rpx'}]">
<view class="tm-switch-bg round-l-24 round-r-24 flex-between"
:class="[bgColorCusjs,loaddingState?'opacity-7':'']"
>
<view class="text-size-xs tm-switch-txt text-align-center flex-center" style="width:50%">
<text>{{text[0]?text[0]:''}}</text>
</view>
<view class="text-size-xs tm-switch-txt text-align-center flex-center" style="width:50%">
<text class="pr-8">{{text[1]?text[1]:''}}</text>
</view>
</view>
<!-- bar -->
<view class="tm-switch-wk-bar absolute round-24 white flex-center "
:style="[
{transform:changValue?`translateX(${(width-(width/2+4))}rpx)`:`translateX(2rpx)`},
{width:(width/2-4)+'rpx',height:(height-4)+'rpx'}
]"
:class="[changValue?'shadow-'+color+'-10':'',changValue?'on aniOn':'aniOff']">
<text v-if="loaddingState" class="iconfont icon-loading" :class="[loaddingState?'load':'',`text-${color_tmeme}`]"></text>
</view>
</view>
</view>
</template>
<script>
/**
* 开关
* @property {String|Boolean} value = [true|false] 同v-model一样的值如果需要双向绑定需要value.sync推荐使用v-model
* @property {String|Number|Boolean|Object} name = [] 自定义数据change时携带
* @property {Function} change {checked,value:携带的name数据}
* @property {Boolean} disabled = [true|false] 默认false, 禁用
* @property {String} color = [] 默认primary, 主题色
* @property {Boolean} black = [true|false] 默认false, 暗黑模式
* @property {Boolean} loadding = [true|false] 默认false, 是否加载中
* @property {Array} text = [true|false] 默认 ['开','关'], 左右两边的字符
* @property {Number} width = [] 默认100,单位rpx宽度
* @property {Number} height = [] 默认50,单位rpx高度
* @property {String} offBgcolor = [] 默认'grey-lighten-2 text-grey', 主题色可以是文字色组合来改变文字和背景色.
* @example <tm-switch v-model="checked"></tm-switch>
*
*/
export default {
name: 'tm-switch',
model: {
prop: 'value',
event: 'input'
},
props:{
value:{
type:String|Boolean,
default:false
},
name:{
type:String|Number|Boolean|Object,
default:''
},
// 禁用。
disabled: {
type:Boolean|String,
default:false
},
loadding: {
type:Boolean|String,
default:false
},
color:{
type:String,
default:'primary'
},
// 暗黑
black: {
type:Boolean|String,
default:null
},
// 左右两边的字符。
text:{
type:Array,
default:()=>{
return ['开','关']
}
},
width:{
type:String|Number,
default:100
},
height:{
type:String|Number,
default:50
},
offBgcolor:{
type:String,
default:'grey-lighten-2 text-grey'
},
// 跟随主题色的改变而改变。
fllowTheme:{
type:Boolean|String,
default:true
}
},
watch: {
value: function(newval, oldval) {
if (newval !== oldval) {
if (!this.jiancMax()) {
this.changValue = false;
return;
}
}
}
},
computed: {
black_tmeme: function() {
if (this.black !== null) return this.black;
return this.$tm.vx.state().tmVuetify.black;
},
color_tmeme:function(){
if(this.$tm.vx.state().tmVuetify.color!==null&&this.$tm.vx.state().tmVuetify.color && this.fllowTheme){
return this.$tm.vx.state().tmVuetify.color;
}
return this.color;
},
changValue: {
get: function() {
return this.value;
},
set: function(newValue) {
this.$emit('input', newValue)
// 如果不想用v-model. 直接使用value,需要:value.sync
this.$emit('update:value', newValue);
}
},
loaddingState:function(){
return this.loadding;
},
bgColorCusjs(){
if(this.disabled) {
if(this.black_tmeme){
return 'grey-darken-4 bk';
}else{
return this.color_tmeme+' opacity-5';
}
}
if(this.black_tmeme){
if(this.changValue) return this.color_tmeme + ' bk ';
if(!this.changValue) return 'grey-darken-1 bk ';
}else{
if(this.changValue) return this.color_tmeme + ' text-white ';
if(!this.changValue) return this.offBgcolor;
}
}
},
data() {
return {
animationOn:null,
animationOff:null,
aniData:null,
};
},
mounted() {
},
methods: {
// 检查是否超过了最大选择。
jiancMax() {
if(this.disabled) return false;
return true;
},
onclick(e) {
if (this.disabled||this.loaddingState) return;
if (!this.jiancMax()) {
return;
}
this.changValue = !this.changValue;
this.change();
},
change() {
this.$nextTick(function(){
this.$emit('change', {
checked: this.changValue,
value: this.name
});
})
}
},
}
</script>
<style lang="scss" scoped>
.tm-switch{
vertical-align: middle;
.tm-switch-wk{
// width: 100rpx;
// height: 52rpx;
}
.tm-switch-bg{
width: 100%;
height: 100%;
transition: all 0.5s;
.tm-switch-txt{
// width: 50upx;
height: 100%;
// line-height: 48upx;
}
}
.tm-switch-wk-bar{
left: 4rpx;
top: 4rpx;
// width:40rpx;
// height: 46rpx;
transition: all 0.35s ease-in-out;
.load{
animation: xhRote 0.8s infinite linear;
}
}
}
.aniOn{
left: inherit;
}
.aniOff{
right: inherit;
}
@keyframes xhRote{
0%{
transform: rotate(0deg);
}
100%{
transform: rotate(360deg);
}
}
</style>