camera.vue 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. <script setup lang="ts">
  2. import Camera from '@/assets/camera.html?url';
  3. import { DEFAULT_HEIGHT, DEFAULT_WIDTH, DEFAULT_ZOOM } from '@/modules/camera/camera.config';
  4. const {
  5. preview = true,
  6. scale = 1,
  7. offsetX = 0,
  8. offsetY = 0,
  9. } = defineProps<{
  10. scale?: number;
  11. offsetX?: number;
  12. offsetY?: number;
  13. preview?: boolean;
  14. }>();
  15. const emits = defineEmits<{ loaded: [] }>();
  16. const style = computed(() => `width: ${scale * DEFAULT_WIDTH}px;height: ${scale * DEFAULT_HEIGHT}px;`);
  17. const snapshot = ref<string | void>();
  18. const cameraFrameRef = useTemplateRef<
  19. HTMLIFrameElement & {
  20. contentWindow: {
  21. loadCamera(props: { width: number; height: number; zoom?: number }): Promise<void>;
  22. handle(promise?: Promise<void>): string;
  23. };
  24. }
  25. >('camera-frame');
  26. const loadCamera = async () => {
  27. await cameraFrameRef.value?.contentWindow.loadCamera?.({
  28. width: DEFAULT_WIDTH,
  29. height: DEFAULT_HEIGHT,
  30. zoom: DEFAULT_ZOOM,
  31. });
  32. cameraFrameRef.value?.contentWindow.addEventListener('resize', update);
  33. emits('loaded');
  34. };
  35. watch([() => offsetX, () => offsetY], () => { setTimeout(update, 100); });
  36. function update() {
  37. cameraFrameRef.value?.contentWindow.updateCoordinate?.(offsetX, offsetY);
  38. }
  39. defineExpose({
  40. handle() {
  41. if ( !preview || !snapshot.value ) {
  42. snapshot.value = cameraFrameRef.value?.contentWindow.handle?.();
  43. } else {
  44. snapshot.value = void 0;
  45. }
  46. return snapshot.value;
  47. },
  48. });
  49. </script>
  50. <template>
  51. <div class="relative camera-container" :style="style">
  52. <iframe ref="camera-frame" :src="Camera" @load="loadCamera()"></iframe>
  53. <img v-if="snapshot" :src="snapshot" alt="图像" />
  54. <slot name="shade" :style="style" :scale="scale"></slot>
  55. </div>
  56. </template>
  57. <style scoped lang="scss">
  58. .camera-container {
  59. iframe {
  60. clip-path: url('#shade');
  61. }
  62. img {
  63. object-fit: scale-down;
  64. }
  65. > * {
  66. position: absolute;
  67. width: 100%;
  68. height: 100%;
  69. }
  70. }
  71. </style>