vr图片展示
1.安装
npm install pannellum
2.组件
view-vr.vue
<template>
<div class="vr-player-container">
<!-- 加载状态 -->
<div v-if="loading" class="loading-overlay">
<div class="spinner"></div>
<p>加载全景图中...</p>
</div>
<!-- 全景图容器 -->
<div ref="imgpanoramaContainer" class="panorama-container"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, watch } from 'vue';
import 'pannellum/build/pannellum.css';
const props = defineProps({
imageUrl: {
type: String,
required: true
},
initialView: {
type: Object,
default: () => ({
hfov: 110,
pitch: 0,
yaw: 0,
autoRotate: 0
})
},
showControls: {
type: Boolean,
default: true
}
});
const imgpanoramaContainer = ref(null);
const viewer = ref(null);
const loading = ref(true);
//const autoRotate = ref(props.initialView.autoRotate !== 0);
// 动态加载 Pannellum
const loadPannellum = async () => {
try {
// 先加载 CSS
await import('pannellum/build/pannellum.css');
// 再加载 JS 并返回全局对象
await import('pannellum');
return window.pannellum;
} catch (error) {
console.error('加载 Pannellum 失败:', error);
throw error;
}
};
// 初始化全景图
const initPanorama = async () => {
if (!imgpanoramaContainer.value) return;
try {
loading.value = true;
const pannellum = await loadPannellum();
viewer.value = pannellum.viewer(imgpanoramaContainer.value, {
type: 'equirectangular',
panorama: props.imageUrl,
autoLoad: true,
});
viewer.value.on('load', () => {
loading.value = false;
})
viewer.value.on('error', (err) => {
console.error('全景图加载错误:', err);
loading.value = false;
})
} catch (error) {
console.error('初始化全景图失败:', error);
loading.value = false;
}
};
// 生命周期钩子
onMounted(() => {
initPanorama();
});
onUnmounted(() => {
if (viewer.value) {
viewer.value.destroy();
viewer.value = null;
}
});
// 监听图片 URL 变化
watch(() => props.imageUrl, (newUrl) => {
if (viewer.value && newUrl) {
loading.value = true;
viewer.value.loadScene({
type: 'equirectangular',
panorama: newUrl
});
viewer.value.setHfov(props.initialView.hfov);
viewer.value.setPitch(props.initialView.pitch);
viewer.value.setYaw(props.initialView.yaw);
viewer.value.setAutoRotate(props.initialView.autoRotate);
setTimeout(() => {
loading.value = false;
}, 1000);
}
});
</script>
<style scoped>
.vr-player-container {
position: relative;
width: 100%;
height: 500px;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
.panorama-container {
width: 100%;
height: 100%;
}
.loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 10;
color: white;
}
.spinner {
width: 50px;
height: 50px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: #fff;
animation: spin 1s linear infinite;
margin-bottom: 15px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.control-panel {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 10px;
z-index: 5;
background-color: rgba(0, 0, 0, 0.5);
padding: 8px 15px;
border-radius: 25px;
}
.control-button {
background-color: rgba(255, 255, 255, 0.2);
border: none;
color: white;
width: 35px;
height: 35px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: background-color 0.3s;
font-size: 14px;
}
.control-button:hover {
background-color: rgba(255, 255, 255, 0.4);
}
.zoom-controls {
display: flex;
gap: 5px;
}
</style>
3.使用
import PannellumViewer from './components/view-vr.vue'
<div style="width:600px;height:300px">
<PannellumViewer
:imageUrl="panoramaUrl"
:initialView="{ hfov: 100, pitch: 0, yaw: 0, autoRotate: 1 }"
:showControls="true"
/>
</div>
<script setup>
import PannellumViewer from './components/view-vr.vue'
const panoramaUrl = 'https://pannellum.org/images/alma.jpg'
</script>

浙公网安备 33010602011771号