uni-app 一些实用的页面模板

时间倒计时

<!-- 时间倒计时 -->
<template>
  <view class="container">
    <view class="flex-row time-box">
      <view class="time-item">{{ laveTimeList[0] }}</view>
      <text>天</text>
      <view class="time-item">{{ laveTimeList[1] }}</view>
      <text>时</text>
      <view class="time-item">{{ laveTimeList[2] }}</view>
      <text>分</text>
      <view class="time-item">{{ laveTimeList[3] }}</view>
      <text>秒</text>
    </view>
    <view class="flex-row time-box">
      <view class="flex-row">
        <block v-for="(item, i) in laveTimeDateList[0]" :key="i">
          <view class="time-item date-item">{{ item }}</view>
        </block>
        <text>天</text>
      </view>
      <view class="flex-row">
        <block v-for="(item, i) in laveTimeDateList[1]" :key="i">
          <view class="time-item date-item">{{ item }}</view>
        </block>
        <text>时</text>
      </view>
      <view class="flex-row">
        <block v-for="(item, i) in laveTimeDateList[2]" :key="i">
          <view class="time-item date-item">{{ item }}</view>
        </block>
        <text>分</text>
      </view>
      <view class="flex-row">
        <block v-for="(item, i) in laveTimeDateList[3]" :key="i">
          <view class="time-item date-item">{{ item }}</view>
        </block>
        <text>秒</text>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      laveTimeList: [], // 剩余时间(天-时-分-秒)
      laveTimeDateList: [], // 在拆分
      timer: "" // 定时器
    };
  },
  onLoad() {
    this.getLeftTime("2023/10/25 14:52:00");
  },
  onUnload() {
    if (this.timer) clearInterval(this.timer);
  },
  methods: {
    /* 计算剩余时间 */
    getLeftTime(e) {
      let timeLeft = this.getTimestap(e); // 获取时间戳
      this.initDate(timeLeft); // 初始化数据
      this.timer = setInterval(() => {
        this.initDate(timeLeft); // 初始化数据
        if (timeLeft-- === 0) clearInterval(this.timer); // 清除定时
      }, 1000);
    },
    /* 初始化数据 */
    initDate(e) {
      const period = this.formateSeconds(e); // 天-时-分-秒
      this.laveTimeList = period; // 剩余时间(天-时-分-秒)
      this.laveTimeDateList = this.formatDate(JSON.stringify(period)); // 格式化日期
    },
    /* 天-时-分-秒 */
    formateSeconds(e) {
      const time = [],
        day = parseInt(e / 86400),
        hour = parseInt((e % 86400) / 3600),
        min = parseInt(((e % 86400) % 3600) / 60),
        sec = parseInt(((e % 86400) % 3600) % 60);
      time[0] = day > 0 ? this.addZero(day) : this.addZero(0);
      time[1] = hour > 0 ? this.addZero(hour) : this.addZero(0);
      time[2] = min > 0 ? this.addZero(min) : this.addZero(0);
      time[3] = sec > 0 ? this.addZero(sec) : this.addZero(0);
      return time;
    },
    /* 数字前面补零 */
    addZero(num) {
      return num < 10 ? "0" + num : num;
    },
    /* 获取时间戳 */
    getTimestap(e) {
      const curTime = parseInt(new Date().getTime() / 1000); // 当前时间
      const futureTime = parseInt(new Date(e.replace(/-/g, "/")).getTime() / 1000); // 指定时间
      return futureTime <= curTime ? 0 : futureTime - curTime;
    },
    /* 格式化日期 */
    formatDate(e) {
      const list = JSON.parse(e);
      for (let i = 0; i < list.length; i++) {
        list[i] = list[i].toString().split("");
      }
      return list;
    }
  }
};
</script>

