一个高效、灵活的图片 Vue
组件,自动实现图片懒加载功能,并能按需适配云厂商的图片处理功能。
npm
安装:
~ npm install @robot-img/vue-img
使用不同云厂商的图片处理功能按需使用图片,已有图片处理函数参考:
也可以通过
createSrcTplFactory
快速创建一个全局图片处理函数
import './index.css'
import { createApp, defineComponent, provide } from 'vue'
import {
checkWebpSupported,
createImgPool,
createSrcTplFactory,
createSrcTplOfAliOss,
createSrcTplOfKSYunKS3,
createSrcTplOfTencent,
ImgDiv,
} from '@robot-img/vue-img'
async function main() {
// 判断浏览器是否支持 webp 格式图片
const webp = await checkWebpSupported()
// 阿里云,参考:https://help.aliyun.com/document_detail/44688.html
const imgPoolAliOss = createImgPool({
createSrcTpl: createSrcTplOfAliOss({
webp,
}),
globalVars: {
className: 'cloud-img',
},
})
// 可以用这个方法加一个默认样式,当然自行增加也是 OK 的
/**
* 根据 globalVars.className 设置一个全局默认样式
* 默认样式为:
* ```
* .${globalVars.className} {
* transition: background-image .3s;
* background-size: cover;
* background-position: center;
* background-repeat: no-repeat;
* }
* span.${globalVars.className} {
* display: inline-block;
* }
* ```
*/
imgPoolAliOss.appendDefaultStyle()
const ExampleAliOss = defineComponent({
components: {
'robot-img': ImgDiv,
},
setup() {
provide('imgPool', imgPoolAliOss)
return () => <robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
},
})
// 金山云,详见:https://docs.ksyun.com/documents/886
const imgPoolK3S = createImgPool({
createSrcTpl: createSrcTplOfKSYunKS3({
webp,
}),
globalVars: {
className: 'cloud-img',
},
})
const ExampleK3S = defineComponent({
components: {
'robot-img': ImgDiv,
},
setup() {
provide('imgPool', imgPoolK3S)
return () => <robot-img src="//ks3-cn-beijing.ksyun.com/ks3-resources/suiyi.jpg" />
},
})
// 腾讯云,详见:https://cloud.tencent.com/document/product/460/36541
const imgPoolTencent = createImgPool({
createSrcTpl: createSrcTplOfTencent({
webp,
}),
globalVars: {
className: 'cloud-img',
},
})
const ExampleTencent = defineComponent({
components: {
'robot-img': ImgDiv,
},
setup() {
provide('imgPool', imgPoolTencent)
return () => (
<robot-img src="//examples-1251000004.cos.ap-shanghai.myqcloud.com/sample.jpeg" />
)
},
})
// 自定义,以腾讯云为基础,比如自定义 webp 格式的质量
const createCustomSrcTpl = createSrcTplFactory((globalVars) => ({ rect, src }) => {
const configs: string[] = []
if (rect.width && rect.height) {
const w = Math.floor(globalVars.ratio * rect.width)
const h = Math.floor(globalVars.ratio * rect.height)
configs.push(`1/w/${w}/h/${h}`)
}
if (globalVars.webp) {
configs.push('format/webp/quality/90')
}
if (configs.length < 1) {
return src
}
return `${src}?imageView2/${configs.join('/')}`
})
const imgPoolCustom = createImgPool({
createSrcTpl: createCustomSrcTpl({
webp,
}),
globalVars: {
className: 'cloud-img',
},
})
const ExampleCustom = defineComponent({
components: {
'robot-img': ImgDiv,
},
setup() {
provide('imgPool', imgPoolCustom)
return () => (
<robot-img src="//examples-1251000004.cos.ap-shanghai.myqcloud.com/sample.jpeg" />
)
},
})
const App = defineComponent({
components: {
'example-ali-oss': ExampleAliOss,
'example-k3s': ExampleK3S,
'example-tencent': ExampleTencent,
'example-custom': ExampleCustom,
},
render() {
return (
<div>
<p>阿里云:</p>
<example-ali-oss />
<p>金山云:</p>
<example-k3s />
<p>腾讯云:</p>
<example-tencent />
<p>自定义:</p>
<example-custom />
</div>
)
},
})
createApp(App).mount(document.getElementById('10-recommend')!)
}
main()
当不进行任何设置时,组件将只有懒加载
功能
import { createApp, defineComponent } from 'vue'
import { Img } from '@robot-img/vue-img'
const App = defineComponent({
components: {
'robot-img': Img,
},
setup() {
return () => (
<robot-img width="150" src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
)
},
})
createApp(App).mount(document.getElementById('20-default')!)
import './index.css'
import { createApp, defineComponent, provide } from 'vue'
import {
checkWebpSupported,
createImgPool,
createSrcTplOfAliOss,
ImgDiv,
ImgSrcTplPropFn,
} from '@robot-img/vue-img'
async function main() {
// 判断浏览器是否支持 webp 格式图片
const webp = await checkWebpSupported()
// 阿里云,参考:https://help.aliyun.com/document_detail/44688.html
const imgPoolAliOss = createImgPool({
createSrcTpl: createSrcTplOfAliOss({
webp,
}),
globalVars: {
className: 'tpl-img',
},
})
imgPoolAliOss.appendDefaultStyle()
const App = defineComponent({
components: {
'robot-img': ImgDiv,
},
setup() {
provide('imgPool', imgPoolAliOss)
const srcTpl: ImgSrcTplPropFn = ({ src, ratioWidth, ratioHeight, webp }) =>
`${src}?x-oss-process=image/resize,m_lfit,w_${ratioWidth},h_${ratioHeight}${
webp ? '/format,webp' : ''
}/blur,r_3,s_2`
return () => (
<robot-img srcTpl={srcTpl} src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
)
},
})
createApp(App).mount(document.getElementById('40-tpl')!)
}
main()
import './index.css'
import { createApp, defineComponent } from 'vue'
import { checkWebpSupported, createSrcTplOfAliOss, ImgContainer, ImgDiv } from '@robot-img/vue-img'
async function main() {
// 判断浏览器是否支持 webp 格式图片
const webp = await checkWebpSupported()
const App = defineComponent({
components: {
'robot-img': ImgDiv,
container: ImgContainer,
},
setup() {
const createSrcTpl = createSrcTplOfAliOss({
webp,
})
const globalVars = {
className: 'container-img',
}
return () => (
<container class="demo-container" createSrcTpl={createSrcTpl} globalVars={globalVars}>
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
<robot-img src="//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg" />
</container>
)
},
})
createApp(App).mount(document.getElementById('50-container')!)
}
main()
图片组件会根据图片的面积自动适应,默认的判断方法:
function defaultShouldUpdate(newRect: DOMRect, oldRect: DOMRect) {
// 当 width or height 变大 20% 时,才更新图片
return newRect.width > oldRect.width * 1.2 || newRect.height > oldRect.height * 1.2
}
也可以通过给组件传 shouldUpdate
来定义图片是否需要更新,也可以通过
imgPool.reset({
globalVars: { shouldUpdate: (newRect, oldRect) => true }
})
设置全家默认的 shouldUpdate
。
import './index.css'
import { createApp, defineComponent, reactive } from 'vue'
import {
checkWebpSupported,
createImgPool,
createSrcTplOfAliOss,
ImgProps,
useImg,
} from '@robot-img/vue-img'
async function main() {
// 阿里云,参考:https://help.aliyun.com/document_detail/44688.html
const imgPoolAliOss = createImgPool({
createSrcTpl: createSrcTplOfAliOss({
webp: await checkWebpSupported(),
}),
globalVars: {
className: 'resize-img-example',
},
})
const ImgDiv = defineComponent({
setup() {
const props = reactive<ImgProps>({
src: '//image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg',
lazy: 'resize',
})
const { state, domRef, domProps } = useImg<HTMLDivElement>(props)
const ratio = reactive({
value: 1,
})
const handleAdd = () => {
ratio.value = Math.min(3, ratio.value * 1.05)
}
const handleCut = () => {
ratio.value = ratio.value * 0.95
}
return () => {
let backgroundImage
if (state.src) {
backgroundImage = `url(${state.src})`
}
const style = {
backgroundImage,
width: `${100 * ratio.value}px`,
height: `${80 * ratio.value}px`,
}
return (
<>
<p>
<button onClick={handleAdd}>宽高变大10%</button>
<button onClick={handleCut}>宽高变小10%</button>
</p>
<div {...domProps} ref={domRef} style={style} />
<p>current src: ${state.src}</p>
</>
)
}
},
})
const App = defineComponent({
components: {
'robot-img': ImgDiv,
},
provide: {
imgPool: imgPoolAliOss,
},
setup() {
return () => (
<div class="example-resize">
<robot-img />
</div>
)
},
})
createApp(App).mount(document.getElementById('60-resize')!)
}
main()