refactor: 移动端升级 Vue3 + uView Plus

将 lilishop-uniapp 从 Vue2/uView 1.6 迁移到 Vue3/uview-plus,优先支持 H5/微商城与微信小程序;移除 vendored uview-ui,改用 npm 依赖、Vuex4 与迁移脚本/补丁,并补充 VUE3_MIGRATION.md 回归清单。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
pikachu1995@126.com
2026-06-30 18:50:38 +08:00
parent c290c7a329
commit dc2bef455a
299 changed files with 5507 additions and 43811 deletions

View File

@@ -1,6 +1,6 @@
<template>
<div class="wrapper">
<u-popup class="popup" v-model="buyMask" :height="setup.height" closeable :mode="setup.mode" :border-radius="setup.radius" @close="closeMask()">
<u-popup class="popup" :show="buyMask" :height="setup.height" closeable :mode="setup.mode" :border-radius="setup.radius" @close="closeMask()">
<!-- 商品 -->
<view class="goods-box bottom">
<view class="goods-header">
@@ -12,8 +12,8 @@
<view class="goods-price" v-if="goodsDetail.promotionPrice && ((isGroup && buyType === 'PINTUAN') || !isGroup)">
<span v-if="goodsDetail.promotionPrice && !pointDetail">
<span class="goods-price-promotionShow goods-price-bigshow">{{ $options.filters.goodsFormatPrice(goodsDetail.promotionPrice)[0] }}</span>
.{{ $options.filters.goodsFormatPrice(goodsDetail.promotionPrice)[1] }}
<span class="goods-price-promotionShow goods-price-bigshow">{{ goodsFormatPrice(goodsDetail.promotionPrice)[0] }}</span>
.{{ goodsFormatPrice(goodsDetail.promotionPrice)[1] }}
</span>
<span v-if="pointDetail.points">
<span class="goods-price-promotionShow goods-price-bigshow">{{ pointDetail.points }}</span>
@@ -21,8 +21,8 @@
</span>
<div class="promotion-box">
<span class="goods-price-bigshow">{{ $options.filters.goodsFormatPrice(goodsDetail.price)[0] }}</span>
.{{ $options.filters.goodsFormatPrice(goodsDetail.price)[1] }}
<span class="goods-price-bigshow">{{ goodsFormatPrice(goodsDetail.price)[0] }}</span>
.{{ goodsFormatPrice(goodsDetail.price)[1] }}
</div>
</view>
<!-- 正常商品的价格 -->
@@ -32,8 +32,8 @@
<div class="goods-price" v-for="(item, index) in wholesaleList" :key="index">
<span>
<span class="goods-price-bigshow">{{ $options.filters.goodsFormatPrice(item.price)[0] }}</span>
.{{ $options.filters.goodsFormatPrice(item.price)[1] }}
<span class="goods-price-bigshow">{{ goodsFormatPrice(item.price)[0] }}</span>
.{{ goodsFormatPrice(item.price)[1] }}
</span>
<span class="wholesale-item">{{ item.num }}{{ goodsDetail.goodsUnit }}</span>
</div>
@@ -41,8 +41,8 @@
<div class="goods-price" v-else>
<span>
<span class="goods-price-bigshow">{{ $options.filters.goodsFormatPrice(goodsDetail.price)[0] }}</span>
.{{ $options.filters.goodsFormatPrice(goodsDetail.price)[1] }}
<span class="goods-price-bigshow">{{ goodsFormatPrice(goodsDetail.price)[0] }}</span>
.{{ goodsFormatPrice(goodsDetail.price)[1] }}
</span>
</div>
</view>
@@ -81,16 +81,16 @@
</view>
<!-- 拼团购买仅筛选出当前拼团类型商品 -->
<template v-for="(spec_val, spec_index) in spec.values" :key="spec_index">
<view
v-if="parentOrder && spec_val.skuId == goodsDetail.id"
:class="{ active: spec_val.value == currentSelected[specIndex] }"
class="skus-view-item"
v-for="(spec_val, spec_index) in spec.values"
:key="spec_index"
@click="handleClickSpec(spec, specIndex, spec_val)"
>
{{ spec_val.value }}
</view>
</template>
</view>
</view>
<div class="soldout" v-if="goodsDetail.quantity === 0">
@@ -261,7 +261,7 @@ export default {
}
});
if (selectedSkuId?.skuId) {
this.$set(this.currentSelected, index, specValue.value);
this.currentSelected[index] = specValue.value;
this.selectSkuList = {
spec: {
specName: val.name,
@@ -531,11 +531,6 @@ export default {
color: $price-color;
line-height: 80rpx;
margin-right: 20rpx;
> * {
color: $price-color;
line-height: 80rpx;
}
}
.promotion-box {
@@ -565,9 +560,6 @@ export default {
> .goods-check-skus-name {
margin-left: 4rpx;
}
> span {
color: #333;
}
}

View File

@@ -1,7 +1,7 @@
<template>
<div class="index">
<u-modal v-model="show" :show-title="false" :show-confirm-button="false" mask-close-able>
<u-modal v-model:show="show" :show-title="false" :show-confirm-button="false" mask-close-able>
<view class="slot-content">
<image @click="downLoad()" class="img" :src="imgUrl" />
<div class="canvas-hide">

View File

@@ -208,7 +208,7 @@ export default {
this.tabCurrentIndex++;
// 当前距离重新为最上面
this.$set(this,'scrollTop',0)
this['scrollTop'] = 0
}
} catch (error) {
uni.hideLoading();
@@ -391,12 +391,10 @@ export default {
flex-direction: column;
/* #endif */
margin-right: 5px;
margin-left: 40rpx;
vertical-align: middle;
}
.color {
color: $light-color;
}
icon {
margin-left: 40rpx;
}
</style>

View File

@@ -10,7 +10,7 @@
height="330rpx"
mode="aspectFit"
>
<u-loading slot="loading"></u-loading>
<template #loading><u-loading></u-loading></template>
</u-image>
</view>
<view class="goods-detail">
@@ -23,9 +23,9 @@
<div class="price" v-if="item.price != undefined">
¥<span
>{{
$options.filters.goodsFormatPrice(item.price)[0]
goodsFormatPrice(item.price)[0]
}} </span
>.{{ $options.filters.goodsFormatPrice(item.price)[1] }}
>.{{ goodsFormatPrice(item.price)[1] }}
</div>
</view>
<div class="count-config" @click="navigateToDetailPage(item)">
@@ -67,7 +67,7 @@
mode="aspectFit"
:src="item.goodsImage || item.thumbnail"
>
<u-loading slot="loading"></u-loading>
<template #loading><u-loading></u-loading></template>
</u-image>
</div>
<div class="goods-detail">
@@ -77,8 +77,8 @@
<view class="price-box" @click="navigateToDetailPage(item)">
<div class="price" v-if="item.price != undefined">
¥<span
>{{ $options.filters.goodsFormatPrice(item.price)[0] }} </span
>.{{ $options.filters.goodsFormatPrice(item.price)[1] }}
>{{ goodsFormatPrice(item.price)[0] }} </span
>.{{ goodsFormatPrice(item.price)[1] }}
</div>
</view>
<div class="promotion" @click="navigateToDetailPage(item)">

View File

@@ -5,7 +5,7 @@
<view v-for="(item, index) in res" :key="index" class="goods-item">
<view class="image-wrapper" @click="navigateToDetailPage(item)">
<u-image :src="item.thumbnail" width="100%" height='330rpx' mode="aspectFit">
<u-loading slot="loading"></u-loading>
<template #loading><u-loading></u-loading></template>
</u-image>
</view>
<view class="goods-detail">
@@ -15,19 +15,19 @@
</div>
<view class="price-box" @click="navigateToDetailPage(item)">
<div class="price" v-if="item.price!=undefined">
¥<span>{{ $options.filters.goodsFormatPrice(item.price )[0] }} </span>.{{
$options.filters.goodsFormatPrice(item.price )[1]
¥<span class="price-int">{{ goodsFormatPrice(item.price )[0] }} </span>.{{
goodsFormatPrice(item.price )[1]
}}
</div>
</view>
<div class="promotion" @click="navigateToDetailPage(item)">
<div v-if="item.salesModel == 'WHOLESALE'">
<span></span>
<span class="promotion-tag"></span>
</div>
<div v-for="(promotionItem,promotionIndex) in getPromotion(item)" :key="promotionIndex">
<span v-if="promotionItem.indexOf('COUPON') != -1"></span>
<span v-if="promotionItem.indexOf('FULL_DISCOUNT') != -1">满减</span>
<span v-if="promotionItem.indexOf('SECKILL') != -1">秒杀</span>
<span class="promotion-tag" v-if="promotionItem.indexOf('COUPON') != -1"></span>
<span class="promotion-tag" v-if="promotionItem.indexOf('FULL_DISCOUNT') != -1">满减</span>
<span class="promotion-tag" v-if="promotionItem.indexOf('SECKILL') != -1">秒杀</span>
</div>
</div>
<div class="count-config" @click="navigateToDetailPage(item)">
@@ -35,14 +35,12 @@
<span>{{ item.commentNum || "0" }}条评论</span>
</div>
<div class="store-seller-name" v-if="storeName" @click="navigateToStoreDetailPage(item)">
<div class="text-hidden">
<u-tag style="margin-right: 10rpx" size="mini" mode="dark" v-if="item.selfOperated"
text="自营" type="error" />
<span>{{ item.storeName || "暂无" }}</span>
</div>
<span>
<u-icon name="arrow-right"></u-icon>
</span>
<view class="store-name-row">
<text class="self-tag" v-if="item.selfOperated">自营</text>
<text class="store-name-text">{{ item.storeName || "暂无" }}</text>
<text class="to-store">进店</text>
</view>
<u-icon name="arrow-right" size="12" color="#c5c5c5"></u-icon>
</div>
</view>
</view>
@@ -53,43 +51,39 @@
<div class="flex goods-col">
<div class="goods-img" @click="navigateToDetailPage(item)">
<u-image width="230rpx" mode="aspectFit" border-radius='16' height="230rpx" :src="item.thumbnail">
<u-loading slot="loading"></u-loading>
<template #loading><u-loading></u-loading></template>
</u-image>
</div>
<div class="goods-detail">
<div class="title clamp3" @click="navigateToDetailPage(item)">{{ item.goodsName }}</div>
<view class="price-box" @click="navigateToDetailPage(item)">
<div class="price" v-if="item.price!=undefined">
¥<span>{{ $options.filters.goodsFormatPrice(item.price )[0] }} </span>.{{
$options.filters.goodsFormatPrice(item.price )[1]
¥<span class="price-int">{{ goodsFormatPrice(item.price )[0] }} </span>.{{
goodsFormatPrice(item.price )[1]
}}
</div>
</view>
<div class="promotion" @click="navigateToDetailPage(item)">
<div v-if="item.salesModel == 'WHOLESALE'">
<span></span>
<span class="promotion-tag"></span>
</div>
<div v-for="(promotionItem,promotionIndex) in getPromotion(item)" :key="promotionIndex">
<span v-if="promotionItem.indexOf('COUPON') != -1"></span>
<span v-if="promotionItem.indexOf('FULL_DISCOUNT') != -1">满减</span>
<span v-if="promotionItem.indexOf('SECKILL') != -1">秒杀</span>
<span class="promotion-tag" v-if="promotionItem.indexOf('COUPON') != -1"></span>
<span class="promotion-tag" v-if="promotionItem.indexOf('FULL_DISCOUNT') != -1">满减</span>
<span class="promotion-tag" v-if="promotionItem.indexOf('SECKILL') != -1">秒杀</span>
</div>
</div>
<div style="overflow: hidden" @click="navigateToDetailPage(item)" class="count-config">
<span style="float: left; font-size: 22rpx">已售 {{ item.buyCount || '0' }}</span>
<span style="float: right; font-size: 22rpx">{{ item.commentNum || '0' }}条评论</span>
</div>
<div style="overflow: hidden" @click="navigateToStoreDetailPage(item)" class="count-config">
<div class="text-hidden" v-if="storeName">
<u-tag style="margin-right: 10rpx" size="mini" mode="dark" v-if="item.selfOperated"
text="自营" type="error" />
<span class="line1-store-name">{{ item.storeName }}</span>
<span class="to-store">进店<u-icon size="24" name="arrow-right" color="#666"></u-icon>
</span>
</div>
<span>
<u-icon name="arrow-right" color="#c5c5c5"></u-icon>
</span>
<div class="store-seller-name" @click="navigateToStoreDetailPage(item)">
<view class="store-name-row" v-if="storeName">
<text class="self-tag" v-if="item.selfOperated">自营</text>
<text class="store-name-text">{{ item.storeName }}</text>
<text class="to-store">进店</text>
</view>
<u-icon name="arrow-right" size="12" color="#c5c5c5"></u-icon>
</div>
</div>
</div>
@@ -245,32 +239,78 @@
font-size: $font-sm;
}
.text-hidden {
.store-seller-name {
color: #666;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 4rpx;
font-size: 24rpx;
}
.store-name-row {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
overflow: hidden;
}
.store-name-text {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 24rpx;
color: #999;
}
.to-store {
flex-shrink: 0;
font-size: 24rpx;
color: #333;
margin-left: 8rpx;
}
.self-tag {
flex-shrink: 0;
margin-right: 8rpx;
padding: 2rpx 10rpx;
border-radius: 8rpx;
background: $main-color;
color: #fff;
font-size: 20rpx;
line-height: 1.4;
}
.count-config {
padding: 5rpx 0;
color: #666;
display: flex;
font-size: 24rpx;
justify-content: space-between;
}
}
.goods-row {
background: #fff;
padding: 16rpx;
>.goods-col {
display: flex;
>.goods-img {
overflow: hidden;
flex: 4;
}
>.goods-detail {
flex: 7;
}
}
}
.goods-detail {
margin: 0 20rpx;
@@ -289,25 +329,61 @@
.promotion {
margin-top: 4rpx;
display: flex;
div {
span {
font-size: 24rpx;
color: $light-color;
margin-right: 10rpx;
padding: 0 4rpx;
border-radius: 2rpx;
}
.promotion-tag {
font-size: 24rpx;
color: $light-color;
margin-right: 10rpx;
padding: 0 4rpx;
border-radius: 2rpx;
}
}
.store-seller-name {
color: #666;
overflow: hidden;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 4rpx;
font-size: 24rpx;
}
.store-name-row {
flex: 1;
min-width: 0;
display: flex;
align-items: center;
overflow: hidden;
}
.store-name-text {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 24rpx;
color: #999;
}
.to-store {
flex-shrink: 0;
font-size: 24rpx;
color: #333;
margin-left: 8rpx;
}
.self-tag {
flex-shrink: 0;
margin-right: 8rpx;
padding: 2rpx 10rpx;
border-radius: 8rpx;
background: $main-color;
color: #fff;
font-size: 20rpx;
line-height: 1.4;
}
.count-config {
padding: 5rpx 0;
color: #666;
@@ -315,7 +391,7 @@
font-size: 24rpx;
justify-content: space-between;
}
>.price-box {
margin-top: 10rpx;
display: flex;
@@ -330,8 +406,8 @@
line-height: 1;
color: $main-color;
font-weight: bold;
::v-deep span:nth-of-type(1) {
.price-int {
font-size: 38rpx;
}
}

View File

@@ -4,7 +4,7 @@
<div class="flex goods-col">
<div class="goods-img">
<u-image width="230rpx" mode="aspectFit" border-radius='16' height="230rpx" :src="item.goodsImage || item.thumbnail">
<u-loading slot="loading"></u-loading>
<template #loading><u-loading></u-loading></template>
</u-image>
</div>
<div class="goods-detail">
@@ -13,28 +13,28 @@
<view class="price-box">
<!-- 秒杀 / 拼团 -->
<div class="price" v-if="!type && item.price!=undefined">
¥<span>{{ $options.filters.goodsFormatPrice(item.price )[0] }} </span>.{{
$options.filters.goodsFormatPrice(item.price )[1]
¥<span class="price-int">{{ goodsFormatPrice(item.price )[0] }} </span>.{{
goodsFormatPrice(item.price )[1]
}}
</div>
<!-- 砍价 -->
<div class="price" v-if="type && item.purchasePrice!=undefined">
最低
¥<span>{{ $options.filters.goodsFormatPrice(item.purchasePrice )[0] }} </span>.{{
$options.filters.goodsFormatPrice(item.purchasePrice )[1]
¥<span class="price-int">{{ goodsFormatPrice(item.purchasePrice )[0] }} </span>.{{
goodsFormatPrice(item.purchasePrice )[1]
}}
</div>
<!-- 兜底策略如果金额是0 -->
<div class="price" v-if="!item.price && !type">
¥<span>0 </span>.00
¥<span class="price-int">0 </span>.00
</div>
</view>
<div>
<image class='buy' :src="buy"></image>
<image class="buy" src="/static/buy.png"></image>
</div>
</div>
<div class='count-config' v-if="!type">
<span>即将恢复{{ item.originalPrice}}</span>
<text class="count-config-text">即将恢复{{ item.originalPrice}}</text>
</div>
</div>
</div>
@@ -49,7 +49,6 @@
data() {
return {
lightColor: this.$mainColor,
buy: require('@/static/buy.png')
}
},
mixins: [commonTpl],
@@ -119,21 +118,6 @@
overflow: hidden;
}
.promotion {
margin-top: 4rpx;
display: flex;
div {
span {
font-size: 24rpx;
color: $light-color;
margin-right: 10rpx;
padding: 0 4rpx;
border-radius: 2rpx;
}
}
}
.count-config {
padding: 5rpx 0;
color: #666;
@@ -141,6 +125,10 @@
font-size: 24rpx;
letter-spacing:2rpx;
padding-left: 10rpx;
.count-config-text {
font-size: 24rpx;
}
}
@@ -162,7 +150,7 @@
color: $main-color;
font-weight: bold;
::v-deep span:nth-of-type(1) {
.price-int {
font-size: 48rpx;
}
}

View File

@@ -100,10 +100,6 @@ $w_94: 94%;
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
overflow: hidden;
> img {
width: 100%;
height: 100%;
}
}
.goods-desc {
border-bottom-left-radius: 20rpx;

View File

@@ -1,7 +1,7 @@
<template>
<view class="serach">
<view class="left-box" @tap="onClickLeft">
<u-icon name="arrow-left" size="40" color="#666"></u-icon>
<u-icon name="arrow-left" size="28" color="#666"></u-icon>
</view>
<view class="content" :style="{ 'border-radius': radius + 'px' }">
<!-- HM修改 增加进入输入状态的点击范围 -->
@@ -21,8 +21,8 @@
</view>
<view v-else class="button-item">
<u-icon name="grid-fill" size="50" @click="handelListClass()" v-if="!switchLayout"></u-icon>
<u-icon v-else @click="handelListClass()" name="list-dot" size="50"></u-icon>
<u-icon name="grid-fill" size="32" @click="handelListClass()" v-if="!switchLayout"></u-icon>
<u-icon v-else @click="handelListClass()" name="list-dot" size="32"></u-icon>
</view>
</view>
</view>
@@ -162,7 +162,7 @@ export default {
.serach {
display: flex;
width: 100%;
//border-bottom: 1px #f5f5f5 solid; //HM修改 去掉边框
align-items: center;
box-sizing: border-box;
font-size: 24rpx;
@@ -170,53 +170,41 @@ export default {
display: flex;
align-items: center;
justify-content: center;
width: 15%;
/* #ifndef APP-NVUE */
text-align: center;
// display: flex;
// /* #endif */
flex-shrink: 0;
width: auto;
padding: 0 8rpx;
}
.content {
display: flex;
align-items: center;
width: 100%;
flex: 1;
min-width: 0;
height: 70rpx;
color: #999;
background: #eee;
overflow: hidden;
transition: all 0.2s linear;
border-radius: 1000rpx;
.content-box {
width: 100%;
display: flex;
align-items: center;
&.center {
justify-content: center;
}
.icon {
padding: 0 15rpx;
&.icon-serach:before {
content: "\e61c";
}
justify-content: flex-start;
}
.input {
width: 100%;
max-width: 100%;
flex: 1;
min-width: 0;
width: auto;
line-height: 60rpx;
height: 60rpx;
transition: all 0.2s linear;
&.center {
width: 200rpx;
}
&.sub {
// position: absolute;
width: auto;
color: grey;
}
}
}
@@ -226,16 +214,16 @@ export default {
display: flex;
align-items: center;
justify-content: center;
position: relative;
flex-shrink: 0;
width: 0;
overflow: hidden;
transition: all 0.2s linear;
white-space: nowrap;
overflow: hidden;
&.active {
padding-left: 15rpx;
width: 100rpx;
padding-left: 12rpx;
width: auto;
min-width: 80rpx;
}
}
}

View File

@@ -1,6 +1,6 @@
<template>
<!-- 遮罩层 -->
<u-popup @close="close" v-model="show" mode="bottom" border-radius="30" height="260rpx">
<u-popup @close="close" v-model:show="show" mode="bottom" border-radius="30" height="260rpx">
<view class="share-title">
<span>分享至</span>
@@ -15,14 +15,14 @@
<!-- #endif -->
<!-- #ifdef APP-PLUS -->
<view class="share-item" @click="handleShare(item)" v-for="(item, index) in list" :key="index">
<u-icon :color="item.color" size="80" :name="item.icon"></u-icon>
<view>{{ item.title }}</view>
<u-icon class="share-icon" :color="item.color" size="80" :name="item.icon"></u-icon>
<view class="share-label">{{ item.title }}</view>
</view>
<!-- #endif -->
<!-- #ifdef H5 -->
<view class="share-item" @click="copyLink()">
<u-icon color="#b4aee8" size="80" name="share-fill"></u-icon>
<view>{{ '复制链接' }}</view>
<u-icon class="share-icon" color="#b4aee8" size="80" name="share-fill"></u-icon>
<view class="share-label">{{ '复制链接' }}</view>
</view>
<!-- #endif -->
</view>
@@ -31,7 +31,8 @@
<script>
import { h5Copy } from "@/js_sdk/h5-copy/h5-copy.js";
import configs from "@/config/config";
import mpShare from "uview-ui/libs/mixin/mpShare.js";
import mpShare from "@/utils/mpShare.js";
import { setClipboard } from "@/utils/filters.js";
export default {
mixins: [mpShare],
@@ -83,7 +84,7 @@ export default {
this.configs.shareLink +
getCurrentPages()[getCurrentPages().length - 1].__page__.fullPath;
}
this.$options.filters.setClipboard(content)
setClipboard(content)
},
// #endif
@@ -155,7 +156,7 @@ export default {
top: 30rpx;
}
}
button:after {
.share-btn:after {
border: none;
}
@@ -168,7 +169,8 @@ button:after {
width: 25%;
font-size: 24rpx;
color: #666;
> * {
> .share-icon,
> .share-label {
margin: 8rpx 0;
}
}

View File

@@ -1,6 +1,6 @@
<template>
<div>
<u-popup v-model="show" mode="bottom" height="800rpx" border-radius="14">
<u-popup v-model:show="show" mode="bottom" height="800rpx" border-radius="14">
<div class="wrapper">
<view class="down-goods-tips">该商品已下架</view>
<scroll-view scroll-y="true" style="height: 670rpx">

View File

@@ -0,0 +1,86 @@
<template>
<view class="u-time-line-item">
<view class="u-time-line-item__node" :style="nodeStyle">
<slot name="node">
<view class="u-time-line-item__dot" :style="{ backgroundColor: bgColor }"></view>
</slot>
</view>
<view class="u-time-line-item__content">
<slot name="content" />
</view>
</view>
</template>
<script>
export default {
name: 'UTimeLineItem',
props: {
nodeTop: {
type: [String, Number],
default: ''
},
bgColor: {
type: String,
default: '#ffffff'
}
},
computed: {
nodeStyle() {
if (this.nodeTop === '' || this.nodeTop === null || this.nodeTop === undefined) {
return {}
}
const top = typeof this.nodeTop === 'number' ? `${this.nodeTop}rpx` : this.nodeTop
return { top }
}
}
}
</script>
<style lang="scss" scoped>
.u-time-line-item {
display: flex;
flex-direction: row;
position: relative;
padding-bottom: 32rpx;
&:last-child {
padding-bottom: 0;
}
&__node {
position: relative;
width: 32rpx;
display: flex;
justify-content: center;
flex-shrink: 0;
z-index: 1;
}
&__dot {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
background-color: #ddd;
}
&__content {
flex: 1;
padding-left: 12rpx;
}
&::before {
content: '';
position: absolute;
left: 15rpx;
top: 0;
bottom: 0;
width: 1px;
background-color: #ddd;
}
&:last-child::before {
bottom: auto;
height: 16rpx;
}
}
</style>

View File

@@ -0,0 +1,18 @@
<template>
<view class="u-time-line">
<slot />
</view>
</template>
<script>
export default {
name: 'UTimeLine'
}
</script>
<style lang="scss" scoped>
.u-time-line {
display: flex;
flex-direction: column;
}
</style>

View File

@@ -2,22 +2,22 @@
<view class="uni-load-more">
<view class="uni-load-more__img" v-show="status === 'loading' && showIcon">
<view class="load1">
<view :style="{ background: color }"></view>
<view :style="{ background: color }"></view>
<view :style="{ background: color }"></view>
<view :style="{ background: color }"></view>
<view class="load-item" :style="{ background: color }"></view>
<view class="load-item" :style="{ background: color }"></view>
<view class="load-item" :style="{ background: color }"></view>
<view class="load-item" :style="{ background: color }"></view>
</view>
<view class="load2">
<view :style="{ background: color }"></view>
<view :style="{ background: color }"></view>
<view :style="{ background: color }"></view>
<view :style="{ background: color }"></view>
<view class="load-item" :style="{ background: color }"></view>
<view class="load-item" :style="{ background: color }"></view>
<view class="load-item" :style="{ background: color }"></view>
<view class="load-item" :style="{ background: color }"></view>
</view>
<view class="load3">
<view :style="{ background: color }"></view>
<view :style="{ background: color }"></view>
<view :style="{ background: color }"></view>
<view :style="{ background: color }"></view>
<view class="load-item" :style="{ background: color }"></view>
<view class="load-item" :style="{ background: color }"></view>
<view class="load-item" :style="{ background: color }"></view>
<view class="load-item" :style="{ background: color }"></view>
</view>
</view>
<text class="uni-load-more__text" :style="{ color: color }" v-if="showText">
@@ -86,11 +86,13 @@ export default {
margin-right: 10px;
}
.uni-load-more__img > view {
.load1,
.load2,
.load3 {
position: absolute;
}
.uni-load-more__img > view view {
.load-item {
width: 6px;
height: 2px;
border-top-left-radius: 1px;
@@ -102,25 +104,25 @@ export default {
animation: load 1.56s ease infinite;
}
.uni-load-more__img > view view:nth-child(1) {
.load-item:nth-child(1) {
transform: rotate(90deg);
top: 2px;
left: 9px;
}
.uni-load-more__img > view view:nth-child(2) {
.load-item:nth-child(2) {
transform: rotate(180deg);
top: 11px;
right: 0;
}
.uni-load-more__img > view view:nth-child(3) {
.load-item:nth-child(3) {
transform: rotate(270deg);
bottom: 2px;
left: 9px;
}
.uni-load-more__img > view view:nth-child(4) {
.load-item:nth-child(4) {
top: 11px;
left: 0;
}
@@ -140,51 +142,51 @@ export default {
transform: rotate(60deg);
}
.load1 view:nth-child(1) {
.load1 .load-item:nth-child(1) {
animation-delay: 0s;
}
.load2 view:nth-child(1) {
.load2 .load-item:nth-child(1) {
animation-delay: 0.13s;
}
.load3 view:nth-child(1) {
.load3 .load-item:nth-child(1) {
animation-delay: 0.26s;
}
.load1 view:nth-child(2) {
.load1 .load-item:nth-child(2) {
animation-delay: 0.39s;
}
.load2 view:nth-child(2) {
.load2 .load-item:nth-child(2) {
animation-delay: 0.52s;
}
.load3 view:nth-child(2) {
.load3 .load-item:nth-child(2) {
animation-delay: 0.65s;
}
.load1 view:nth-child(3) {
.load1 .load-item:nth-child(3) {
animation-delay: 0.78s;
}
.load2 view:nth-child(3) {
.load2 .load-item:nth-child(3) {
animation-delay: 0.91s;
}
.load3 view:nth-child(3) {
.load3 .load-item:nth-child(3) {
animation-delay: 1.04s;
}
.load1 view:nth-child(4) {
.load1 .load-item:nth-child(4) {
animation-delay: 1.17s;
}
.load2 view:nth-child(4) {
.load2 .load-item:nth-child(4) {
animation-delay: 1.3s;
}
.load3 view:nth-child(4) {
.load3 .load-item:nth-child(4) {
animation-delay: 1.43s;
}

View File

@@ -24,14 +24,13 @@
<!-- 输入框 - -->
<view id="xt__input-ground" class="xt__input-ground">
<template v-for="(item, index) in size">
<template v-for="(item, index) in size" :key="index">
<view
:key="index"
:style="{ borderColor: code.length === index && cursorVisible ? boxActiveColor : boxNormalColor }"
:class="['xt__box', `xt__box-${type + ''}`, `xt__box::after`]"
>
<view :style="{ borderColor: boxActiveColor }" class="xt__middle-line" v-if="type === 'middle' && !code[index]"></view>
<text class="xt__code-text">{{ code[index] | codeFormat(isPassword) }}</text>
<text class="xt__code-text">{{ codeFormat(code[index], isPassword) }}</text>
</view>
</template>
</view>
@@ -178,14 +177,7 @@ export default {
// 输入失去焦点
inputBlur() {
this.cursorVisible = false;
}
},
watch: {
value(val) {
this.code = val;
}
},
filters: {
},
codeFormat(val, isPassword) {
let value = '';
if (val) {
@@ -193,6 +185,11 @@ export default {
}
return value;
}
},
watch: {
value(val) {
this.code = val;
}
}
};
</script>