<style lang="scss" scoped>
.container {
  .flex-row {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: row;
  }
  .time-box {
    color: #eaa81b;
    font-size: 26rpx;
    margin: 20rpx;
    padding: 40rpx 20rpx;
    background: #fff;
    border-radius: 20rpx;
  }
  .time-item {
    width: 60rpx;
    text-align: center;
    height: 40rpx;
    line-height: 40rpx;
    font-size: 24rpx;
    margin: 0 20rpx;
    background: linear-gradient(90deg, #ffebb1 0%, #ffdb8f 100%);
    border-radius: 4rpx;
  }
  .date-item {
    width: 30rpx;
    margin: 0 10rpx;
  }
}
</style>

canvas 图形验证码

<!-- canvas 图形验证码 -->
<template>
  <view class="container">
    <view class="canvas-box"><canvas type="2d" id="canvasCode" @click="drawPic" /></view>
    <view class="text-tip">验证码:{{ curCode }}</view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      width: 100, // 宽度
      height: 50, // 高度
      fontSize: 25, // 字体大小
      fontFamily: "SimHei", // 字体
      count: 4, // 验证码位数
      curCode: "", // 当前验证码
      jamPointNum: 40, // 干扰点数
      jamLineNum: 10 // 干扰线数
    };
  },
  onLoad() {
    this.drawPic(); // 绘制验证码图片
  },
  methods: {
    /* 绘制验证码图片 */
    drawPic() {
      uni
        .createSelectorQuery()
        .select("#canvasCode")
        .fields({ node: true, size: true })
        .exec(res => {
          const canvasObj = res[0].node;
          const ctx = canvasObj.getContext("2d");
          // 清除画布
          ctx.fillStyle = "rgb(255, 255, 255)";
          ctx.fillRect(0, 0, 91, 36);
          // 绘制背景色
          ctx.fillStyle = this.randomColor(180, 240); // 颜色若太深可能导致看不清
          ctx.fillRect(0, 0, this.width, this.height);
          // 绘制文字
          const str = "ABCEFGHJKLMNPQRSTWXY123456789";
          let codeTemp = "";
          for (let i = 0; i < this.count; i++) {
            const txt = str[this.randomNum(0, str.length)];
            codeTemp += txt;
            ctx.fillStyle = this.randomColor(50, 160); // 随机生成字体颜色
            ctx.font = this.randomNum(this.fontSize, this.fontSize + 6) + "px " + this.fontFamily; // 随机生成字体大小
            const x = 10 + i * 20;
            const y = this.randomNum(25, 30);
            const deg = this.randomNum(-30, 30);
            // 修改坐标原点和旋转角度
            ctx.translate(x, y);
            ctx.rotate((deg * Math.PI) / 180);
            ctx.fillText(txt, 5, 0);
            // 恢复坐标原点和旋转角度
            ctx.rotate((-deg * Math.PI) / 180);
            ctx.translate(-x, -y);
          }
          this.curCode = codeTemp;
          // 绘制干扰线
          for (let i = 0; i < this.jamLineNum; i++) {
            ctx.strokeStyle = this.randomColor(40, 180);
            ctx.beginPath();
            ctx.moveTo(this.randomNum(0, this.width), this.randomNum(0, this.height));
            ctx.lineTo(this.randomNum(0, this.width), this.randomNum(0, this.height));
            ctx.stroke();
          }
          // 绘制干扰点
          for (let i = 0; i < this.jamPointNum; i++) {
            ctx.fillStyle = this.randomColor(0, 255);
            ctx.beginPath();
            ctx.arc(this.randomNum(0, this.width), this.randomNum(0, this.height), 1, 0, 2 * Math.PI);
            ctx.fill();
          }
        });
    },
    randomNum(min, max) {
      // 生成一个随机数
      return Math.floor(Math.random() * (max - min) + min);
    },
    randomColor(min, max) {
      // 生成一个随机色
      const red = this.randomNum(min, max); // 红色
      const green = this.randomNum(min, max); // 绿色
      const blue = this.randomNum(min, max); // 蓝色
      return `rgb(${red}, ${green}, ${blue})`;
    }
  }
};
</script>

<style lang="scss" scoped>
.container {
  .canvas-box {
    width: 200rpx;
    height: 100rpx;
    margin: 200rpx auto;
  }
  .text-tip {
    width: 80%;
    text-align: center;
    color: #333;
    font-size: 28rpx;
    margin: 80rpx auto;
  }
}
</style>

圆角灯笼

<!-- 圆角灯笼 -->
<template>
  <view class="container">
    <!-- 灯笼-内 -->
    <view class="cont-box">
      <view class="lantern-box">
        <view class="line-tip"></view>
        <view class="outer-bg">
          <view class="inner-bg"><view class="text-tip">福</view></view>
        </view>
        <view class="spike-box">
          <view class="spike-tip"></view>
          <view class="dots-tip"></view>
        </view>
      </view>
    </view>
    <!-- 灯笼-外 -->
    <view class="cont-box cont-outer-box">
      <view class="lantern-box">
        <view class="line-tip"></view>
        <view class="outer-bg">
          <view class="inner-bg"><view class="text-tip">幸</view></view>
        </view>
        <view class="spike-box">
          <view class="spike-tip"></view>
          <view class="dots-tip"></view>
        </view>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {};
  },
  onLoad() {},
  methods: {}
};
</script>

