效果圖

使用示例
<script setup lang="ts">
import RotatedImage from "**/RotatedImage.vue";
import { ref } from "vue";
const value = ref(50);
const clockwise = ref(true);
const src = ref(
"https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel1.jpeg"
);
</script>
<template>
<section>
<n-radio-group v-model:value="clockwise" name="radiogroup">
<n-space>
<n-radio :value="true"> 順時針 </n-radio>
<n-radio :value="false"> 逆時針 </n-radio>
</n-space>
</n-radio-group>
<n-radio-group v-model:value="src" name="radiogroup">
<n-space>
<n-radio
value="https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel1.jpeg"
>
圖1
</n-radio>
<n-radio
value="https://naive-ui.oss-cn-beijing.aliyuncs.com/carousel-img/carousel2.jpeg"
>
圖2
</n-radio>
</n-space>
</n-radio-group>
<n-slider v-model:value="value" />
<RotatedImage :clockwise="clockwise" :width="value + '%'" :src="src" />
ewrwrwrwrwrwrwrwrwrwrwrwrwrwrwrer割讓給rr割讓給weeeeeeeeeeeue隔熱隔熱eeeeeeregregious
</section>
</template>
<style scoped lang="scss">
section {
margin: 50px;
width: 600px;
height: 800px;
border: 1px solid;
font-size: 51px;
word-wrap: break-word;
.rotated-image {
float: left;
clear: both;
}
}
</style>
RotatedImage.vue
<script setup lang="ts">
import { onUnmounted, ref, watch } from "vue";
interface Props {
src: string;
/** 旋轉後圖片的寬度 */
width?: number | string;
/** 旋轉後圖片的高度 */
height?: number | string;
/** 順時針旋轉 */
clockwise?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
clockwise: true,
});
const divRef = ref<HTMLDivElement>();
let img: HTMLImageElement;
function setDivDimensions(width?: string | number, height?: string | number) {
const div = divRef.value!;
if (width) {
if (typeof width === "number") div.style.width = `${width}px`;
else div.style.width = width;
}
if (height) {
if (typeof height === "number") div.style.height = `${height}px`;
else div.style.height = height;
}
}
watch(
() => props,
({ width, height }) => {
requestAnimationFrame(() => {
setDivDimensions(width, height);
rect();
});
},
{ immediate: true, deep: true }
);
function rect() {
const div = divRef.value!;
if (!img || !div) return;
const { naturalWidth, naturalHeight } = img;
const aspectRatio = naturalWidth / naturalHeight;
let width, height;
if (props.width || props.height) {
const rect = div.getBoundingClientRect();
const targetWidth = rect.width;
const targetHeight = rect.height;
if (props.width && props.height) {
width = targetWidth;
height = targetHeight;
} else if (props.width) {
width = targetWidth;
height = targetWidth * aspectRatio;
} else if (props.height) {
width = targetHeight / aspectRatio;
height = targetHeight;
}
} else {
width = naturalHeight;
height = naturalWidth;
}
setDivDimensions(props.width || width, props.height || height);
img.style.width = height + "px";
img.style.height = width + "px";
rotated();
}
function rotated() {
const { width, height } = divRef.value!.getBoundingClientRect();
img.style.width = height + "px";
img.style.height = width + "px";
if (props.clockwise) {
img.style.transformOrigin = "left top";
img.style.transform = `translate(${width}px, 0px) rotate(90deg)`;
} else {
img.style.transformOrigin = "right top";
img.style.transform = `translate(${-height}px, 0px) rotate(-90deg)`;
}
}
function load(event: Event) {
if (event.target instanceof HTMLImageElement) {
img = event.target;
rect();
}
}
const observe = new ResizeObserver(rect);
requestAnimationFrame(() => observe.observe(divRef.value!));
onUnmounted(() => {
observe.disconnect();
});
</script>
<template>
<div ref="divRef" class="rotated-image">
<img :src="src" @load="load" />
</div>
</template>
<style scoped lang="scss">
.rotated-image {
display: inline-block;
}
</style>