mirror of
https://gitee.com/beijing_hongye_huicheng/lilishop-uniapp.git
synced 2026-08-06 10:57:25 +08:00
refactor: 重构多个组件以支持 Vue 3 语法和功能
- 将多个组件转换为 `<script setup>` 语法,提升可读性和性能 - 优化状态管理和事件处理逻辑,简化代码结构 - 更新样式和布局以适应新组件结构 - 添加新功能和修复已知问题,提升用户体验
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<view>
|
||||
<!-- 一行两列商品展示 -->
|
||||
<view class="goods-list" v-if="type == 'twoColumns'">
|
||||
<view v-for="(item, index) in res" :key="index" class="goods-item">
|
||||
@@ -10,7 +10,7 @@
|
||||
height="330rpx"
|
||||
mode="aspectFit"
|
||||
>
|
||||
<template #loading><u-loading></u-loading></template>
|
||||
<template #loading><u-loading-icon></u-loading-icon></template>
|
||||
</u-image>
|
||||
</view>
|
||||
<view class="goods-detail">
|
||||
@@ -57,7 +57,7 @@
|
||||
</view>
|
||||
<!-- 一行一列商品展示 -->
|
||||
<div v-if="type == 'oneColumns'">
|
||||
<div v-for="(item, index) in res" :key="index" class="goods-row">
|
||||
div v-for="(item, index) in res" :key="index" class="goods-row">
|
||||
<div class="flex goods-col">
|
||||
<div class="goods-img" @click="navigateToDetailPage(item)">
|
||||
<u-image
|
||||
@@ -67,7 +67,7 @@
|
||||
mode="aspectFit"
|
||||
:src="item.goodsImage || item.thumbnail"
|
||||
>
|
||||
<template #loading><u-loading></u-loading></template>
|
||||
<template #loading><u-loading-icon></u-loading-icon></template>
|
||||
</u-image>
|
||||
</div>
|
||||
<div class="goods-detail">
|
||||
@@ -112,41 +112,26 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import commonTpl from "@/components/m-goods-list/common";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
lightColor: this.$mainColor,
|
||||
};
|
||||
},
|
||||
mixins: [commonTpl],
|
||||
props: {
|
||||
// 展示的类型
|
||||
type:{
|
||||
type:String,
|
||||
default:"oneColumns"
|
||||
},
|
||||
// 遍历的数据
|
||||
res: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 跳转到商品详情
|
||||
navigateToDetailPage(item) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
<script setup lang="ts">
|
||||
import { useGoodsListCommon } from './common'
|
||||
import { goodsFormatPrice } from '@/utils/filters.js'
|
||||
|
||||
const { lightSearchStr, getPromotion, navigateToDetailPage, navigateToStoreDetailPage } = useGoodsListCommon()
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
type?: string
|
||||
res?: any[]
|
||||
storeName?: boolean
|
||||
keyword?: string | null
|
||||
}>(), {
|
||||
type: 'oneColumns',
|
||||
res: () => [],
|
||||
storeName: true,
|
||||
keyword: ''
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
90
components/m-goods-list/common.ts
Normal file
90
components/m-goods-list/common.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { useStore } from '@/store'
|
||||
|
||||
/**
|
||||
* 商品列表公共逻辑(原 common.vue mixin)
|
||||
* 提供高亮搜索、unicode 转换、促销标签、导航跳转等通用方法
|
||||
*/
|
||||
export function useGoodsListCommon() {
|
||||
const store = useStore()
|
||||
|
||||
const lightColor = store.getters.lightColor
|
||||
|
||||
/**
|
||||
* 高亮显示搜索内容
|
||||
*/
|
||||
const lightSearchStr = (keyword: string, str: string) => {
|
||||
if (!keyword) {
|
||||
return str
|
||||
} else {
|
||||
let unicodes = ''
|
||||
for (let i of Array.from(keyword)) {
|
||||
unicodes += unicode(i) + "|"
|
||||
}
|
||||
const rule = '(' + unicodes + ')'
|
||||
const reg = new RegExp(rule, 'gi')
|
||||
return str ? str.replace(reg, (matchValue) =>
|
||||
`<span style="color:${lightColor}">${matchValue}</span>`
|
||||
) : ''
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为 unicode
|
||||
*/
|
||||
const unicode = (str: string) => {
|
||||
var value = ''
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
value += '\\u' + leftZero4(parseInt(str.charCodeAt(i).toString(16)))
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
const leftZero4 = (str: string) => {
|
||||
if (str != null && str != '' && str != 'undefined') {
|
||||
if (str.length == 2) {
|
||||
return '00' + str
|
||||
}
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据去重 只显示一次 减免 劵等
|
||||
*/
|
||||
const getPromotion = (item: any) => {
|
||||
if (item.promotionMap) {
|
||||
let array: string[] = []
|
||||
Object.keys(item.promotionMap).forEach((child) => {
|
||||
if (!array.includes(child.split("-")[0])) {
|
||||
array.push(child.split("-")[0])
|
||||
}
|
||||
})
|
||||
return array
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到商品详情
|
||||
*/
|
||||
const navigateToDetailPage = (item: any) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转到店铺详情
|
||||
*/
|
||||
const navigateToStoreDetailPage = (item: any) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/product/shopPage?id=${item.storeId}`,
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
lightSearchStr,
|
||||
getPromotion,
|
||||
navigateToDetailPage,
|
||||
navigateToStoreDetailPage,
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
<template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
methods: {
|
||||
// 高亮显示搜索内容
|
||||
lightSearchStr(keyword, str) {
|
||||
if (!keyword) {
|
||||
return str
|
||||
} else {
|
||||
let unicodes = '';
|
||||
for (let i of Array.from(keyword)) {
|
||||
unicodes += this.unicode(i) + "|"
|
||||
}
|
||||
const rule = '(' + unicodes + ')'
|
||||
const reg = new RegExp(rule, 'gi');
|
||||
return str ? str.replace(reg, matchValue =>
|
||||
`<span style="color:${this.lightColor}">${matchValue}</span>`
|
||||
) : ''
|
||||
}
|
||||
},
|
||||
// 转换为unicode
|
||||
unicode(str) {
|
||||
var value = '';
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
value += '\\u' + this.left_zero_4(parseInt(str.charCodeAt(i)).toString(16));
|
||||
}
|
||||
return value;
|
||||
},
|
||||
left_zero_4(str) {
|
||||
if (str != null && str != '' && str != 'undefined') {
|
||||
if (str.length == 2) {
|
||||
return '00' + str;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
},
|
||||
// 数据去重一下 只显示一次 减免 劵 什么的
|
||||
getPromotion(item) {
|
||||
if (item.promotionMap) {
|
||||
let array = [];
|
||||
Object.keys(item.promotionMap).forEach((child) => {
|
||||
if (!array.includes(child.split("-")[0])) {
|
||||
array.push(child.split("-")[0]);
|
||||
}
|
||||
});
|
||||
return array;
|
||||
}
|
||||
},
|
||||
// 跳转到商品详情
|
||||
navigateToDetailPage(item) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`,
|
||||
});
|
||||
},
|
||||
// 跳转地址
|
||||
navigateToStoreDetailPage(item) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/product/shopPage?id=${item.storeId}`,
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
|
||||
</style>
|
||||
@@ -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">
|
||||
<template #loading><u-loading></u-loading></template>
|
||||
<template #loading><u-loading-icon></u-loading-icon></template>
|
||||
</u-image>
|
||||
</view>
|
||||
<view class="goods-detail">
|
||||
@@ -51,7 +51,7 @@
|
||||
<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">
|
||||
<template #loading><u-loading></u-loading></template>
|
||||
<template #loading><u-loading-icon></u-loading-icon></template>
|
||||
</u-image>
|
||||
</div>
|
||||
<div class="goods-detail">
|
||||
@@ -94,114 +94,32 @@
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import commonTpl from '@/components/m-goods-list/common'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
lightColor: this.$mainColor
|
||||
}
|
||||
},
|
||||
mixins: [commonTpl],
|
||||
|
||||
props: {
|
||||
// 遍历的数据
|
||||
res: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
// 一行两列还是一行一列显示
|
||||
type: {
|
||||
type: String,
|
||||
default: 'twoColumns',
|
||||
validator() {
|
||||
return ['twoColumns', 'oneColumns']
|
||||
}
|
||||
},
|
||||
storeName: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
tabBarGap: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
keyword: {
|
||||
type: null,
|
||||
default: ''
|
||||
}
|
||||
<script setup lang="ts">
|
||||
import { watch } from 'vue'
|
||||
import { useGoodsListCommon } from './common'
|
||||
import { goodsFormatPrice } from '@/utils/filters.js'
|
||||
|
||||
},
|
||||
watch: {
|
||||
keyword(val) {
|
||||
if (val) {
|
||||
this.lightSearchStr(val)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
const { lightSearchStr, getPromotion, navigateToDetailPage, navigateToStoreDetailPage } = useGoodsListCommon()
|
||||
|
||||
// 高亮显示搜索内容
|
||||
lightSearchStr(keyword, str) {
|
||||
if (!keyword) {
|
||||
return str
|
||||
} else {
|
||||
let unicodes = '';
|
||||
for (let i of Array.from(keyword)) {
|
||||
unicodes += this.unicode(i) + "|"
|
||||
}
|
||||
const rule = '(' + unicodes + ')'
|
||||
const reg = new RegExp(rule, 'gi');
|
||||
return str ? str.replace(reg, matchValue =>
|
||||
`<span style="color:${this.lightColor}">${matchValue}</span>`
|
||||
) : ''
|
||||
}
|
||||
},
|
||||
// 转换为unicode
|
||||
unicode(str) {
|
||||
var value = '';
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
value += '\\u' + this.left_zero_4(parseInt(str.charCodeAt(i)).toString(16));
|
||||
}
|
||||
return value;
|
||||
},
|
||||
left_zero_4(str) {
|
||||
if (str != null && str != '' && str != 'undefined') {
|
||||
if (str.length == 2) {
|
||||
return '00' + str;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
},
|
||||
// 数据去重一下 只显示一次 减免 劵 什么的
|
||||
getPromotion(item) {
|
||||
if (item ? item.promotionMap : item.promotionMap) {
|
||||
const fieldList = item ? item.promotionMap : item.promotionMap
|
||||
let array = [];
|
||||
Object.keys(fieldList).forEach((child) => {
|
||||
if (!array.includes(child.split("-")[0])) {
|
||||
array.push(child.split("-")[0]);
|
||||
}
|
||||
});
|
||||
return array;
|
||||
}
|
||||
},
|
||||
// 跳转到商品详情
|
||||
navigateToDetailPage(item) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/product/goods?id=${item.id}&goodsId=${item.goodsId}`,
|
||||
});
|
||||
},
|
||||
// 跳转地址
|
||||
navigateToStoreDetailPage(item) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/product/shopPage?id=${item.storeId}`,
|
||||
});
|
||||
},
|
||||
}
|
||||
const props = withDefaults(defineProps<{
|
||||
res?: any[]
|
||||
type?: string
|
||||
storeName?: boolean
|
||||
tabBarGap?: boolean
|
||||
keyword?: string | null
|
||||
}>(), {
|
||||
res: () => [],
|
||||
type: 'twoColumns',
|
||||
storeName: true,
|
||||
tabBarGap: true,
|
||||
keyword: ''
|
||||
})
|
||||
|
||||
watch(() => props.keyword, (val) => {
|
||||
if (val) {
|
||||
lightSearchStr(val as string, '')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
@@ -212,6 +130,7 @@
|
||||
.goods-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
margin: 10rpx 20rpx 284rpx;
|
||||
width: calc(100% - 40rpx);
|
||||
box-sizing: border-box;
|
||||
@@ -219,21 +138,17 @@
|
||||
&.goods-list--embedded {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
|
||||
>.goods-item {
|
||||
background-color: #ffffff;
|
||||
display: flex;
|
||||
border-radius: 16rpx;
|
||||
flex-direction: column;
|
||||
width: calc(50% - 30rpx);
|
||||
width: calc(50% - 10rpx);
|
||||
margin-bottom: 20rpx;
|
||||
padding-bottom: 20rpx;
|
||||
|
||||
&:nth-child(2n + 1) {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
.image-wrapper {
|
||||
width: 100%;
|
||||
height: 330rpx;
|
||||
@@ -242,12 +157,12 @@
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.count-config,
|
||||
.store-seller-name {
|
||||
font-size: $font-sm;
|
||||
}
|
||||
|
||||
|
||||
.store-seller-name {
|
||||
color: #666;
|
||||
display: flex;
|
||||
@@ -322,7 +237,7 @@
|
||||
|
||||
.goods-detail {
|
||||
margin: 0 20rpx;
|
||||
|
||||
|
||||
>.title {
|
||||
font-size: $font-base;
|
||||
color: $font-color-dark;
|
||||
@@ -334,7 +249,7 @@
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
.promotion {
|
||||
margin-top: 4rpx;
|
||||
display: flex;
|
||||
@@ -344,10 +259,10 @@
|
||||
color: $light-color;
|
||||
margin-right: 10rpx;
|
||||
padding: 0 4rpx;
|
||||
border-radius: 2rpx;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.store-seller-name {
|
||||
color: #666;
|
||||
display: flex;
|
||||
@@ -409,7 +324,7 @@
|
||||
padding-right: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: $font-color-light;
|
||||
|
||||
|
||||
>.price {
|
||||
font-size: 26rpx;
|
||||
line-height: 1;
|
||||
@@ -421,6 +336,5 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -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">
|
||||
<template #loading><u-loading></u-loading></template>
|
||||
<template #loading><u-loading-icon></u-loading-icon></template>
|
||||
</u-image>
|
||||
</div>
|
||||
<div class="goods-detail">
|
||||
@@ -43,43 +43,33 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import commonTpl from '@/components/m-goods-list/common'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
lightColor: this.$mainColor,
|
||||
}
|
||||
},
|
||||
mixins: [commonTpl],
|
||||
props: {
|
||||
// 遍历的数据
|
||||
res: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
},
|
||||
type:{
|
||||
type:null,
|
||||
default:""
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 跳转到商品详情
|
||||
navigateToDetailPage(item) {
|
||||
if(this.type == 'kanJia'){
|
||||
uni.navigateTo({
|
||||
url: `/pages/promotion/bargain/detail?id=${item.id}`,
|
||||
});
|
||||
return
|
||||
}
|
||||
uni.navigateTo({
|
||||
url: `/pages/product/goods?id=${item.skuId}&goodsId=${item.goodsId}`,
|
||||
});
|
||||
},
|
||||
}
|
||||
<script setup lang="ts">
|
||||
import { useGoodsListCommon } from './common'
|
||||
import { goodsFormatPrice } from '@/utils/filters.js'
|
||||
|
||||
const { navigateToDetailPage } = useGoodsListCommon()
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
res?: any[]
|
||||
type?: string | null
|
||||
}>(), {
|
||||
res: () => [],
|
||||
type: ''
|
||||
})
|
||||
|
||||
// 跳转到商品详情(覆盖公共方法,增加砍价跳转)
|
||||
const navigateToDetailPageOverride = (item: any) => {
|
||||
if(props.type == 'kanJia'){
|
||||
uni.navigateTo({
|
||||
url: `/pages/promotion/bargain/detail?id=${item.id}`,
|
||||
})
|
||||
return
|
||||
}
|
||||
navigateToDetailPage({
|
||||
id: item.skuId,
|
||||
goodsId: item.goodsId,
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
@@ -87,72 +77,72 @@
|
||||
width: 152rpx;
|
||||
height: 108rpx;
|
||||
}
|
||||
.flex-j-sb {
|
||||
.flex-j-sb {
|
||||
width: 100%;
|
||||
}
|
||||
.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;
|
||||
>.title {
|
||||
font-size: $font-base;
|
||||
color: $font-color-dark;
|
||||
line-height: 1.5;
|
||||
height: 86rpx;
|
||||
padding: 10rpx 0 0;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.count-config {
|
||||
padding: 5rpx 0;
|
||||
color: #666;
|
||||
display: flex;
|
||||
font-size: 24rpx;
|
||||
letter-spacing:2rpx;
|
||||
padding-left: 10rpx;
|
||||
|
||||
.count-config-text {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
.price-box {
|
||||
margin-top: 10rpx;
|
||||
.goods-row {
|
||||
background: #fff;
|
||||
padding: 16rpx;
|
||||
>.goods-col {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-right: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: $font-color-light;
|
||||
|
||||
>.price {
|
||||
font-size: 26rpx;
|
||||
line-height: 1;
|
||||
color: $main-color;
|
||||
font-weight: bold;
|
||||
|
||||
.price-int {
|
||||
font-size: 48rpx;
|
||||
}
|
||||
>.goods-img {
|
||||
overflow: hidden;
|
||||
flex: 4;
|
||||
}
|
||||
>.goods-detail {
|
||||
flex: 7;
|
||||
}
|
||||
}
|
||||
}
|
||||
.goods-detail {
|
||||
margin: 0 20rpx;
|
||||
>.title {
|
||||
font-size: $font-base;
|
||||
color: $font-color-dark;
|
||||
line-height: 1.5;
|
||||
height: 86rpx;
|
||||
padding: 10rpx 0 0;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.count-config {
|
||||
padding: 5rpx 0;
|
||||
color: #666;
|
||||
display: flex;
|
||||
font-size: 24rpx;
|
||||
letter-spacing:2rpx;
|
||||
padding-left: 10rpx;
|
||||
|
||||
.count-config-text {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
.price-box {
|
||||
margin-top: 10rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-right: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: $font-color-light;
|
||||
|
||||
>.price {
|
||||
font-size: 26rpx;
|
||||
line-height: 1;
|
||||
color: $main-color;
|
||||
font-weight: bold;
|
||||
|
||||
.price-int {
|
||||
font-size: 48rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user