UniApp和微信小程序中v-switch夜间模式动画开关-微信小程序兼容版

时间:2025-03-29 07:44:48

switch.wxml

<view class="main-container" style="background-color: {{value ? '#9aa6d6' : '#20114c'}}; transform: scale({{size}})" bindtap="onClick">
  <view class="content" style="left: {{value ? '0' : '-80rpx'}}">
    <!-- 云 -->
    <view class="left">
      <view
        class="cloud"
        wx:for="{{cloudList}}"
        wx:key="id"
        style="top: {{item.top}}rpx; left: {{value ? item.left : 0}}rpx; transform: scale({{item.scale}}); transition: {{item.transition}}s"
      >
        <view class="cloud-square"></view>
        <view class="cloud-circle"></view>
        <view class="cloud-circle small"></view>
      </view>
    </view>
    <!-- 太阳 and 月亮 -->
    <view class="middle" style="background-color: {{value ? '#ffe2a1' : '#fff'}}">
      <view class="crater-box" style="transform: {{!value ? 'translate(0,0)' : 'translate(50rpx,-50rpx)'}}">
        <view
          class="crater crater{{item.id}}"
          wx:for="{{craterList}}"
          wx:key="id"
          style="top: {{item.top}}rpx; left: {{item.left}}rpx; transform: scale({{item.scale}}); opacity: {{item.opacity}}"
        ></view>
      </view>
    </view>
    <!-- 星星 -->
    <view class="right">
      <view class="star-box">
        <view
          class="star star{{item.id}} {{!value ? 'twinkle' : ''}}"
          wx:for="{{starList}}"
          wx:key="id"
          style="top: {{item.top}}rpx; left: {{!value ? item.left : 50}}rpx; transition: {{item.transition}}s; animation-delay: {{item.delay}}s"
        ></view>
      </view>
    </view>
  </view>
</view>

switch.wxss

.main-container {
  position: relative;
  width: 160rpx;
  height: 80rpx;
  background-color: #20114c;
  border-radius: 40rpx;
  transition: 1s all cubic-bezier(0.2, 0.1, 0.1, 0.8);
  overflow: hidden;
}

.content {
  position: absolute;
  top: 0;
  height: 100%;
  width: 240rpx;
  transition: 0.6s all cubic-bezier(0.2, 0.1, 0.1, 0.8);
  overflow: hidden;
}

.left {
  position: absolute;
  top: 50%;
  left: 0;
  height: 100%;
  width: 86rpx;
  transform: translateY(-50%);
  z-index: 1;
}

.cloud {
  top: 50%;
  left: 50%;
  position: absolute;
  width: 36rpx;
  height: 26rpx;
}

.cloud-square {
  position: absolute;
  bottom: 0;
  width: 36rpx;
  height: 18rpx;
  border-radius: 9rpx;
  background-color: #fff;
}

.cloud-circle {
  position: absolute;
  top: 0;
  right: 4rpx;
  height: 18rpx;
  width: 18rpx;
  border-radius: 9rpx;
  background-color: #fff;
}

.cloud-circle.small {
  top: 4rpx;
  left: 2rpx;
  transform: scale(0.8);
}

.middle {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 66rpx;
  height: 66rpx;
  border-radius: 33rpx;
  transform: translate(-50%, -50%);
  overflow: hidden;
  transition: 0.6s all cubic-bezier(0.2, 0.1, 0.1, 0.8);
  box-shadow: 0 0 10rpx rgba(255, 255, 255, 0.5);
}

.crater-box {
  transition: 0.6s;
}

