Merge remote-tracking branch 'origin/dev/1.0' into yuanlaide2
# Conflicts: # .local.config.js
This commit is contained in:
@@ -281,13 +281,42 @@ export default {
|
||||
.tab-bar {
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
/* ============================================================
|
||||
* 固定在最底端,不能位置漂移(微信小程序 / 鸿蒙元服务 / 快应用 H5)
|
||||
* ------------------------------------------------------------
|
||||
* 现象(只在客户端小程序里复现,浏览器 H5 没事):
|
||||
* 页面带 navigationStyle:custom + 页面内有 scroll-view,
|
||||
* 滚到底部时 .tab-bar 会被微信客户端的页面避让逻辑推上去,
|
||||
* 出现"位置漂移"。
|
||||
*
|
||||
* 根因(微信小程序特性):
|
||||
* 1) 微信小程序里 position:fixed 的 containing block 是 page
|
||||
* 根容器(不是 viewport),可视区变化时 fixed 元素下沿会
|
||||
* 跟着重算,造成漂移。
|
||||
* 2) 父级一旦出现 transform/filter/will-change,fixed 的
|
||||
* containing block 会被进一步改写,fixed 元素行为更不可控。
|
||||
*
|
||||
* 加固措施:
|
||||
* - bottom: 0 !important 钉死下沿
|
||||
* - 提升 z-index 到 2147483647,避免被其他 fixed 元素遮挡
|
||||
* - transform: translateZ(0) 强制提升到独立合成层,降低父级
|
||||
* transform 干扰;will-change:transform 提示浏览器持续合成
|
||||
* - 微信小程序里 #ifdef MP-WEIXIN / #ifdef MP-HARMONY 走原生
|
||||
* tabBar,diy-bottom-nav 通常不会同时存在,但保留兜底
|
||||
* ============================================================ */
|
||||
position: fixed !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
bottom: 0 !important;
|
||||
top: auto !important;
|
||||
width: 100%;
|
||||
z-index: 998;
|
||||
z-index: 2147483647 !important;
|
||||
display: flex;
|
||||
border-top: 2rpx solid #f5f5f5;
|
||||
/* 强制提升合成层,降低父级 transform/filter 改变 containing block 的概率 */
|
||||
transform: translateZ(0) !important;
|
||||
-webkit-transform: translateZ(0) !important;
|
||||
will-change: transform !important;
|
||||
padding-bottom: 0;
|
||||
padding-bottom: constant(safe-area-inset-bottom);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<view class="goods-img-wrap">
|
||||
<image class="goods-img"
|
||||
:src="$util.img(item.goods_image, { size: goodsValue.template == 'large-mode' ? 'big' : 'mid' })"
|
||||
mode="widthFix" @error="imgError(index)"
|
||||
:mode="imgMode" @error="imgError(index)"
|
||||
:style="{ borderRadius: goodsValue.imgAroundRadius * 2 + 'rpx' }"
|
||||
show-menu-by-longpress />
|
||||
<view class="sell-out" v-if="item.stock <= 0">
|
||||
@@ -117,7 +117,7 @@
|
||||
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||
<view class="goods-img-wrap">
|
||||
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
:src="$util.img(item.goods_image, { size: 'mid' })" mode="widthFix" @error="imgError(index)"
|
||||
:src="$util.img(item.goods_image, { size: 'mid' })" :mode="imgMode" @error="imgError(index)"
|
||||
:lazy-load="true" show-menu-by-longpress />
|
||||
<view class="sell-out" v-if="item.stock <= 0">
|
||||
<text class="iconfont icon-shuqing"></text>
|
||||
@@ -184,7 +184,7 @@
|
||||
:class="[goodsValue.ornament.type]" :style="goodsItemCss">
|
||||
<view class="goods-img-wrap">
|
||||
<image class="goods-img" :style="{ borderRadius: value.imgAroundRadius * 2 + 'rpx' }"
|
||||
:src="$util.img(dataItem.goods_image, { size: 'mid' })" mode="widthFix"
|
||||
:src="$util.img(dataItem.goods_image, { size: 'mid' })" :mode="imgMode"
|
||||
@error="imgError(dataIndex)" :lazy-load="true" show-menu-by-longpress />
|
||||
<view class="sell-out" v-if="dataItem.stock <= 0">
|
||||
<text class="iconfont icon-shuqing"></text>
|
||||
@@ -302,6 +302,19 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 商品图 image 的 mode 模式:
|
||||
// - 大图模式(large-mode):容器高度由图片决定,固定使用 widthFix 保持原比例
|
||||
// - 鸿蒙元服务:其他模板下 image 的 widthFix 模式异常(图片被裁剪/显示不全),改用 aspectFill 填满固定容器
|
||||
// - H5、微信小程序等其他环境:保持 widthFix 行为不变
|
||||
imgMode() {
|
||||
if (this.goodsValue.template == 'large-mode') return 'widthFix';
|
||||
// #ifdef MP-HARMONY
|
||||
return 'aspectFill';
|
||||
// #endif
|
||||
// #ifndef MP-HARMONY
|
||||
return 'widthFix';
|
||||
// #endif
|
||||
},
|
||||
goodsListWarpCss() {
|
||||
var obj = '';
|
||||
obj += 'background-color:' + this.goodsValue.componentBgColor + ';';
|
||||
|
||||
@@ -300,6 +300,7 @@ export default {
|
||||
handler() {
|
||||
this.diyGlobalData = this.diyData ? this.$util.deepClone(this.diyData) : null;
|
||||
this.processData();
|
||||
this._notifyLoaded();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
@@ -308,8 +309,9 @@ export default {
|
||||
this.processData();
|
||||
},
|
||||
mounted() {
|
||||
// 通知父组件 diy-group 内容已渲染完毕
|
||||
this.$emit('loaded');
|
||||
if (this.diyData && this.diyData.value) {
|
||||
this._notifyLoaded();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
topNavColor() {
|
||||
@@ -323,7 +325,6 @@ export default {
|
||||
|
||||
return topNavColor;
|
||||
},
|
||||
// 过滤组件的渲染
|
||||
diyDataArray() {
|
||||
if (!this.processedData) {
|
||||
this.processData();
|
||||
@@ -347,6 +348,12 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
_notifyLoaded() {
|
||||
if (this._loadedTimer) clearTimeout(this._loadedTimer);
|
||||
this._loadedTimer = setTimeout(() => {
|
||||
this.$emit('loaded');
|
||||
}, 300);
|
||||
},
|
||||
processData() {
|
||||
if (!this.diyGlobalData || !this.diyGlobalData.value) {
|
||||
this.processedData = [];
|
||||
|
||||
@@ -64,7 +64,9 @@
|
||||
id="myVideo"
|
||||
:src="video_url"
|
||||
:controls="true"
|
||||
object-fit="contain"
|
||||
@loadedmetadata="onPopupVideoLoaded"
|
||||
@error="onPopupVideoError"
|
||||
></video>
|
||||
</view>
|
||||
</uni-popup>
|
||||
@@ -88,11 +90,14 @@ export default {
|
||||
pageWidth: '',
|
||||
indicatorDots: false,
|
||||
swiperCurrent: 0,
|
||||
video_url: ''
|
||||
video_url: '',
|
||||
popupVideoWidth: 0,
|
||||
popupVideoHeight: 0,
|
||||
windowWidth: 0
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 组件创建时的逻辑
|
||||
this.initWindowWidth();
|
||||
},
|
||||
watch: {
|
||||
componentRefresh(newValue) {
|
||||
@@ -140,24 +145,33 @@ export default {
|
||||
// 弹窗视频容器样式
|
||||
popupVideoStyle() {
|
||||
let style = 'position:fixed;width:100%;left:0;';
|
||||
|
||||
if (this.popupVideoRatio) {
|
||||
// 根据视频比例设置位置
|
||||
if (this.popupVideoRatio === 'portrait') {
|
||||
// 竖屏视频:居中显示,使用9/16比例
|
||||
style += 'top:50%;transform:translateY(-50%);';
|
||||
style += 'aspect-ratio: 9 / 16;';
|
||||
} else {
|
||||
// 横屏视频:靠近顶部显示,使用16/9比例
|
||||
style += 'top:20%;';
|
||||
style += 'aspect-ratio: 16 / 9;';
|
||||
}
|
||||
} else {
|
||||
// 默认:居中显示,使用竖屏比例
|
||||
style += 'top:50%;transform:translateY(-50%);';
|
||||
style += 'aspect-ratio: 9 / 16;';
|
||||
const defaultRatio = 9 / 16;
|
||||
|
||||
let ratio = defaultRatio;
|
||||
if (this.popupVideoWidth && this.popupVideoHeight) {
|
||||
ratio = this.popupVideoHeight / this.popupVideoWidth;
|
||||
}
|
||||
|
||||
|
||||
const isPortrait = ratio > 1;
|
||||
|
||||
if (isPortrait) {
|
||||
style += 'top:50%;transform:translateY(-50%);';
|
||||
} else {
|
||||
style += 'top:20%;';
|
||||
}
|
||||
|
||||
// #ifdef H5
|
||||
style += 'padding-top: ' + (ratio * 100) + '%;';
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
style += 'padding-top: ' + (ratio * 100) + '%;';
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-HARMONY
|
||||
style += 'height: ' + (this.windowWidth * ratio) + 'px;';
|
||||
// #endif
|
||||
|
||||
return style;
|
||||
}
|
||||
},
|
||||
@@ -165,8 +179,8 @@ export default {
|
||||
// 显示视频播放弹窗
|
||||
showVideo(item) {
|
||||
this.video_url = item.videoUrl;
|
||||
// 重置视频比例为null,等待新的检测结果
|
||||
this.popupVideoRatio = null;
|
||||
this.popupVideoWidth = 0;
|
||||
this.popupVideoHeight = 0;
|
||||
this.$refs.videoPopup.open();
|
||||
},
|
||||
|
||||
@@ -174,6 +188,16 @@ export default {
|
||||
imgError(index) {
|
||||
// 图片加载失败的处理逻辑
|
||||
},
|
||||
|
||||
// 初始化窗口宽度
|
||||
initWindowWidth() {
|
||||
try {
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
this.windowWidth = systemInfo.windowWidth || 375;
|
||||
} catch (e) {
|
||||
this.windowWidth = 375;
|
||||
}
|
||||
},
|
||||
|
||||
// 弹窗视频加载完成事件
|
||||
onPopupVideoLoaded(event) {
|
||||
@@ -198,13 +222,24 @@ export default {
|
||||
}
|
||||
// #endif
|
||||
|
||||
// 鸿蒙元服务端:通过事件对象获取视频宽高
|
||||
// #ifdef MP-HARMONY
|
||||
if (event && event.detail) {
|
||||
width = event.detail.width || 0;
|
||||
height = event.detail.height || 0;
|
||||
}
|
||||
// #endif
|
||||
|
||||
if (width && height) {
|
||||
this.popupVideoRatio = width >= height ? 'landscape' : 'portrait';
|
||||
} else {
|
||||
// 获取失败,默认竖屏
|
||||
this.popupVideoRatio = 'portrait';
|
||||
this.popupVideoWidth = width;
|
||||
this.popupVideoHeight = height;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 弹窗视频错误事件
|
||||
onPopupVideoError(event) {
|
||||
console.error('Popup video load failed:', event);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -576,8 +611,9 @@ export default {
|
||||
|
||||
.video-container {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.adaptive-video {
|
||||
@@ -589,6 +625,22 @@ export default {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
/* #ifdef MP-WEIXIN */
|
||||
.adaptive-video {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
/* #ifdef MP-HARMONY */
|
||||
.adaptive-video {
|
||||
position: static;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
.video-nav {
|
||||
padding: 16rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -26,6 +26,23 @@
|
||||
:poster="posterUrl"
|
||||
:style="videoWarpCss"
|
||||
controls
|
||||
object-fit="cover"
|
||||
@loadedmetadata="onVideoLoaded"
|
||||
@error="onVideoError"
|
||||
></video>
|
||||
<!-- #endif -->
|
||||
|
||||
<!-- 鸿蒙元服务端使用uni-app的video组件 -->
|
||||
<!-- #ifdef MP-HARMONY -->
|
||||
<video
|
||||
ref="videoRef"
|
||||
data-component-name="diy-video"
|
||||
class="diy-video harmony-video"
|
||||
:src="videoUrl"
|
||||
:poster="posterUrl"
|
||||
:style="videoWarpCss"
|
||||
controls
|
||||
object-fit="cover"
|
||||
@loadedmetadata="onVideoLoaded"
|
||||
@error="onVideoError"
|
||||
></video>
|
||||
@@ -44,14 +61,17 @@ export default {
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
videoRatio: null, // 视频比例:'landscape'(横屏)或 'portrait'(竖屏)
|
||||
videoUrl: '',
|
||||
posterUrl: ''
|
||||
};
|
||||
},
|
||||
return {
|
||||
videoWidth: 0,
|
||||
videoHeight: 0,
|
||||
videoUrl: '',
|
||||
posterUrl: '',
|
||||
windowWidth: 0
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.initVideoData();
|
||||
this.initWindowWidth();
|
||||
},
|
||||
mixins: [DiyMinx],
|
||||
watch: {
|
||||
@@ -78,18 +98,26 @@ export default {
|
||||
// 动态计算容器比例
|
||||
containerStyle() {
|
||||
let style = '';
|
||||
const defaultRatio = 9 / 16;
|
||||
|
||||
if (this.videoRatio === 'landscape') {
|
||||
// 横屏视频:16/9比例
|
||||
style += 'aspect-ratio: 16 / 9;';
|
||||
} else if (this.videoRatio === 'portrait') {
|
||||
// 竖屏视频:9/16比例
|
||||
style += 'aspect-ratio: 9 / 16;';
|
||||
} else {
|
||||
// 未加载完成 → 默认使用竖屏比例
|
||||
style += 'aspect-ratio: 9 / 16;';
|
||||
let ratio = defaultRatio;
|
||||
if (this.videoWidth && this.videoHeight) {
|
||||
ratio = this.videoHeight / this.videoWidth;
|
||||
}
|
||||
|
||||
// #ifdef H5
|
||||
style += 'padding-top: ' + (ratio * 100) + '%;';
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
style += 'padding-top: ' + (ratio * 100) + '%;';
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-HARMONY
|
||||
style += 'width: 100%;';
|
||||
style += 'height: ' + (this.windowWidth * ratio) + 'px;';
|
||||
// #endif
|
||||
|
||||
return style;
|
||||
}
|
||||
},
|
||||
@@ -104,6 +132,16 @@ export default {
|
||||
// #endif
|
||||
},
|
||||
|
||||
// 初始化窗口宽度
|
||||
initWindowWidth() {
|
||||
try {
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
this.windowWidth = systemInfo.windowWidth || 375;
|
||||
} catch (e) {
|
||||
this.windowWidth = 375;
|
||||
}
|
||||
},
|
||||
|
||||
// 获取视频URL
|
||||
getVideoUrl() {
|
||||
if (!this.value || !this.value.videoUrl) return '';
|
||||
@@ -138,7 +176,8 @@ export default {
|
||||
const height = video.videoHeight;
|
||||
|
||||
if (width && height) {
|
||||
this.videoRatio = width >= height ? 'landscape' : 'portrait';
|
||||
this.videoWidth = width;
|
||||
this.videoHeight = height;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -169,8 +208,16 @@ export default {
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-HARMONY
|
||||
if (event && event.detail) {
|
||||
width = event.detail.width || 0;
|
||||
height = event.detail.height || 0;
|
||||
}
|
||||
// #endif
|
||||
|
||||
if (width && height) {
|
||||
this.videoRatio = width >= height ? 'landscape' : 'portrait';
|
||||
this.videoWidth = width;
|
||||
this.videoHeight = height;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -216,6 +263,11 @@ export default {
|
||||
/* H5端样式 */
|
||||
/* #ifdef H5 */
|
||||
.h5-video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
object-fit: cover;
|
||||
}
|
||||
/* #endif */
|
||||
@@ -225,6 +277,19 @@ export default {
|
||||
.mp-video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
/* #endif */
|
||||
|
||||
/* 鸿蒙元服务端样式 */
|
||||
/* #ifdef MP-HARMONY */
|
||||
.harmony-video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/* #endif */
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user