<style lang="scss" scoped>
.container {
  .cont-box {
    position: fixed;
    top: -80rpx;
    right: -40rpx;
    z-index: 999;
    .lantern-box {
      position: relative;
      width: 240rpx;
      height: 180rpx;
      background: rgba(216, 0, 15, 0.8);
      margin: 100rpx;
      transform-origin: 50% -200rpx;
      -webkit-transform-origin: 50% -200rpx;
      animation: swing 3s infinite ease-in-out;
      -webkit-animation: swing 3s infinite ease-in-out;
      box-shadow: -10rpx 10rpx 100rpx 8rpx rgba(250, 108, 0, 1);
      border-radius: 50% 50%;
    }
    .lantern-box::before {
      content: " ";
      position: absolute;
      top: -14rpx;
      left: 58rpx;
      display: block;
      width: 120rpx;
      height: 24rpx;
      background: linear-gradient(to right, #dc8f03, #ffa500, #dc8f03, #ffa500, #dc8f03);
      border: solid 2rpx #dc8f03;
      border-radius: 10rpx 10rpx 0 0;
      z-index: 999;
    }
    .lantern-box::after {
      content: " ";
      position: absolute;
      bottom: -14rpx;
      left: 20rpx;
      display: block;
      width: 120rpx;
      height: 24rpx;
      margin-left: 40rpx;
      background: linear-gradient(to right, #dc8f03, #ffa500, #dc8f03, #ffa500, #dc8f03);
      border: solid 2rpx #dc8f03;
      border-radius: 0 0 10rpx 10rpx;
    }
    .line-tip {
      position: absolute;
      top: -40rpx;
      left: 120rpx;
      width: 4rpx;
      height: 40rpx;
      background: #dc8f03;
    }
    .outer-bg {
      width: 200rpx;
      height: 180rpx;
      background: rgba(216, 0, 15, 0.1);
      margin: 24rpx 16rpx 16rpx 16rpx;
      border: 4rpx solid #dc8f03;
      border-radius: 50% 50%;
      .inner-bg {
        width: 90rpx;
        height: 180rpx;
        background: rgba(216, 0, 15, 0.1);
        margin: -8rpx 16rpx 16rpx 52rpx;
        border: 4rpx solid #dc8f03;
        border-radius: 50% 50%;
        .text-tip {
          text-align: center;
          line-height: 170rpx;
          color: #dc8f03;
          font-size: 3.1rem;
          font-family: 华文行楷, Arial, Lucida Grande, Tahoma, sans-serif;
          font-weight: bold;
        }
      }
    }
    .spike-box {
      position: relative;
      width: 10rpx;
      height: 40rpx;
      background: #ffa500;
      margin: -10rpx 0 0 118rpx;
      transform-origin: 50% -90rpx;
      -webkit-transform-origin: 50% -90rpx;
      animation: swing 4s infinite ease-in-out;
      -webkit-animation: swing 4s infinite ease-in-out;
      border-radius: 0 0 10rpx 10rpx;
      .dots-tip {
        position: absolute;
        top: 28rpx;
        left: -4rpx;
        width: 20rpx;
        height: 20rpx;
        background: #dc8f03;
        border-radius: 50%;
      }
      .spike-tip {
        position: absolute;
        top: 36rpx;
        left: -4rpx;
        width: 20rpx;
        height: 70rpx;
        background: #ffa500;
        border-radius: 0 0 0 10rpx;
      }
    }
  }
  .cont-outer-box {
    top: -60rpx;
    right: 20rpx;
    .lantern-box {
      animation: swing 5s infinite ease-in-out;
      -webkit-animation: swing 5s infinite ease-in-out;
      box-shadow: -10rpx 10rpx 60rpx 8rpx rgba(252, 144, 61, 1);
    }
  }
  @keyframes swing {
    0% {
      -webkit-transform: rotate(-10deg);
    }
    50% {
      -webkit-transform: rotate(10deg);
    }
    100% {
      -webkit-transform: rotate(-10deg);
    }
  }
  @-webkit-keyframes swing {
    0% {
      -webkit-transform: rotate(-10deg);
    }
    50% {
      -webkit-transform: rotate(10deg);
    }
    100% {
      -webkit-transform: rotate(-10deg);
    }
  }
}
</style>

<style>
page {
  background-color: #222;
}
</style>

自定义顶部导航栏

<!-- 自定义顶部导航栏 -->
<template>
  <view class="container" :style="'padding-top: ' + navHeight + 'rpx'">
    <view class="head-back">
      <image src="/static/return.png" mode="aspectFill" @click="toBack" />
      <image src="/static/home.png" mode="aspectFill" @click="toHome" />
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      statusBarHeight: 0, // 状态导航栏高度
      navigationBarHeight: 0, // 导航栏高度(标题栏高度)
      navHeight: 0 // 总体高度
    };
  },
  onLoad() {
    /** 状态栏高度 */
    this.statusBarHeight = wx.getSystemInfoSync().statusBarHeight;
    /** 获取微信胶囊的位置信息 width,height,top,right,left,bottom */
    const custom = wx.getMenuButtonBoundingClientRect();
    /** 导航栏高度(标题栏高度) = 胶囊高度 + (顶部距离 - 状态栏高度) * 2 */
    this.navigationBarHeight = custom.height + (custom.top - this.statusBarHeight) * 2;
    /** 总体高度 = 状态栏高度 + 导航栏高度 */
    this.navHeight = this.navigationBarHeight + this.statusBarHeight;
  },
  methods: {
    /* 返回 */
    toBack() {
      console.log("返回");
    },
    /* 回到首页 */
    toHome() {
      console.log("回到首页");
    }
  }
};
</script>