.crater {
  position: absolute;
  width: 28rpx;
  height: 28rpx;
  border-radius: 50%;
  background: linear-gradient(to bottom, #efedf3, #fff);
}

.right {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  right: 0;
  height: 100%;
  width: 86rpx;
  z-index: 1;
  overflow: hidden;
}

.star-box {
  height: 100%;
}

.star {
  position: absolute;
  width: 10rpx;
  height: 10rpx;
  border-radius: 50%;
  background-color: #fff;
  transition: 0.2s;
}

.star1 {
  width: 2rpx;
  height: 2rpx;
}

.star2 {
  width: 4rpx;
  height: 4rpx;
}

.star3 {
  width: 3rpx;
  height: 3rpx;
}

.star4 {
  width: 5rpx;
  height: 5rpx;
}

.star5 {
  width: 3rpx;
  height: 3rpx;
}

.star6 {
  width: 3rpx;
  height: 3rpx;
}

.twinkle {
  animation: twinkle 2s infinite ease-in-out;
}

@keyframes dawn {
  0%,
  100% {
    background-color: #fff;
  }
  80% {
    background-color: #e2fdff;
  }
  90% {
    background-color: #edffff;
  }
}

@keyframes twinkle {
  0%,
  100% {
    transform: scale(1);
  }
  20% {
    transform: scale(1.2);
  }
  40% {
    transform: scale(1.4);
  }
  60% {
    transform: scale(1.2);
  }
  80% {
    transform: scale(1.1);
  }
}

switch.js

Component({
  properties: {
    // 开关缩放倍数 (0.5-2)
    size: {
      type: [Number, String],
      value: 1
    },
    // 通过value双向绑定的值
    value: {
      type: Boolean,
      value: false
    },
    // 打开选择器时的值
    activeValue: {
      type: [Number, String, Boolean],
      value: true
    },
    // 关闭选择器时的值
    inactiveValue: {
      type: [Number, String, Boolean],
      value: false
    }
  },

  data: {
    cloudList: [
      {
        id: 1,
        top: 30,
        left: 12,
        scale: 0.8,
        transition: 0.2
      },
      {
        id: 2,
        top: 8,
        left: 40,
        scale: 0.4,
        transition: 0.4
      },
      {
        id: 3,
        top: 46,
        left: 50,
        scale: 0.6,
        transition: 0.8
      }
    ],
    starList: [
      {
        id: 1,
        top: 24,
        left: 12,
        delay: 0.2,
        transition: 0.2
      },
      {
        id: 2,
        top: 26,
        left: 24,
        delay: 0.5,
        transition: 0.4
      },
      {
        id: 3,
        top: 42,
        left: 28,
        delay: 0.3,
        transition: 0.8
      },
      {
        id: 4,
        top: 54,
        left: 38,
        delay: 0.7,
        transition: 0.8
      },
      {
        id: 5,
        top: 32,
        left: 46,
        delay: 0.8,
        transition: 0.8
      },
      {
        id: 6,
        top: 46,
        left: 50,
        delay: 0.6,
        transition: 0.8
      }
    ],
    craterList: [
      {
        id: 1,
        top: 6,
        left: 28,
        scale: 0.3,
        opacity: 0.6
      },
      {
        id: 2,
        top: 12,
        left: 10,
        scale: 0.4,
        opacity: 0.8
      },
      {
        id: 3,
        top: 24,
        left: 32,
        scale: 0.6,
        opacity: 1
      },
      {
        id: 4,
        top: 28,
        left: 10,
        scale: 0.2,
        opacity: 0.4
      }
    ]
  },

  methods: {
    onClick() {
      const newValue = !this.data.value;
      this.setData({
        value: newValue
      });
      this.triggerEvent('input', newValue);
      this.triggerEvent('change', newValue ? this.data.activeValue : this.data.inactiveValue);
      console.log(newValue)
    }
  }
});

switch.json

{
  "component": true,
  "usingComponents": {}
}

引入组件

  "usingComponents": {
    "v-switch": "/components/switch/switch"
  },

使用组件

<v-switch value="{{switchValue}}" size="0.7" active-value="1" inactive-value="0" bind:change="onChangeChecked" bind:input="onChangeCheckedInput"></v-switch>

uniapp版参考原作者:https://ext.dcloud.net.cn/plugin?id=3469