index.vue 4.8 KB
<template>
    <view class="webview-container">
        <!-- 导航栏 -->
        <view class="nav-bar">
            <view class="nav-left" @click="handleBack">
                <view class="back-icon">←</view>
                <text class="back-text">返回</text>
            </view>
            <view class="nav-title">{{ pageTitle }}</view>
            <view class="nav-right"></view>
        </view>
        
        <!-- WebView内容 -->
        <web-view 
            v-if="webUrl" 
            :src="webUrl" 
            class="web-view"
            @message="handleMessage"
            @load="handleLoad"
            @error="handleError"
        ></web-view>
        
        <!-- 加载状态 -->
        <view v-if="loading" class="loading-container">
            <view class="loading-spinner">⏳</view>
            <view class="loading-text">加载中...</view>
        </view>
        
        <!-- 错误状态 -->
        <view v-if="error" class="error-container">
            <view class="error-icon">⚠️</view>
            <view class="error-text">页面加载失败</view>
            <nut-button type="primary" size="small" @click="handleRetry">重试</nut-button>
        </view>
    </view>
</template>

<script setup>
import { ref, onMounted } from 'vue'
import Taro from '@tarojs/taro'

/**
 * WebView页面组件
 * 用于预览外部网页链接
 */

// 页面状态
const webUrl = ref('')
const pageTitle = ref('网页预览')
const loading = ref(true)
const error = ref(false)

/**
 * 获取页面参数
 */
const getPageParams = () => {
    const instance = Taro.getCurrentInstance()
    const params = instance.router?.params || {}
    
    if (params.url) {
        webUrl.value = decodeURIComponent(params.url)
    }
    
    if (params.title) {
        pageTitle.value = decodeURIComponent(params.title)
    }
}

/**
 * 处理返回按钮点击
 */
const handleBack = () => {
    Taro.navigateBack()
}

/**
 * 处理WebView加载完成
 */
const handleLoad = (e) => {
    console.log('WebView加载完成:', e)
    loading.value = false
    error.value = false
}

/**
 * 处理WebView加载错误
 */
const handleError = (e) => {
    console.error('WebView加载错误:', e)
    loading.value = false
    error.value = true
    
    Taro.showToast({
        title: '页面加载失败',
        icon: 'none'
    })
}

/**
 * 处理WebView消息
 */
const handleMessage = (e) => {
    console.log('WebView消息:', e)
    // 可以在这里处理来自WebView的消息
}

/**
 * 重试加载
 */
const handleRetry = () => {
    loading.value = true
    error.value = false
    // 重新设置URL触发重新加载
    const currentUrl = webUrl.value
    webUrl.value = ''
    setTimeout(() => {
        webUrl.value = currentUrl
    }, 100)
}

// 页面挂载时获取参数
onMounted(() => {
    getPageParams()
    
    // 如果没有URL参数,显示错误
    if (!webUrl.value) {
        loading.value = false
        error.value = true
        Taro.showToast({
            title: '缺少URL参数',
            icon: 'none'
        })
    }
})
</script>

<script>
export default {
    name: 'WebViewPage'
}
</script>

<style lang="less">
.webview-container {
    width: 100%;
    height: 100vh;
    display: flex;
    flex-direction: column;
    background-color: #fff;
}

.nav-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 88rpx;
    padding: 0 32rpx;
    background-color: #fff;
    border-bottom: 1rpx solid #eee;
    position: sticky;
    top: 0;
    z-index: 100;
}

.nav-left {
    display: flex;
    align-items: center;
    cursor: pointer;
    
    .back-icon {
        font-size: 32rpx;
        color: #333;
        font-weight: bold;
    }
    
    .back-text {
        margin-left: 8rpx;
        font-size: 28rpx;
        color: #333;
    }
}

.nav-title {
    font-size: 32rpx;
    font-weight: 600;
    color: #333;
    text-align: center;
    flex: 1;
}

.nav-right {
    width: 80rpx;
}

.web-view {
    flex: 1;
    width: 100%;
}

.loading-container {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.loading-spinner {
    font-size: 48rpx;
    margin-bottom: 16rpx;
    animation: spin 1s linear infinite;
}

.loading-text {
    font-size: 28rpx;
    color: #666;
}

@keyframes spin {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}

.error-container {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
}

.error-icon {
    font-size: 80rpx;
    margin-bottom: 24rpx;
}

.error-text {
    font-size: 28rpx;
    color: #666;
    margin-bottom: 32rpx;
}
</style>