Skip to content

Commit

Permalink
refactor(image): move to script setup (#3058)
Browse files Browse the repository at this point in the history
  • Loading branch information
eiinu authored May 7, 2024
1 parent 328e3af commit 499f576
Show file tree
Hide file tree
Showing 12 changed files with 251 additions and 248 deletions.
3 changes: 2 additions & 1 deletion src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
"cName": "图片",
"desc": "图片展示",
"taro": false,
"setup": true,
"author": "yangxiaolu"
}
]
Expand Down Expand Up @@ -928,4 +929,4 @@
]
}
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`Image: load error 1`] = `
"<div class="nut-image" style="width: 100px; height: 100px;"><img class="nut-img" src="https://x" alt="" style="object-fit: fill; object-position: center;">
<!--v-if-->
<div class="nut-img-error"><svg class="nut-icon nut-icon-imageError" style="height: 20px; width: 16px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" role="presentation">
<path d="M696.43 465.25c40.61 0 73.53-32.72 73.53-73.09s-32.96-73.08-73.53-73.08-73.54 32.72-73.54 73.08 32.92 73.09 73.54 73.09zM535.74 650.62l-273.61-259.4a56.19 56.19 0 0 0-15.36 11.58l-114 119.63-6-222.77c-.73-26.82 20.84-49.41 47.67-50.14l201.77-5.44 47.34-50-250.43 6.75C119 202.33 76.33 247.17 77.78 301l7.32 271.4 4.5 166.78C91.06 793 136.05 835.47 190.2 834l176-4.75 12-.32 47.34-50 116.18-122.64z" fill="currentColor" fill-opacity="0.9"></path>,<path d="m861.71 214.8-242.83-33.86-55.09 41.46L855 263a49.05 49.05 0 0 1 41.79 55.13l-54.33 389.59-120.87-159.05A59.86 59.86 0 0 0 638.06 537l-44 33.08 65.07 86.15L603.84 698l-79.57 60.1-54.92 41.48 34.17 4.76 270.73 37.76a97.55 97.55 0 0 0 109.88-79.6 22.37 22.37 0 0 0 .65-3.44l60.53-434.16c7.44-53.32-29.95-102.62-83.6-110.1z" fill="currentColor" fill-opacity="0.9"></path>
</svg></div>
</div>"
`;
exports[`Image: loading 1`] = `
"<div class="nut-image" style="width: 100px; height: 100px;"><img class="nut-img" src="" alt="" style="object-fit: fill; object-position: center;">
<div class="nut-img-loading"><svg class="nut-icon nut-icon-image" style="height: 20px; width: 16px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" role="presentation">
<path d="M853.161 892.55H362.595l-209.433-.414a18.5 18.5 0 0 1-1.813-.092c-24.849-2.485-47.825-14.06-64.696-32.595-16.991-18.665-26.35-42.855-26.35-68.112V264.626c0-55.808 45.404-101.211 101.212-101.211H853.16c55.808 0 101.21 45.403 101.21 101.211v225.513c0 .275-.006.552-.018.826-.022.494-1.972 51.723 15.481 85.462 4.717 9.119 1.148 20.335-7.97 25.053-9.117 4.714-20.335 1.15-25.053-7.97-21.3-41.177-19.845-97.643-19.619-103.74V264.627c0-35.307-28.724-64.031-64.03-64.031H161.515c-35.308 0-64.032 28.724-64.032 64.031v526.711c0 32.755 24.321 59.958 56.718 63.62l208.431.412h490.53c35.306 0 64.03-28.725 64.03-64.032l-.382-93.677c-.105-1.75-1.587-19.548-19.55-42.5a9.548 9.548 0 0 1-.147-.19l-21.712-28.489-117.227-155.119c-.416-.55-38.995-50.852-86.272-45.534-38.335 4.315-75.955 45.164-108.79 118.132-17.615 39.141-34.65 68.269-52.082 89.046-17.607 20.986-35.68 33.52-55.251 38.317-43.423 10.638-81.05-18.995-120.887-50.373l-5.057-3.98c-46.555-36.578-68.75-28.224-158.33 59.602-7.33 7.188-19.1 7.071-26.289-.26-7.187-7.33-7.07-19.1.26-26.287 46.659-45.746 77.544-72.727 107.086-84.283 33.358-13.048 64.275-6.267 100.242 21.994l5.093 4.008c33.923 26.72 63.22 49.795 89.029 43.467 25.618-6.279 53.3-42.114 82.28-106.509 39.14-86.976 85.838-134.027 138.797-139.849 68.454-7.515 117.824 57.405 119.892 60.172l117.122 154.98 21.6 28.344c26.277 33.631 27.334 61.639 27.367 64.725l.001.128.384 94.06c.001 55.884-45.4 101.287-101.209 101.287z" fill="currentColor" fill-opacity="0.9"></path>,<path d="M312.328 446.968c-42.325 0-76.759-34.434-76.759-76.76s34.434-76.759 76.76-76.759 76.759 34.435 76.759 76.76-34.434 76.759-76.76 76.759zm0-116.34c-21.824 0-39.579 17.756-39.579 39.58s17.755 39.58 39.58 39.58 39.579-17.756 39.579-39.58-17.755-39.58-39.58-39.58z" fill="currentColor" fill-opacity="0.9"></path>
</svg></div>
<!--v-if-->
</div>"
`;
exports[`Image: render 1`] = `
"<div class="nut-image" style="width: 100px; height: 100px;"><img class="nut-img" src="//img10.360buyimg.com/ling/jfs/t1/181258/24/10385/53029/60d04978Ef21f2d42/92baeb21f907cd24.jpg" alt="" style="object-fit: fill; object-position: center;">
<!--v-if-->
<!--v-if-->
</div>"
`;
exports[`Image: render Round 1`] = `
"<div class="nut-image nut-image-round" style="width: 100px; height: 100px;"><img class="nut-img" src="//img10.360buyimg.com/ling/jfs/t1/181258/24/10385/53029/60d04978Ef21f2d42/92baeb21f907cd24.jpg" alt="" style="object-fit: fill; object-position: center;">
<!--v-if-->
<!--v-if-->
</div>"
`;
Original file line number Diff line number Diff line change
@@ -1,23 +1,12 @@
import { config, mount } from '@vue/test-utils'
import { Image as ImagePage } from '@nutui/nutui'
import { Loading, CircleClose, Image, ImageError } from '@nutui/icons-vue'
beforeAll(() => {
config.global.components = {
Loading,
CircleClose,
Image,
ImageError
}
})
import { mount } from '@vue/test-utils'
import { Image } from '@nutui/nutui'

