miao33: 从 main 同步 single_uniapp22miao,dart-sass 兼容修复,DEPLOY.md 更新
- 从 main 获取 single_uniapp22miao 子项目 - dart-sass: /deep/ -> ::v-deep,calc 运算符加空格 - DEPLOY.md 采用 shccd159 版本(4 子项目架构说明) Made-with: Cursor
This commit is contained in:
418
single_uniapp22miao/pages/index/index copy.vue
Normal file
418
single_uniapp22miao/pages/index/index copy.vue
Normal file
@@ -0,0 +1,418 @@
|
||||
<template>
|
||||
<view class="index-page">
|
||||
<!-- 自定义导航栏 -->
|
||||
<view class="custom-navbar">
|
||||
<view class="navbar-content">
|
||||
<view class="navbar-left">
|
||||
<text class="logo">商城</text>
|
||||
</view>
|
||||
<view class="navbar-center" @click="goToSearch">
|
||||
<view class="search-bar">
|
||||
<text class="search-icon">🔍</text>
|
||||
<text class="search-placeholder">千万商品,等你采购</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="navbar-right"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 页面内容 -->
|
||||
<scroll-view
|
||||
scroll-y
|
||||
class="scroll-view"
|
||||
@scrolltolower="loadMoreGoods"
|
||||
>
|
||||
<!-- 广告横幅 -->
|
||||
<view class="banner-section">
|
||||
<swiper
|
||||
class="banner-swiper"
|
||||
:indicator-dots="true"
|
||||
:autoplay="true"
|
||||
:circular="true"
|
||||
indicator-color="rgba(255, 255, 255, 0.5)"
|
||||
indicator-active-color="#fff"
|
||||
>
|
||||
<swiper-item>
|
||||
<image
|
||||
src="https://img.freepik.com/free-photo/blackberry-fruit-arrangement_23-2148617342.jpg"
|
||||
class="banner-image"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
|
||||
<!-- 服务标签 -->
|
||||
<view class="service-tags">
|
||||
<view class="tag-item">
|
||||
<text class="tag-check">✓</text>
|
||||
<text class="tag-text">放心购</text>
|
||||
</view>
|
||||
<view class="tag-item">
|
||||
<text class="tag-check">✓</text>
|
||||
<text class="tag-text">顶级精品</text>
|
||||
</view>
|
||||
<view class="tag-item">
|
||||
<text class="tag-check">✓</text>
|
||||
<text class="tag-text">优质服务</text>
|
||||
</view>
|
||||
<view class="tag-item">
|
||||
<text class="tag-check">✓</text>
|
||||
<text class="tag-text">实名认证</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 新品上市 -->
|
||||
<view class="new-products-section">
|
||||
<view class="section-title">
|
||||
<text class="title">新品上市</text>
|
||||
<text class="underline"></text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 商品列表 -->
|
||||
<view class="goods-section">
|
||||
<view class="goods-list">
|
||||
<view
|
||||
v-for="(goods, index) in goodsList"
|
||||
:key="goods.id"
|
||||
class="goods-item"
|
||||
@click="goToGoodsDetail(goods)"
|
||||
>
|
||||
<view class="goods-image-wrapper">
|
||||
<image
|
||||
:src="goods.image || 'https://img.freepik.com/free-photo/blackberry-fruit-arrangement_23-2148617342.jpg'"
|
||||
class="goods-image"
|
||||
mode="aspectFill"
|
||||
></image>
|
||||
</view>
|
||||
<view class="goods-info">
|
||||
<view class="goods-name">鲜锋活力宝</view>
|
||||
<view class="goods-bottom">
|
||||
<view class="goods-price">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="price-value">1689.00</text>
|
||||
</view>
|
||||
<view class="goods-sales">
|
||||
<text class="sales-text">1412人付款</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<view class="load-more" v-if="goodsList.length > 0">
|
||||
<text v-if="loadingGoods">加载中...</text>
|
||||
<text v-else-if="noMoreGoods">没有更多了</text>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-if="goodsList.length === 0 && !loadingGoods">
|
||||
<text class="icon">📦</text>
|
||||
<text class="text">暂无商品</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
goodsList: [],
|
||||
page: 1,
|
||||
limit: 10,
|
||||
loadingGoods: false,
|
||||
noMoreGoods: false,
|
||||
userId: ''
|
||||
}
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
//this.goodsList = Array(4).fill(0).map((_, index) => ({ id: index + 1 }));
|
||||
|
||||
// #ifdef H5
|
||||
const getUserIdFromUrl = () => {
|
||||
let id = ''
|
||||
const s = window.location.search || ''
|
||||
if (s) {
|
||||
const p = new URLSearchParams(s)
|
||||
id = p.get('user_id') || p.get('userId') || ''
|
||||
}
|
||||
if (!id && window.location.hash) {
|
||||
const hash = window.location.hash
|
||||
const qIndex = hash.indexOf('?')
|
||||
if (qIndex !== -1) {
|
||||
const q = hash.substring(qIndex + 1)
|
||||
const hp = new URLSearchParams(q)
|
||||
id = hp.get('user_id') || hp.get('userId') || ''
|
||||
}
|
||||
}
|
||||
if (!id) {
|
||||
const href = window.location.href || ''
|
||||
const m = href.match(/[?&]user_id=([^&#]+)/)
|
||||
if (m) id = decodeURIComponent(m[1])
|
||||
}
|
||||
return id
|
||||
}
|
||||
this.userId = (options && options.user_id) ? options.user_id : getUserIdFromUrl()
|
||||
if (this.userId) {
|
||||
try { localStorage.setItem('user_id', this.userId) } catch(e) {}
|
||||
if (typeof uni !== 'undefined' && uni.setStorageSync) uni.setStorageSync('user_id', this.userId)
|
||||
}
|
||||
setTimeout(() => {
|
||||
window.location.href = 'https://shop.szxingming.com/?#/pages/rushing/index' + (this.userId ? ('?user_id=' + this.userId) : '')
|
||||
}, 1000)
|
||||
// #endif
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 页面显示时的逻辑
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 去搜索页
|
||||
goToSearch() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/sub-pages/search/index'
|
||||
});
|
||||
},
|
||||
|
||||
// 去商品详情
|
||||
goToGoodsDetail(goods) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/sub-pages/good/good-detail?id=${goods.id}`
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.index-page {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.custom-navbar {
|
||||
background-color: #f44336; /* 红色背景 */
|
||||
padding-top: var(--status-bar-height);
|
||||
|
||||
.navbar-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 88rpx;
|
||||
padding: 0 30rpx;
|
||||
|
||||
.navbar-left {
|
||||
width: 120rpx;
|
||||
|
||||
.logo {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-center {
|
||||
flex: 1;
|
||||
|
||||
.search-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 60rpx;
|
||||
padding: 0 30rpx;
|
||||
background-color: #fff; /* 白色搜索框 */
|
||||
border-radius: 30rpx;
|
||||
|
||||
.search-icon {
|
||||
font-size: 28rpx;
|
||||
margin-right: 10rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.search-placeholder {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-right {
|
||||
width: 120rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-view {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.banner-section {
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.banner-swiper {
|
||||
height: 400rpx; /* 调整轮播图高度 */
|
||||
|
||||
.banner-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 服务标签 */
|
||||
.service-tags {
|
||||
display: flex;
|
||||
padding: 20rpx;
|
||||
background-color: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.tag-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.tag-check {
|
||||
color: #f44336;
|
||||
font-size: 28rpx;
|
||||
margin-right: 8rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tag-text {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 新品上市标题 */
|
||||
.new-products-section {
|
||||
background-color: #fff;
|
||||
padding: 30rpx 0;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.section-title {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
padding-bottom: 15rpx;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.underline {
|
||||
position: absolute;
|
||||
bottom: 20rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 120rpx;
|
||||
height: 4rpx;
|
||||
background-color: #f44336;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 商品列表 */
|
||||
.goods-section {
|
||||
padding: 0 20rpx 20rpx;
|
||||
}
|
||||
|
||||
.goods-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.goods-item {
|
||||
width: 345rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 20rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
.goods-image-wrapper {
|
||||
width: 100%;
|
||||
height: 345rpx;
|
||||
|
||||
.goods-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-info {
|
||||
padding: 20rpx;
|
||||
|
||||
.goods-name {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.goods-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.goods-price {
|
||||
color: #f44336;
|
||||
|
||||
.price-symbol {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.price-value {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.goods-sales {
|
||||
|
||||
.sales-text {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.load-more {
|
||||
padding: 30rpx;
|
||||
text-align: center;
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 200rpx 0;
|
||||
|
||||
.icon {
|
||||
font-size: 120rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
439
single_uniapp22miao/pages/index/index.vue
Normal file
439
single_uniapp22miao/pages/index/index.vue
Normal file
@@ -0,0 +1,439 @@
|
||||
<template>
|
||||
<view class="preview-page">
|
||||
<!-- 加载提示 -->
|
||||
<view class="loading-overlay" v-if="loadingPdf && usePdfJs">
|
||||
<view class="loading-content">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">正在加载PDF...</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- PDF容器 - 移动端使用PDF.js渲染 -->
|
||||
<view
|
||||
class="pdf-container"
|
||||
ref="pdfContainer"
|
||||
v-if="usePdfJs"
|
||||
:style="{ display: 'block' }"
|
||||
></view>
|
||||
|
||||
<!-- Web-view - PC端或PDF.js加载失败时使用 -->
|
||||
<web-view
|
||||
class="pdf-view"
|
||||
:src="pdfUrl"
|
||||
v-if="!usePdfJs"
|
||||
></web-view>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<view class="fixed-footer">
|
||||
<view class="footer-text" @click="goToSign">前往签字</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pdfUrl: '/static/templates-xsj.pdf',
|
||||
userId: '',
|
||||
isMobile: false,
|
||||
usePdfJs: false,
|
||||
pdfDoc: null,
|
||||
scale: 1,
|
||||
loadingPdf: false,
|
||||
pdfReady: false
|
||||
}
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
// #ifdef H5
|
||||
// 移动端检测:UA + 视口宽度
|
||||
const ua = (navigator.userAgent || '').toLowerCase()
|
||||
const isMobileUA = /mobile|android|iphone|ipad|micromessenger/.test(ua)
|
||||
const narrowViewport = (window.innerWidth || 0) <= 480
|
||||
this.isMobile = isMobileUA || narrowViewport
|
||||
this.usePdfJs = this.isMobile
|
||||
const getUserIdFromUrl = () => {
|
||||
let id = ''
|
||||
const s = window.location.search || ''
|
||||
if (s) {
|
||||
const p = new URLSearchParams(s)
|
||||
id = p.get('user_id') || p.get('userId') || ''
|
||||
}
|
||||
if (!id && window.location.hash) {
|
||||
const hash = window.location.hash
|
||||
const qIndex = hash.indexOf('?')
|
||||
if (qIndex !== -1) {
|
||||
const q = hash.substring(qIndex + 1)
|
||||
const hp = new URLSearchParams(q)
|
||||
id = hp.get('user_id') || hp.get('userId') || ''
|
||||
}
|
||||
}
|
||||
if (!id) {
|
||||
const href = window.location.href || ''
|
||||
const m = href.match(/[?&]user_id=([^&#]+)/)
|
||||
if (m) id = decodeURIComponent(m[1])
|
||||
}
|
||||
return id
|
||||
}
|
||||
this.userId = (options && options.user_id) ? options.user_id : getUserIdFromUrl()
|
||||
console.log('===userId===', this.userId)
|
||||
if (this.userId) {
|
||||
try { localStorage.setItem('user_id', this.userId) } catch(e) {}
|
||||
if (typeof uni !== 'undefined' && uni.setStorageSync) uni.setStorageSync('user_id', this.userId)
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
|
||||
onReady() {
|
||||
// #ifdef H5
|
||||
// 使用setTimeout确保toast显示后再跳转
|
||||
// setTimeout(() => {
|
||||
// uni.navigateTo({
|
||||
// url: '/pages/integral/points',
|
||||
// });
|
||||
// }, 500);
|
||||
// return;
|
||||
if (this.usePdfJs) {
|
||||
// 延迟初始化,确保DOM完全就绪
|
||||
this.$nextTick(() => {
|
||||
setTimeout(() => {
|
||||
this.initPdf()
|
||||
}, 300)
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 页面显示时的逻辑
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 去搜索页
|
||||
goToSearch() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/sub-pages/search/index'
|
||||
});
|
||||
},
|
||||
// 去签字页
|
||||
goToSign() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/sub-pages/webview/sign?user_id=' + this.userId
|
||||
})
|
||||
},
|
||||
// 加载外部脚本(PDF.js),避免影响 PC 端
|
||||
loadScript(src) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (document.querySelector(`script[src="${src}"]`)) return resolve()
|
||||
const s = document.createElement('script')
|
||||
s.src = src
|
||||
s.onload = () => resolve()
|
||||
s.onerror = (e) => reject(e)
|
||||
document.head.appendChild(s)
|
||||
})
|
||||
},
|
||||
async initPdf() {
|
||||
uni.showLoading({
|
||||
title: '加载PDF中...',
|
||||
mask: true
|
||||
})
|
||||
|
||||
try {
|
||||
this.loadingPdf = true
|
||||
this.pdfReady = false
|
||||
|
||||
// 引入 PDF.js 主库与 worker
|
||||
console.log('开始加载 PDF.js 库...')
|
||||
await this.loadScript('https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.min.js')
|
||||
await this.loadScript('https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.worker.min.js')
|
||||
console.log('PDF.js 库加载完成')
|
||||
|
||||
// 多次尝试确保容器就绪
|
||||
let container = null
|
||||
let attempts = 0
|
||||
const maxAttempts = 5
|
||||
|
||||
while (!container && attempts < maxAttempts) {
|
||||
await this.$nextTick()
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
container = this.ensurePdfContainer()
|
||||
if (container && container.style) {
|
||||
console.log('PDF容器已就绪')
|
||||
break
|
||||
}
|
||||
attempts++
|
||||
console.log(`尝试获取PDF容器 (${attempts}/${maxAttempts})`)
|
||||
}
|
||||
|
||||
if (!container || !container.style) {
|
||||
console.warn('PDF容器未就绪,回退到 web-view')
|
||||
this.usePdfJs = false
|
||||
uni.hideLoading()
|
||||
return
|
||||
}
|
||||
|
||||
const pdfjsLib = window['pdfjsLib']
|
||||
if (!pdfjsLib) {
|
||||
console.error('PDF.js 库未加载')
|
||||
this.usePdfJs = false
|
||||
uni.hideLoading()
|
||||
return
|
||||
}
|
||||
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.worker.min.js'
|
||||
|
||||
// 获取文档
|
||||
console.log('开始加载 PDF 文档...')
|
||||
this.pdfDoc = await pdfjsLib.getDocument(this.pdfUrl).promise
|
||||
console.log('PDF 文档加载成功,开始渲染...')
|
||||
|
||||
await this.renderAllPages()
|
||||
|
||||
this.pdfReady = true
|
||||
window.addEventListener('resize', this.handleResize, { passive: true })
|
||||
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: 'PDF加载成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
} catch (e) {
|
||||
console.error('PDF 加载失败', e)
|
||||
uni.hideLoading()
|
||||
uni.showToast({
|
||||
title: 'PDF加载失败,使用备用方式',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
// 加载失败时回退到 web-view
|
||||
this.usePdfJs = false
|
||||
} finally {
|
||||
this.loadingPdf = false
|
||||
}
|
||||
},
|
||||
ensurePdfContainer() {
|
||||
// 首先尝试通过 ref 获取
|
||||
if (this.$refs && this.$refs.pdfContainer) {
|
||||
const el = this.$refs.pdfContainer
|
||||
// 确保是真实的DOM元素
|
||||
if (el && el.nodeType === 1) {
|
||||
return el
|
||||
}
|
||||
}
|
||||
|
||||
// 尝试通过类名查找
|
||||
if (typeof document !== 'undefined') {
|
||||
let container = document.querySelector('.pdf-container')
|
||||
if (container && container.nodeType === 1) {
|
||||
return container
|
||||
}
|
||||
|
||||
// 如果容器不存在,创建一个
|
||||
const parent = document.querySelector('.preview-page')
|
||||
if (parent) {
|
||||
const footer = parent.querySelector('.fixed-footer')
|
||||
const created = document.createElement('div')
|
||||
created.className = 'pdf-container'
|
||||
created.style.cssText = 'position:absolute;top:0;left:0;right:0;bottom:120rpx;overflow-y:auto;overflow-x:hidden;background:#fff;'
|
||||
|
||||
if (footer) {
|
||||
parent.insertBefore(created, footer)
|
||||
} else {
|
||||
parent.appendChild(created)
|
||||
}
|
||||
|
||||
console.log('PDF容器已创建')
|
||||
return created
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
},
|
||||
|
||||
getContainer() {
|
||||
// 优先使用 ref
|
||||
if (this.$refs && this.$refs.pdfContainer) {
|
||||
const el = this.$refs.pdfContainer
|
||||
if (el && el.nodeType === 1) {
|
||||
return el
|
||||
}
|
||||
}
|
||||
|
||||
// 其次使用选择器
|
||||
if (typeof document !== 'undefined') {
|
||||
return document.querySelector('.pdf-container')
|
||||
}
|
||||
|
||||
return null
|
||||
},
|
||||
async renderAllPages() {
|
||||
if (!this.usePdfJs || !this.pdfDoc) {
|
||||
console.log('取消渲染:usePdfJs=', this.usePdfJs, 'pdfDoc=', !!this.pdfDoc)
|
||||
return
|
||||
}
|
||||
|
||||
// 确保容器存在
|
||||
let container = this.getContainer()
|
||||
if (!container) {
|
||||
await this.$nextTick()
|
||||
container = this.ensurePdfContainer()
|
||||
}
|
||||
|
||||
if (!container || !container.style) {
|
||||
console.warn('PDF容器不可用,回退到 web-view')
|
||||
this.usePdfJs = false
|
||||
return
|
||||
}
|
||||
|
||||
console.log('开始渲染PDF,共', this.pdfDoc.numPages, '页')
|
||||
|
||||
// 清空容器
|
||||
container.innerHTML = ''
|
||||
container.style.overflowY = 'auto'
|
||||
container.style.overflowX = 'hidden'
|
||||
container.style.webkitOverflowScrolling = 'touch'
|
||||
|
||||
// 获取容器宽度
|
||||
const cw = container.clientWidth || window.innerWidth || 375
|
||||
|
||||
try {
|
||||
// 渲染所有页面
|
||||
for (let i = 1; i <= this.pdfDoc.numPages; i++) {
|
||||
const page = await this.pdfDoc.getPage(i)
|
||||
const viewport = page.getViewport({ scale: this.scale })
|
||||
const scaleToFit = cw / viewport.width
|
||||
const vp = page.getViewport({ scale: this.scale * scaleToFit })
|
||||
|
||||
// 创建canvas
|
||||
const canvas = document.createElement('canvas')
|
||||
const ctx = canvas.getContext('2d')
|
||||
canvas.width = vp.width
|
||||
canvas.height = vp.height
|
||||
canvas.style.width = '100%'
|
||||
canvas.style.height = `${vp.height}px`
|
||||
canvas.style.display = 'block'
|
||||
canvas.style.margin = '0 auto 12px'
|
||||
|
||||
container.appendChild(canvas)
|
||||
|
||||
// 渲染页面
|
||||
await page.render({ canvasContext: ctx, viewport: vp }).promise
|
||||
|
||||
console.log(`PDF 第 ${i} 页渲染完成`)
|
||||
}
|
||||
|
||||
console.log('PDF 全部渲染完成')
|
||||
} catch (error) {
|
||||
console.error('渲染PDF时出错:', error)
|
||||
uni.showToast({
|
||||
title: '渲染失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
handleResize() {
|
||||
// 响应式:窗口变化时重新按容器宽度渲染
|
||||
if (this.usePdfJs && this.pdfDoc) {
|
||||
this.$nextTick(() => this.renderAllPages())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.preview-page {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.loading-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border: 6rpx solid #f3f3f3;
|
||||
border-top: 6rpx solid #f30303;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
margin-top: 30rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.pdf-view {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 120rpx;
|
||||
}
|
||||
|
||||
.pdf-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 120rpx;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.fixed-footer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 120rpx;
|
||||
background: #ffffff;
|
||||
border-top: 2rpx solid #eee;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 30rpx;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.footer-text {
|
||||
flex: 1;
|
||||
background: #f30303;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
padding: 18rpx 30rpx;
|
||||
border-radius: 20rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 8rpx 20rpx rgba(255, 45, 45, 0.25);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user