perf: 修改移动端包体积问题
- 删除未使用组件 primewind-sliderrange、u--image(主包无用组件) - manifest 启用 lazyCodeLoading 组件按需注入 - 移除 serverInfo/evaluate 中对已删组件的失效引用 - 压缩 smartDevice 页图片(cat 缩略图降至 160px、hero 横幅降质量档),主包图片总量降至 200K 以下 Claude-Session: https://claude.ai/code/session_01Ya56EWbT3mBRNrtMv8pjNC
@ -1,74 +0,0 @@
|
||||
# slider-range
|
||||
uni-app 滑块区间选择组件
|
||||
|
||||
可根据具体需求,修改、自定义其他内容。
|
||||
|
||||
## 属性说明
|
||||
|
||||
|属性名|类型|默认值|说明|
|
||||
| -- | -- | --|--|
|
||||
| value | Array<Number, Number> | [0,100] |滑块已选中区间的值|
|
||||
| min | Number| 0 | 滑块区间最小值 |
|
||||
| max | Number | 100 | 滑块区间最大值 |
|
||||
| step | Number | 1 | 拖动时的步长 |
|
||||
| disabled | Boolean | false | 是否为禁用状态 |
|
||||
| height | Number | 50 | 滑块容器高度 |
|
||||
| barHeight | Number | 5 | 滑块进度条高度 |
|
||||
| backgroundColor | String | #e9e9e9| 滑块进度条背景色|
|
||||
| activeColor | String | #1aad19 | 已选中区间进度条颜色|
|
||||
| blockSize | Number | 20 | 滑块大小 |
|
||||
| blockColor | String | #fff | 滑块颜色 |
|
||||
| decorationVisible | Boolean | false | 是否显示滑块内装饰元素|
|
||||
| tipVisible | Boolean | true | 是否显示滑块值提示文本 |
|
||||
| fomat| Function | | 滑块值提示文本格式化函数,**注意**:小程序中此属性必传,否则会报错,如果无需格式化,可以简单返回原始值: `format(val) { return val }`;H5中可以不传。|
|
||||
|
||||
|
||||
## 使用示例
|
||||
|
||||
```html
|
||||
|
||||
<slider-range
|
||||
:value="rangeValue"
|
||||
:min="rangeMin"
|
||||
:max="rangMax"
|
||||
:step="5"
|
||||
:bar-height="3"
|
||||
:block-size="26"
|
||||
background-color="#EEEEF6"
|
||||
active-color="#FF6B00"
|
||||
:format="format"
|
||||
:decorationVisible="true"
|
||||
@change="handleRangeChange"
|
||||
></slider-range>
|
||||
|
||||
|
||||
```
|
||||
|
||||
```javascript
|
||||
|
||||
import SliderRange from '../components/slider-range/index.vue'
|
||||
export default {
|
||||
components: {
|
||||
SliderRange
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
rangeMin: 5,
|
||||
rangMax: 200,
|
||||
rangeValue: [10, 50]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
format(val) {
|
||||
return val + '%'
|
||||
},
|
||||
handleRangeChange(e) {
|
||||
this.rangeValue = e
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
效果图
|
||||
|
||||

|
||||
@ -1,378 +0,0 @@
|
||||
<template>
|
||||
<view
|
||||
class="slider-range"
|
||||
:class="{ disabled: disabled }"
|
||||
:style="{ paddingLeft: blockSize / 2 + 'px', paddingRight: blockSize / 2 + 'px' }"
|
||||
>
|
||||
<view class="slider-range-inner" :style="{ height: height + 'px' }">
|
||||
<view
|
||||
class="slider-bar"
|
||||
:style="{
|
||||
height: barHeight + 'px',
|
||||
}"
|
||||
>
|
||||
<!-- 背景条 -->
|
||||
<view
|
||||
class="slider-bar-bg"
|
||||
:style="{
|
||||
backgroundColor: backgroundColor,
|
||||
}"
|
||||
></view>
|
||||
|
||||
<!-- 滑块实际区间 -->
|
||||
<view
|
||||
class="slider-bar-inner"
|
||||
:style="{
|
||||
width: ((values[1] - values[0]) / (max - min)) * 100 + '%',
|
||||
left: lowerHandlePosition + '%',
|
||||
backgroundColor: activeColor,
|
||||
}"
|
||||
></view>
|
||||
</view>
|
||||
|
||||
<!-- 滑动块-左 -->
|
||||
<view
|
||||
class="slider-handle-block"
|
||||
:class="{ decoration: decorationVisible }"
|
||||
:style="{
|
||||
backgroundColor: blockColor,
|
||||
width: blockSize + 'px',
|
||||
height: blockSize + 'px',
|
||||
left: lowerHandlePosition + '%',
|
||||
}"
|
||||
@touchstart="_onTouchStart"
|
||||
@touchmove="_onBlockTouchMove"
|
||||
@touchend="_onBlockTouchEnd"
|
||||
data-tag="lowerBlock"
|
||||
></view>
|
||||
|
||||
<!-- 滑动块-右 -->
|
||||
<view
|
||||
class="slider-handle-block"
|
||||
:class="{ decoration: decorationVisible }"
|
||||
:style="{
|
||||
backgroundColor: blockColor,
|
||||
width: blockSize + 'px',
|
||||
height: blockSize + 'px',
|
||||
left: higherHandlePosition + '%',
|
||||
}"
|
||||
@touchstart="_onTouchStart"
|
||||
@touchmove="_onBlockTouchMove"
|
||||
@touchend="_onBlockTouchEnd"
|
||||
data-tag="higherBlock"
|
||||
></view>
|
||||
|
||||
<!-- 滑块值提示 -->
|
||||
<view v-if="tipVisible" class="range-tip" :style="lowerTipStyle">{{ format(values[0]) }}</view>
|
||||
<view v-if="tipVisible" class="range-tip" :style="higherTipStyle">{{ format(values[1]) }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
//滑块区间当前取值
|
||||
value: {
|
||||
type: Array,
|
||||
default: function() {
|
||||
return [0, 100]
|
||||
},
|
||||
},
|
||||
//最小值
|
||||
min: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
//最大值
|
||||
max: {
|
||||
type: Number,
|
||||
default: 100,
|
||||
},
|
||||
step: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
format: {
|
||||
type: Function,
|
||||
default: function(val) {
|
||||
return val
|
||||
},
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
//滑块容器高度
|
||||
height: {
|
||||
height: Number,
|
||||
default: 50,
|
||||
},
|
||||
//区间进度条高度
|
||||
barHeight: {
|
||||
type: Number,
|
||||
default: 5,
|
||||
},
|
||||
//背景条颜色
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: '#e9e9e9',
|
||||
},
|
||||
//已选择的颜色
|
||||
activeColor: {
|
||||
type: String,
|
||||
default: '#1aad19',
|
||||
},
|
||||
//滑块大小
|
||||
blockSize: {
|
||||
type: Number,
|
||||
default: 20,
|
||||
},
|
||||
blockColor: {
|
||||
type: String,
|
||||
default: '#fff',
|
||||
},
|
||||
tipVisible: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
decorationVisible: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
values: [this.min, this.max],
|
||||
startDragPos: 0, // 开始拖动时的坐标位置
|
||||
startVal: 0, //开始拖动时较小点的值
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 较小点滑块的坐标
|
||||
lowerHandlePosition() {
|
||||
return ((this.values[0] - this.min) / (this.max - this.min)) * 100
|
||||
},
|
||||
// 较大点滑块的坐标
|
||||
higherHandlePosition() {
|
||||
return ((this.values[1] - this.min) / (this.max - this.min)) * 100
|
||||
},
|
||||
lowerTipStyle() {
|
||||
if (this.lowerHandlePosition < 90) {
|
||||
return `left: ${this.lowerHandlePosition}%;`
|
||||
}
|
||||
return `right: ${100 - this.lowerHandlePosition}%;transform: translate(50%, -100%);`
|
||||
},
|
||||
higherTipStyle() {
|
||||
if (this.higherHandlePosition < 90) {
|
||||
return `left: ${this.higherHandlePosition}%;`
|
||||
}
|
||||
return `right: ${100 - this.higherHandlePosition}%;transform: translate(50%, -100%);`
|
||||
},
|
||||
},
|
||||
created: function() {},
|
||||
onLoad: function(option) {},
|
||||
watch: {
|
||||
//滑块当前值
|
||||
value: {
|
||||
immediate: true,
|
||||
handler(newVal, oldVal) {
|
||||
if (this._isValuesValid(newVal) && (newVal[0] !== this.values[0] || newVal[1] !== this.values[1])) {
|
||||
this._updateValue(newVal)
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
_updateValue(newVal) {
|
||||
// 步长大于区间差,或者区间最大值和最小值相等情况
|
||||
if (this.step >= this.max - this.min) {
|
||||
throw new RangeError('Invalid slider step or slider range')
|
||||
}
|
||||
|
||||
let newValues = []
|
||||
if (Array.isArray(newVal)) {
|
||||
newValues = [newVal[0], newVal[1]]
|
||||
}
|
||||
if (typeof newValues[0] !== 'number') {
|
||||
newValues[0] = this.values[0]
|
||||
} else {
|
||||
newValues[0] = Math.round((newValues[0] - this.min) / this.step) * this.step + this.min
|
||||
}
|
||||
if (typeof newValues[1] !== 'number') {
|
||||
newValues[1] = this.values[1]
|
||||
} else {
|
||||
newValues[1] = Math.round((newValues[1] - this.min) / this.step) * this.step + this.min
|
||||
}
|
||||
|
||||
// 新值与原值相等,不做处理
|
||||
if (this.values[0] === newValues[0] && this.values[1] === newValues[1]) {
|
||||
return
|
||||
}
|
||||
// 左侧滑块值小于最小值时,设置为最小值
|
||||
if (newValues[0] < this.min) {
|
||||
newValues[0] = this.min
|
||||
}
|
||||
// 右侧滑块值大于最大值时,设置为最大值
|
||||
if (newValues[1] > this.max) {
|
||||
newValues[1] = this.max
|
||||
}
|
||||
// 两个滑块重叠或左右交错,使两个滑块保持最小步长的间距
|
||||
if (newValues[0] >= newValues[1]) {
|
||||
// 左侧未动,右侧滑块滑到左侧滑块之左
|
||||
if (newValues[0] === this.values[0]) {
|
||||
newValues[1] = newValues[0] + this.step
|
||||
} else {
|
||||
// 右侧未动, 左侧滑块滑到右侧之右
|
||||
newValues[0] = newValues[1] - this.step
|
||||
}
|
||||
}
|
||||
|
||||
this.values = newValues
|
||||
this.$emit('change', this.values)
|
||||
},
|
||||
_onTouchStart: function(event) {
|
||||
if (this.disabled) {
|
||||
return
|
||||
}
|
||||
|
||||
this.isDragging = true
|
||||
let tag = event.target.dataset.tag
|
||||
|
||||
//兼容h5平台及某版本微信
|
||||
let e = event.changedTouches ? event.changedTouches[0] : event
|
||||
this.startDragPos = e.pageX
|
||||
|
||||
this.startVal = tag === 'lowerBlock' ? this.values[0] : this.values[1]
|
||||
},
|
||||
_onBlockTouchMove: function(e) {
|
||||
if (this.disabled) {
|
||||
return
|
||||
}
|
||||
this._onDrag(e)
|
||||
},
|
||||
_onBlockTouchEnd: function(e) {
|
||||
if (this.disabled) {
|
||||
return
|
||||
}
|
||||
this.isDragging = false
|
||||
this._onDrag(e)
|
||||
},
|
||||
_onDrag(event) {
|
||||
if (!this.isDragging) {
|
||||
return
|
||||
}
|
||||
let view = uni
|
||||
.createSelectorQuery()
|
||||
.in(this)
|
||||
.select('.slider-range-inner')
|
||||
|
||||
view
|
||||
.boundingClientRect(data => {
|
||||
let sliderWidth = data.width
|
||||
const tag = event.target.dataset.tag
|
||||
let e = event.changedTouches ? event.changedTouches[0] : event
|
||||
let diff = ((e.pageX - this.startDragPos) / sliderWidth) * (this.max - this.min)
|
||||
let nextVal = this.startVal + diff
|
||||
|
||||
if (tag === 'lowerBlock') {
|
||||
this._updateValue([nextVal, null])
|
||||
} else {
|
||||
this._updateValue([null, nextVal])
|
||||
}
|
||||
})
|
||||
.exec()
|
||||
},
|
||||
_isValuesValid: function(values) {
|
||||
return Array.isArray(values) && values.length == 2
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.slider-range {
|
||||
position: relative;
|
||||
padding-top: 40rpx;
|
||||
}
|
||||
|
||||
.slider-range-inner {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.slider-range.disabled .slider-bar-inner {
|
||||
opacity: 0.35;
|
||||
}
|
||||
|
||||
.slider-range.disabled .slider-handle-block {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.slider-bar {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.slider-bar-bg {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10000px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.slider-bar-inner {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10000px;
|
||||
z-index: 11;
|
||||
}
|
||||
|
||||
.slider-handle-block {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 3px 2px rgba(227, 229, 241, 0.5);
|
||||
z-index: 12;
|
||||
}
|
||||
|
||||
.slider-handle-block.decoration::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 6upx;
|
||||
height: 24upx;
|
||||
top: 50%;
|
||||
left: 29%;
|
||||
transform: translateY(-50%);
|
||||
background: #eeedf2;
|
||||
border-radius: 3upx;
|
||||
z-index: 13;
|
||||
}
|
||||
|
||||
.slider-handle-block.decoration::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
width: 6upx;
|
||||
height: 24upx;
|
||||
top: 50%;
|
||||
right: 29%;
|
||||
transform: translateY(-50%);
|
||||
background: #eeedf2;
|
||||
border-radius: 3upx;
|
||||
z-index: 13;
|
||||
}
|
||||
|
||||
.range-tip {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
font-size: 24upx;
|
||||
color: #666;
|
||||
transform: translate(-50%, -100%);
|
||||
}
|
||||
</style>
|
||||
@ -1,90 +0,0 @@
|
||||
<template>
|
||||
<view class="demo-slider-range">
|
||||
<view class="section-title">普通用法</view>
|
||||
<view class="slider-item">
|
||||
<slider-range
|
||||
:value="slider1.rangeValue"
|
||||
:min="slider1.min"
|
||||
:max="slider1.max"
|
||||
:step="slider1.step"
|
||||
:bar-height="barHeight"
|
||||
:block-size="blockSize"
|
||||
:background-color="backgroundColor"
|
||||
:format="format1"
|
||||
@change="handleRangeChange"
|
||||
></slider-range>
|
||||
</view>
|
||||
<view class="section-title">自定义</view>
|
||||
<view class="slider-item">
|
||||
<slider-range
|
||||
:value="slider2.rangeValue"
|
||||
:min="slider2.min"
|
||||
:max="slider2.max"
|
||||
:step="slider2.step"
|
||||
:bar-height="barHeight"
|
||||
:block-size="blockSize"
|
||||
:background-color="backgroundColor"
|
||||
:active-color="slider2.activeColor"
|
||||
:format="format2"
|
||||
:decorationVisible="slider2.decorationVisible"
|
||||
@change="handleRangeChange"
|
||||
></slider-range>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SliderRange from '../../components/slider-range/index.vue'
|
||||
export default {
|
||||
components: {
|
||||
SliderRange,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
barHeight: 3,
|
||||
blockSize: 26,
|
||||
backgroundColor: '#EEEEF6',
|
||||
slider1: {
|
||||
min: 50,
|
||||
max: 200,
|
||||
step: 10,
|
||||
rangeValue: [50, 150],
|
||||
},
|
||||
slider2: {
|
||||
rangeMin: 0,
|
||||
rangMax: 100,
|
||||
rangeValue: [8, 80],
|
||||
step: 1,
|
||||
activeColor: '#FF6B00',
|
||||
decorationVisible: true,
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
format1(val) {
|
||||
return val
|
||||
},
|
||||
format2(val) {
|
||||
return `${val}%`
|
||||
},
|
||||
handleRangeChange(e) {
|
||||
this.rangeValue = e
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.demo-slider-range {
|
||||
background-color: #fff;
|
||||
padding: 100rpx 40rpx 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
padding: 0 0 20rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.slider-item:not(:last-child) {
|
||||
margin-bottom: 100rpx;
|
||||
}
|
||||
</style>
|
||||
@ -73,6 +73,7 @@
|
||||
"urlCheck" : false
|
||||
},
|
||||
"usingComponents" : true,
|
||||
"lazyCodeLoading" : "requiredComponents",
|
||||
"requiredPrivateInfos" : [ "getLocation", "chooseLocation" ],
|
||||
"permission" : {
|
||||
"scope.userLocation" : {
|
||||
|
||||
@ -122,13 +122,8 @@ import {
|
||||
menuButtonInfo,
|
||||
} from "../../../utils/index";
|
||||
import { apiArr } from "../../../api/reservation";
|
||||
import SliderRange from "@/components/primewind-sliderrange/components/primewind-sliderrange/index.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
// 注册组件
|
||||
SliderRange,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bannerList: [
|
||||
@ -224,7 +219,6 @@ export default {
|
||||
max: this.maxPrice || 99999,
|
||||
},
|
||||
};
|
||||
console.log("筛选条件:", filterData);
|
||||
this.showPrice = false;
|
||||
},
|
||||
},
|
||||
|
||||
@ -68,12 +68,10 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uImage from "../../../uni_modules/uview-ui/components/u--image/u--image.vue";
|
||||
import { picUrl, NavgateTo, request } from "../../../utils";
|
||||
import { apiArr } from "../../../api/afterSale";
|
||||
|
||||
export default {
|
||||
components: { uImage },
|
||||
data() {
|
||||
return {
|
||||
// 评分数据
|
||||
|
||||
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 21 KiB |
@ -1,47 +0,0 @@
|
||||
<template>
|
||||
<uvImage
|
||||
:src="src"
|
||||
:mode="mode"
|
||||
:width="width"
|
||||
:height="height"
|
||||
:shape="shape"
|
||||
:radius="radius"
|
||||
:lazyLoad="lazyLoad"
|
||||
:showMenuByLongpress="showMenuByLongpress"
|
||||
:loadingIcon="loadingIcon"
|
||||
:errorIcon="errorIcon"
|
||||
:showLoading="showLoading"
|
||||
:showError="showError"
|
||||
:fade="fade"
|
||||
:webp="webp"
|
||||
:duration="duration"
|
||||
:bgColor="bgColor"
|
||||
:customStyle="customStyle"
|
||||
@click="$emit('click')"
|
||||
@error="$emit('error')"
|
||||
@load="$emit('load')"
|
||||
>
|
||||
<template v-slot:loading>
|
||||
<slot name="loading"></slot>
|
||||
</template>
|
||||
<template v-slot:error>
|
||||
<slot name="error"></slot>
|
||||
</template>
|
||||
</uvImage>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* 此组件存在的理由是,在nvue下,u-image被uni-app官方占用了,u-image在nvue中相当于image组件
|
||||
* 所以在nvue下,取名为u--image,内部其实还是u-iamge.vue,只不过做一层中转
|
||||
*/
|
||||
import uvImage from '../u-image/u-image.vue';
|
||||
import props from '../u-image/props.js';
|
||||
export default {
|
||||
name: 'u--image',
|
||||
mixins: [uni.$u.mpMixin, props, uni.$u.mixin],
|
||||
components: {
|
||||
uvImage
|
||||
},
|
||||
}
|
||||
</script>
|
||||