<style lang="scss" scoped>
.container {
  padding-bottom: 25rpx;
  background-color: rgba(0, 0, 0, 0.7);
  .head-back {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 180rpx;
    height: 60rpx;
    padding: 0 20rpx;
    margin-left: 25rpx;
    border: 1rpx solid rgba(204, 204, 204, 0.6);
    box-sizing: border-box;
    border-radius: 50rpx;
    image {
      width: 40rpx;
      height: 40rpx;
    }
  }
  .head-back::after {
    content: "";
    position: absolute;
    top: 10%;
    left: calc(50% - 1rpx);
    width: 2rpx;
    height: 80%;
    background: #fff;
  }
}
</style>

滚动自动吸顶

<!-- 滚动自动吸顶 -->
<template>
  <view class="container">
    <view class="head-box">头部内容区域</view>
    <view class="nav-box" :class="isFixed ? 'fix-tip' : ''" id="navBox">
      <view class="nav-item" :class="{ 'active-tip': curNav === i }" v-for="(item, i) in navList" :key="i" @click="navToggle(i)">
        {{ item }}
      </view>
    </view>
    <view :class="isFixed ? 'p-t-nav' : ''" id="contBox">
      <view class="cont-item" v-for="(item, i) in curNav * 10 + 5" :key="i">{{ item }}</view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      isFixed: false, // 是否吸顶
      navTop: 0, // 导航栏到顶部的距离
      curNav: 0, // 当前导航栏
      navList: ["未开始", "进行中", "已结束"]
    };
  },
  onReady() {
    // 获取节点距离顶部的距离
    uni
      .createSelectorQuery()
      .select("#navBox")
      .boundingClientRect(rect => {
        if (rect && rect.top) this.navTop = parseInt(rect.top);
      })
      .exec();
  },
  /* 监听页面滚动事件 */
  onPageScroll(e) {
    this.isFixed = parseInt(e.scrollTop) >= this.navTop;
  },
  methods: {
    /* 导航栏切换 */
    navToggle(i) {
      if (this.curNav == i) return;
      this.curNav = i;
      if (this.isFixed) uni.pageScrollTo({ selector: "#contBox", duration: 0.5 }); // duration.滚动到指定位置需要的时间
    }
  }
};
</script>