afterAll(() => {
config.global.components = {}
})
const url = '//img10.360buyimg.com/ling/jfs/t1/181258/24/10385/53029/60d04978Ef21f2d42/92baeb21f907cd24.jpg'

test('ImagePage render', async () => {
const wrapper = mount(ImagePage, {
test('Image: render', async () => {
const wrapper = mount(Image, {
props: {
src: '//img10.360buyimg.com/ling/jfs/t1/181258/24/10385/53029/60d04978Ef21f2d42/92baeb21f907cd24.jpg',
src: url,
width: '100',
height: '100',
showLoading: false
Expand All @@ -27,8 +16,8 @@ test('ImagePage render', async () => {
expect(wrapper.html()).toMatchSnapshot()
})

test('ImagePage load error', async () => {
const wrapper = mount(ImagePage, {
test('Image: load error', async () => {
const wrapper = mount(Image, {
props: {
src: 'https://x',
width: '100',
Expand All @@ -41,8 +30,8 @@ test('ImagePage load error', async () => {
expect(wrapper.html()).toMatchSnapshot()
})

test('ImagePage loading', async () => {
const wrapper = mount(ImagePage, {
test('Image: loading', async () => {
const wrapper = mount(Image, {
props: {
src: '',
width: '100',
Expand All @@ -55,10 +44,10 @@ test('ImagePage loading', async () => {
expect(wrapper.html()).toMatchSnapshot()
})

test('ImagePage render Round', async () => {
const wrapper = mount(ImagePage, {
test('Image: render Round', async () => {
const wrapper = mount(Image, {
props: {
src: '//img10.360buyimg.com/ling/jfs/t1/181258/24/10385/53029/60d04978Ef21f2d42/92baeb21f907cd24.jpg',
src: url,
width: '100',
height: '100',
round: true
Expand Down
13 changes: 13 additions & 0 deletions src/packages/__VUE/image/doc.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,16 @@ The Image component provides a default loading failure warning and supports cust
| click | Emitted when image is clicked | event: Event |
| load | Emitted when image loaded | - |
| error | Emitted when image load failed | - |

### Types version

The component exports the following type definitions:

```js
import type {
ImageFit,
ImagePosition,
ImageProps,
ImageInstance
} from '@nutui/nutui';
```
13 changes: 13 additions & 0 deletions src/packages/__VUE/image/doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,16 @@ Image 组件提供了默认的加载失败提示,支持通过 `error` 插槽
| click | 点击图片时触发 | event: Event |
| load | 图片加载完后触发 | -- |
| error | 图片加载失败后触发 | -- |

### 类型定义 version

组件导出以下类型定义:

```js
import type {
ImageFit,
ImagePosition,
ImageProps,
ImageInstance
} from '@nutui/nutui';
```
3 changes: 3 additions & 0 deletions src/packages/__VUE/image/image.taro.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<view> Please use Image in @tarojs/components. </view>
</template>
152 changes: 152 additions & 0 deletions src/packages/__VUE/image/image.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<template>
<div :class="classes" :style="stylebox" @click="imageClick">
<img ref="imgRef" class="nut-img" :src="lazyLoad ? (show ? src : undefined) : src"
:data-src="lazyLoad ? (show ? undefined : src) : undefined" :alt="alt" :style="styles" @load="load"
@error="error" />
<div v-if="loading" class="nut-img-loading">
<slot name="loading">
<Image width="16px" height="20px" name="image"></Image>
</slot>
</div>
<div v-if="isError && !loading" class="nut-img-error">
<slot name="error">
<ImageError width="16px" height="20px" name="imageError"></ImageError>
</slot>
</div>
</div>
</template>
<script setup lang="ts">
import {
computed,
watch,
CSSProperties,
ref,
onMounted,
onBeforeUnmount
} from 'vue'
import { pxCheck } from '../../utils/pxCheck'
import { ImageFit, ImagePosition } from './types'
import { Image, ImageError } from '@nutui/icons-vue'
defineOptions({
name: 'NutImage'
})
export type ImageProps = Partial<{
src: string
fit: ImageFit
position: ImagePosition
alt: string
width: string
height: string
round: boolean
radius: string | number
showError: boolean
showLoading: boolean
lazyLoad: boolean
}>
const props = withDefaults(defineProps<ImageProps>(), {
fit: 'fill',
position: 'center',
alt: '',
width: '',
height: '',
round: false,
showError: true,
showLoading: true,
lazyLoad: false
})
const emit = defineEmits(['click', 'load', 'error'])
const loading = ref(true)
const isError = ref(false)
const classes = computed(() => {
const prefixCls = 'nut-image'
return {
[prefixCls]: true,
[`${prefixCls}-round`]: props.round
}
})
// 图片懒加载
const observer = ref<any>(null)
const show = ref(false)
const imgRef = ref(null)
const initObserver = () => {
const options = {
threshold: [0],
rootMargin: '0px'
}
observer.value = new IntersectionObserver((entires) => {
entires.forEach((item) => {
if (item.isIntersecting) {
show.value = true
observer.value.disconnect()
}
})
}, options)
imgRef.value && observer.value.observe(imgRef.value)
}
onMounted(() => {
props.lazyLoad && initObserver()
})
onBeforeUnmount(() => {
observer.value && observer.value.disconnect()
})
const stylebox = computed(() => {
let style: {
height?: string
width?: string
overflow?: string
borderRadius?: string
} = {}
if (props.width) style.width = pxCheck(props.width)
if (props.height) style.height = pxCheck(props.height)
if (props.radius !== undefined && props.radius !== null) {
style.overflow = 'hidden'
style.borderRadius = pxCheck(props.radius)
}
return style
})
const styles = computed(() => {
let styless: CSSProperties = {
objectFit: props.fit,
objectPosition: props.position
}
return styless
})
watch(
() => props.src,
() => {
isError.value = false
loading.value = true
}
)
// 图片加载
const load = () => {
isError.value = false
loading.value = false
emit('load')
}
// 图片加载失败
const error = () => {
isError.value = true
loading.value = false
emit('error')
}
const imageClick = (event: Event) => {
emit('click', event)
}
</script>
9 changes: 9 additions & 0 deletions src/packages/__VUE/image/index.taro.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Image from './image.taro.vue'
import type { ComponentPublicInstance } from 'vue'
import { withInstall } from '@/packages/utils'

withInstall(Image)

export type ImageInstance = ComponentPublicInstance & InstanceType<typeof Image>

export { Image, Image as default }
38 changes: 0 additions & 38 deletions src/packages/__VUE/image/index.taro.vue

This file was deleted.

13 changes: 13 additions & 0 deletions src/packages/__VUE/image/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Image from './image.vue'
import type { ComponentPublicInstance } from 'vue'
import { withInstall } from '@/packages/utils'

withInstall(Image)

export type { ImageProps } from './image.vue'

export type { ImageFit, ImagePosition } from './types'

export type ImageInstance = ComponentPublicInstance & InstanceType<typeof Image>

export { Image, Image as default }
Loading

0 comments on commit 499f576

Please sign in to comment.