<style lang="scss" scoped>
.container {
  $navHeight: 88rpx; // nav导航栏高度
  .head-box {
    width: 100%;
    height: 300rpx;
    color: #fff;
    font-size: 26rpx;
    padding: 30rpx;
    background: linear-gradient(90deg, #f54ea2, #ff7676);
    box-sizing: border-box;
  }
  .nav-box {
    position: relative;
    display: flex;
    width: 100%;
    height: $navHeight;
    line-height: $navHeight;
    background: #fff;
    box-shadow: 0 5rpx 5rpx #ccc;
    .nav-item {
      position: relative;
      flex: 1;
      text-align: center;
      color: #333;
      font-size: 28rpx;
    }
    .nav-item::after {
      content: "";
      position: absolute;
      left: 50%;
      transform: translateX(-50%);
      bottom: 4rpx;
      width: 0;
      height: 6rpx;
      background: linear-gradient(90deg, #f54ea2, #ff7676);
      transition: 0.3s width linear;
      border-radius: 3rpx;
    }
    .active-tip {
      color: transparent;
      font-size: 30rpx;
      background-clip: text;
      -webkit-background-clip: text;
      background-image: linear-gradient(90deg, #f54ea2, #ff7676);
      transition: 0.3s all linear;
      transition-delay: 0.1s;
      font-weight: 900;
    }
    .active-tip::after {
      width: 40%;
    }
  }
  .fix-tip {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 99;
  }
  .p-t-nav {
    padding-top: $navHeight;
  }
  .cont-item {
    text-align: center;
    height: 50rpx;
    line-height: 50rpx;
    color: #999;
    padding: 20rpx;
    background: #fff;
    border-bottom: 1rpx solid #eaeef1;
  }
}
</style>

swiper 消息滚动

<!-- swiper 消息滚动 -->
<template>
  <view>
    <!-- 展示一条数据 -->
    <template>
      <view class="tit-box">
        <view class="tit-tip">展示一条数据</view>
      </view>
      <view class="scroll-notice">
        <image class="horn-tip" src="https://img1.baidu.com/it/u=3874629958,3395061015&fm=253" />
        <swiper
          class="notice-box"
          vertical
          autoplay
          circular
          interval="4000"
          duration="1500"
          display-multiple-items="1"
          easing-function="easeInOutCubic"
        >
          <swiper-item v-for="(item, i) in swiperList" :key="i">
            <view class="item-box">
              <view>{{ item.bonusTime }}</view>
              <view class="name-tip">抽中了 {{ item.awardName }}</view>
            </view>
          </swiper-item>
        </swiper>
        <image class="arrow-tip" src="https://img0.baidu.com/it/u=1153718811,3800194060&fm=253" />
      </view>
    </template>
    <!-- 展示两条数据 -->
    <template>
      <view class="tit-box">
        <view class="tit-tip">展示两条数据</view>
      </view>
      <view class="fix-two-box">
        <view class="title-box">
          <view class="line-tip"></view>
          <view class="title-tip">展示两条数据</view>
          <view class="line-tip"></view>
        </view>
        <swiper class="fix-swiper" vertical autoplay circular interval="3000" display-multiple-items="2">
          <swiper-item v-for="(item, i) in dataList" :key="i">
            <view class="item-box">
              <view>{{ item.bonusTime }}</view>
              <view class="name-tip">抽中了 {{ item.awardName }}</view>
            </view>
          </swiper-item>
        </swiper>
      </view>
    </template>
    <!-- 高度随数据长度而变化 -->
    <template>
      <view class="tit-box">
        <view class="tit-tip">高度随数据长度而变化</view>
        <view class="btn-tip" :class="{ 'is-sel': curLen === 3 }" @click="toSwitchLen(3)">3条</view>
        <view class="btn-tip" :class="{ 'is-sel': curLen === 6 }" @click="toSwitchLen(6)">6条</view>
        <view class="btn-tip" :class="{ 'is-sel': curLen === 'all' }" @click="toSwitchLen('all')">全部</view>
      </view>
      <view class="vary-swiper">
        <swiper
          vertical
          autoplay
          circular
          interval="3000"
          :style="'height: ' + (swiperList.length > 6 ? 460 : swiperList.length * 60) + 'rpx'"
          :display-multiple-items="swiperList.length > 6 ? 7 : swiperList.length"
        >
          <swiper-item v-for="(item, i) in swiperList" :key="i">
            <view class="item-box">
              <view>{{ item.bonusTime }}</view>
              <view class="name-tip">抽中了 {{ item.awardName }}</view>
            </view>
          </swiper-item>
        </swiper>
      </view>
    </template>
  </view>
</template>

<script>
export default {
  data() {
    return {
      dataList: [
        { bonusTime: "2023/11/01 10:10", awardName: "iPhone 12 Pro Max" },
        { bonusTime: "2023/11/02 11:15", awardName: "华为Mate 40 Pro" },
        { bonusTime: "2023/11/03 12:20", awardName: "三星Galaxy S21 Ultra" },
        { bonusTime: "2023/11/04 13:25", awardName: "小米11 Ultra" },
        { bonusTime: "2023/11/05 14:30", awardName: "OPPO Find X3 Pro" },
        { bonusTime: "2023/11/06 15:35", awardName: "vivo X60 Pro+" },
        { bonusTime: "2023/11/07 16:40", awardName: "谷歌Pixel 6 Pro" },
        { bonusTime: "2023/11/08 17:45", awardName: "荣耀V40" }
      ], // 数据源
      /* 高度随数据长度而变化 */
      curLen: "",
      swiperList: []
    };
  },
  onLoad() {
    this.toSwitchLen("all"); // 切换数据长度
  },
  methods: {
    /* 切换数据长度 */
    toSwitchLen(e) {
      if (this.curLen === e) return;
      this.curLen = e;
      const rowData = JSON.parse(JSON.stringify(this.dataList));
      if (e === "all") e = rowData.length;
      this.swiperList = rowData.slice(0, e);
    }
  }
};
</script>

<style lang="scss" scoped>
.tit-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 60rpx 30rpx 30rpx;
  .tit-tip {
    font-weight: 900;
  }
  .btn-tip {
    font-size: 24rpx;
    color: #ff6348;
    padding: 5rpx 20rpx;
    border: 1px solid #ff7f50;
    border-radius: 15rpx;
  }
  .is-sel {
    color: #fff;
    background: #ff6348;
  }
}
/* 展示一条数据 */
.scroll-notice {
  $noticeHeight: 66rpx;
  display: flex;
  align-items: center;
  flex-direction: row;
  height: $noticeHeight;
  line-height: $noticeHeight;
  padding: 0 24rpx;
  margin: 30rpx;
  background: #fdf6ec;
  border-radius: 12rpx;
  // 小喇叭
  .horn-tip {
    flex-shrink: 0;
    width: 34rpx;
    height: 28rpx;
    margin-right: 10rpx;
  }
  .notice-box {
    flex: 1;
    height: $noticeHeight;
    .item-box {
      display: flex;
      align-items: center;
      font-size: 26rpx;
      .name-tip {
        color: #ff9900;
        margin-left: 6rpx;
      }
    }
  }
  // 向右箭头
  .arrow-tip {
    flex-shrink: 0;
    width: 22rpx;
    height: 22rpx;
  }
}
/* 展示两条数据 */
.fix-two-box {
  margin: 30rpx;
  border: 1px solid #2979ff;
  border-radius: 30rpx;
  .title-box {
    $bgColor: #2979ff; // 字体、线条颜色
    $lineWidth: 140; // 线条长度
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 30rpx;
    .line-tip {
      position: relative;
      width: $lineWidth + rpx;
      height: 1rpx;
      background: $bgColor;
    }
    .line-tip::before {
      content: "";
      position: absolute;
      bottom: -7rpx;
      width: $lineWidth / 3 + 10 + rpx;
      height: 1rpx;
      background: $bgColor;
    }
    .line-tip:nth-child(1)::before {
      right: 0;
    }
    .title-tip {
      color: $bgColor;
      font-size: 36rpx;
      margin: 0 20rpx;
      font-weight: 900;
    }
  }
  .fix-swiper {
    height: 150rpx;
    font-size: 28rpx;
    margin-top: 30rpx;
    .item-box {
      display: flex;
      align-items: center;
      justify-content: space-between;
      font-size: 26rpx;
      padding: 10rpx 30rpx;
      .name-tip {
        color: #2979ff;
      }
    }
  }
}
/* 高度随数据长度而变化 */
.vary-swiper {
  margin: 30rpx;
  box-sizing: border-box;
  border-radius: 30rpx;
  border: 1px solid #ff7f50;
  .item-box {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 26rpx;
    padding: 10rpx 30rpx;
    .name-tip {
      color: #ff6348;
    }
  }
}
</style>

swiper 商品滑动

<!-- swiper 商品滑动 -->
<template>
  <view>
    <!-- 一次滑动三条 -->
    <view class="container">
      <view class="tit_box">
        <view class="tit-tip">精选商品</view>
      </view>
      <view class="cont-box">
        <swiper class="swiper-box" :indicator-dots="false" autoplay interval="5000" duration="1000" circular>
          <swiper-item v-for="(row, i) in goodsList" :key="i">
            <view class="item-box" v-for="(item, j) in row.list" :key="j">
              <image class="img-tip" :src="item.img" mode="aspectFill" />
              <view class="name-tip">商品{{ j }}</view>
            </view>
          </swiper-item>
        </swiper>
      </view>
    </view>
    <!-- 一次滑动一条 -->
    <view class="container">
      <view class="tit_box">
        <view class="tit-tip">精选商品</view>
      </view>
      <view class="cont-box">
        <swiper
          class="swiper-box"
          :indicator-dots="false"
          autoplay
          interval="1500"
          duration="1000"
          circular
          :display-multiple-items="recordList.length > 2 ? 3 : recordList.length"
        >
          <swiper-item v-for="(item, i) in recordList" :key="i">
            <view class="item-box" style="width: 100%">
              <image class="img-tip" :src="item.img" mode="aspectFill" />
              <view class="name-tip">商品{{ i }}</view>
            </view>
          </swiper-item>
        </swiper>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  data() {
    return {
      goodsList: [
        {
          list: [
            { img: "https://images.pexels.com/photos/1660030/pexels-photo-1660030.jpeg" },
            { img: "https://images.pexels.com/photos/1640774/pexels-photo-1640774.jpeg" },
            { img: "https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg" }
          ]
        },
        {
          list: [
            { img: "https://images.pexels.com/photos/70497/pexels-photo-70497.jpeg" },
            { img: "https://images.pexels.com/photos/7441761/pexels-photo-7441761.jpeg" },
            { img: "https://images.pexels.com/photos/842571/pexels-photo-842571.jpeg" }
          ]
        },
        {
          list: [
            { img: "https://images.pexels.com/photos/17216084/pexels-photo-17216084.jpeg" },
            { img: "https://images.pexels.com/photos/8969237/pexels-photo-8969237.jpeg" },
            { img: "https://images.pexels.com/photos/1099680/pexels-photo-1099680.jpeg" }
          ]
        }
      ],
      recordList: [
        { img: "https://images.pexels.com/photos/1660030/pexels-photo-1660030.jpeg" },
        { img: "https://images.pexels.com/photos/1640774/pexels-photo-1640774.jpeg" },
        { img: "https://images.pexels.com/photos/699953/pexels-photo-699953.jpeg" },
        { img: "https://images.pexels.com/photos/70497/pexels-photo-70497.jpeg" },
        { img: "https://images.pexels.com/photos/7441761/pexels-photo-7441761.jpeg" },
        { img: "https://images.pexels.com/photos/842571/pexels-photo-842571.jpeg" },
        { img: "https://images.pexels.com/photos/17216084/pexels-photo-17216084.jpeg" }
      ]
    };
  },
  onLoad() {},
  methods: {}
};
</script>

<style lang="scss" scoped>
.container {
  position: relative;
  height: 228rpx;
  margin: 20rpx;
  background: #ff4757;
  border-radius: 20rpx;
  overflow: hidden;
  .tit_box {
    width: 110rpx;
    text-align: center;
    height: 100%;
    background: #ff6b81;
    .tit-tip {
      display: inline-block;
      color: #fff;
      width: 50rpx;
      text-align: center;
      vertical-align: middle;
      font-size: 30rpx;
      white-space: pre-wrap;
      font-weight: 900;
    }
  }
  .tit_box::after {
    content: "";
    display: inline-block;
    height: 100%;
    vertical-align: middle;
  }
  .cont-box {
    position: absolute;
    top: 20rpx;
    left: 108rpx;
    width: 84%;
    white-space: nowrap;
    overflow-y: auto;
    box-sizing: border-box;
    .swiper-box {
      height: 192rpx;
      overflow: hidden;
      .item-box {
        float: left;
        width: calc(100% / 3);
        height: 192rpx;
        text-align: center;
        .img-tip {
          display: block;
          width: 145rpx;
          height: 154rpx;
          margin: 0 auto 9rpx;
          border-radius: 16rpx;
        }
        .name-tip {
          text-align: center;
          height: 30rpx;
          line-height: 30rpx;
          color: #fff;
          font-size: 22rpx;
        }
      }
    }
  }
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/242236.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kubernetes实战(十四)-k8s集群扩容master节点

1 Master 高可用架构 Kubernetes 作为容器集群系统&#xff0c;通过健康检查 重启策略实现了 Pod 故障自我修复能力&#xff0c;通过调度算法实现将 Pod 分布式部署&#xff0c;并保持预期副本数&#xff0c;根据 Node 失效状态自动在其他 Node 拉起 Pod&#xff0c;实现了应…

【初阶C++】入门(超详解)

C入门 前言1. C关键字(C98)2. 命名空间2.1 命名空间定义2.2 命名空间使用2.3嵌套命名空间 3. C输入&输出4. 缺省参数4.1 缺省参数概念4.2 缺省参数分类 5. 函数重载5.1 函数重载概念5.2 C支持函数重载的原理--名字修饰(name Mangling) 6. 引用6.1 引用概念6.2 引用特性6.3 …

最新版ES8的client API操作 Elasticsearch Java API client 8.0

作者&#xff1a;ChenZhen 本人不常看网站消息&#xff0c;有问题通过下面的方式联系&#xff1a; 邮箱&#xff1a;1583296383qq.comvx: ChenZhen_7 我的个人博客地址&#xff1a;https://www.chenzhen.space/&#x1f310; 版权&#xff1a;本文为博主的原创文章&#xff…

多丽特膳:个性化的调减饮品,让你的蜕变之路更轻松

不同的人有不同的体型和健康状态&#xff0c;在我们的生活中存在九种体质&#xff0c;它们分别是平和质、气虚质、阳虚质、阴虚质、痰湿质、湿热质、血瘀质、气郁质、特禀质。体质是指人类个体在形态结构和生理功能方面的相对稳定的特征&#xff0c;它反映了人类个体之间的差异…

【源码解析】flink sql执行源码概述:flink sql执行过程中有哪些阶段,这些阶段的源码大概位置在哪里

文章目录 一. sql执行流程源码分析1. Sql语句解析成语法树阶段&#xff08;SQL - > SqlNode&#xff09;2. SqlNode 验证&#xff08;SqlNode – >Operation&#xff09;3. 语义分析&#xff08;Operation - > RelNode&#xff09;4. 优化阶段&#xff08;RelNode - &…

【活动回顾】ABeam News | 兰州大学外国语学院回访ABeam 旗下德硕管理咨询(上海),持续推进远景合作

访企拓岗深入调研 持续推进远景合作 继11月上旬ABeam旗下艾宾信息技术开发&#xff08;西安&#xff09;团队一行拜访兰州大学并举行隆重的校企签约仪式后&#xff0c;近日兰州大学一行领导也如约莅临德硕管理咨询&#xff08;上海&#xff09;有限公司开展拓岗调研。 深化…

基于FPGA的视频接口之高速IO(SATA)

简介 本章节是对于高速IO接口应用的一个扩展,目前扩展为SATA(SSD硬盘,机械硬盘不能使用)。通俗易懂的讲,即把SSD硬盘当做大型的Nand Flash来处理,不格式化硬盘,直接以地址和数据的格式,在SATA盘中写入数据,该数据不能被Window和linux直接识别,需单独编写App来查看SSD…

Python 小程序之PDF文档加解密

PDF文档的加密和解密 文章目录 PDF文档的加密和解密前言一、总体构思二、使用到的库三、PDF文档的加密1.用户输入模块2.打开并读取文档数据3.遍历保存数据到新文档4.新文档进行加密5.新文档命名生成路径6.保存新加密的文档 四、PDF文档的解密1.用户输入模块2.前提准备2.文件解密…

【C++11】右值引用与移动语义

一.左值与右值 左值&#xff1a;可以取地址的表示数据的表达式&#xff0c;左值可以出现在赋值符号左边 右值&#xff1a;不能取地址的表示数据的表达式&#xff0c;右值不能出现在赋值符号左边 int fun() {return 0; } int main() {int a 0;//a->左值const int b 1;//b-&…

粒子群优化算法的实践 - 多个约束条件

粒子群优化算法的实践 - 多个约束条件 flyfish 粒子群优化算法的实践 - 目标函数的可视化 粒子群优化算法的实践 - 向量减法 在粒子群优化算法的代码实践中 代码写法是 #非线性约束 (x[0] - 1) ** 2 (x[1] - 1) ** 2 - 1<0 constraint_ueq (lambda x: (x[0] - 1) ** 2…

【期末考复习向】transformer的运作机制

1.transformer的encoder运作 transformer的encoder部分包括了输入和处理2大部分。首先是输入部分inputs&#xff0c;这里初始的inputs是采用独热向量进行表示的&#xff0c;随后经过word2vec等操作把独热向量&#xff08;采用独热向量的好处就是可向量是正交的&#xff0c;可以…

Centos7部署SVN

文章目录 &#xff08;1&#xff09;SVN概述&#xff08;2&#xff09;SVN与Samba共享&#xff08;3&#xff09;安装SVN&#xff08;4&#xff09;SVN搭建实例&#xff08;5&#xff09;pc连接svn服务器&#xff08;6&#xff09;svn图标所代表含义 &#xff08;1&#xff09;…

【大数据】详解 AVRO 格式

详解 AVRO 格式 1.Avro 介绍2.schema2.1 原始类型2.2 复杂类型2.2.1 Records2.2.2 Enums2.2.3 Arrays2.2.4 Maps2.2.5 Unions2.2.6 Fixed 3.Avro 的文件存储格式3.1 数据编码3.1.1 原始类型3.1.2 复杂类型 3.2 存储格式3.3 存储格式 4.小结 1.Avro 介绍 Apache Avro 是 Hadoop…

【rabbitMQ】声明队列和交换机

上一篇&#xff1a;springboot整合rabbitMQ模拟简单收发消息 https://blog.csdn.net/m0_67930426/article/details/134904766?spm1001.2014.3001.5501 相关配置环境参考上篇 springAMQP提供了几个类用来声明声明队列&#xff0c;交换机及其绑定关系 声明队列&#xff0c;…

经典策略筛选-20231213

策略1&#xff1a; 龙头战法只做最强&#xff1a;国企改革 ----四川金顶 1、十日交易内出现 涨停或 &#xff08;涨幅大于7个点且量比大于3&#xff09; 2、JDK MACD RSI OBV LWR MTM 六指标共振 3、均线多头 4、 筹码峰 &#xff08;锁仓&#xff09; 5、现价> 五日均…

C语言之文件操作(上)

C语言之文件操作&#xff08;上&#xff09; 文章目录 C语言之文件操作&#xff08;上&#xff09;1. 什么是⽂件&#xff1f;1.1 程序⽂件1.2 数据⽂件1.3 ⽂件名 2. ⼆进制⽂件和⽂本⽂件3. ⽂件的打开和关闭3.1 流和标准流3.1.1 流3.1.2 标准流 4. ⽂件指针5. 文件的打开与关…

什么是连接池?如何确认连接池的大小?

对于我们编写的几乎每个网络或移动应用程序来说&#xff0c;其底层的关键组件之一就是数据库。对于编写使用数据库且高性能且资源高效的应用程序&#xff0c;必须处理一项关键资源&#xff0c;但与 CPU、内存等不同&#xff0c;它通常不是很明显。该资源是数据库连接。 什么是…

调用Win10隐藏的语音包

起因 在做一个文本转语音的Demo的时候&#xff0c;遇到了语音包无法正确被Unity识别的问题。明明电脑上安装了语音包但是代码就是识别不出来 原因 具体也不是非常清楚&#xff0c;但是如果语言包是在的话&#xff0c;大概率是Win10系统隐藏了。 确定语言包 首先查看%windi…

VLAN详细学习

文章目录 VLAN概念VLAN种类端口VLAN工作原理以太网的三种链路类型配置 VLAN概念 一种讲局域网设备从逻辑上划分为一个个网段&#xff0c;从而实现虚拟网络的一种技术&#xff0c;这一技术主要应用于交换机中。Vlan技术是技术在以太网帧的基础上增加vlan头&#xff0c;用VLAN I…

云计算大屏,可视化云计算分析平台(云实时数据大屏PSD源文件)

大屏组件可以让UI设计师的工作更加便捷&#xff0c;使其更高效快速的完成设计任务。现分享可视化云分析系统、可视化云计算分析平台、云实时数据大屏的大屏Photoshop源文件&#xff0c;开箱即用&#xff01; 若需 更多行业 相关的大屏&#xff0c;请移步小7的另一篇文章&#…