Skip to content

Commit

Permalink
feat: alioss 图片资源支持 自动剪裁 (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
lianghx-319 authored and levy9527 committed Jan 21, 2020
1 parent 50ebd9c commit 5bbff8a
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 36 deletions.
29 changes: 29 additions & 0 deletions docs/autocrop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
## 自动裁剪
如果传入 width 或 height 属性,会默认按照客户端的 devicePixelRatio(默认是 2) 获取合适大小的图片。节省流量的同时,保证图片最佳显示效果

```vue
<template>
<div>
<p> 原图 宽:400 高:267 </p>
<v-img :src="src"/>
<p> 按宽度等比缩放 宽:100 高:等比缩放<p/>
<v-img :src="src" width="100"/>
<p> 按高度等比缩放 高:100 宽:等比缩放<p/>
<v-img :src="src" height="100"/>
<p> 固定宽高剪裁,宽高:100,居中裁剪,不拉伸图片 </p>
<v-img :src="src" height="100" width="100"/>
<p> 对背景图片使用自动裁剪 </p>
<div v-img="{src}" style="width:100px;height:100px;background-repeat:no-repeat;background-size: 100% auto"></div>
</div>
</template>
<script>
export default {
data() {
return {
src: 'https://image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg'
}
}
}
</script>
```
25 changes: 20 additions & 5 deletions src/background.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,39 @@
import 'lazysizes/plugins/bgset/ls.bgset'
import providerConf from './provider-config'
import getImageSrc from './provider-config'

function getSrc(config) {
const isSupportWebp =
JSON.parse(localStorage.getItem('isSupportWebp')) || false
const {provider = 'alibaba', extraQuery, src} = config
const {
provider = 'alibaba',
extraQuery,
src,
width,
height,
autocrop = true
} = config
if (!src) {
return
}

return providerConf[provider].getSrc({
return getImageSrc({
autocrop,
provider,
src,
isSupportWebp,
extraQuery
extraQuery,
width,
height
})
}

export default {
init(el, {value = {}}) {
const src = getSrc(value)
const size = {
width: el.offsetWidth,
height: el.offsetHeight
}
const src = getSrc({...size, ...value})
el.classList.add('lazyload')
el.setAttribute('data-bgset', src)
},
Expand Down
137 changes: 118 additions & 19 deletions src/provider-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,146 @@ function is(types, src) {
return Array.isArray(types) ? types.some(t => t.test(src)) : types.test(src)
}

export default {
const srcProcess = {
CONVERT_WEBP: 'convertWebp',
CROP_IMAGE: 'cropImage',
APPEND_QUERY: 'appendQuery'
}

const pipe = function(fns) {
return function(item) {
return fns.reduce(function(prev, fn) {
if (typeof fn !== 'function') {
fn = v => v
}
return fn(prev)
}, item)
}
}

export const providerConfig = {
alibaba: {
getSrc({src, isSupportWebp, extraQuery}) {
let query = ''
[srcProcess.CONVERT_WEBP](vm) {
const {src, isSupportWebp} = vm
let query = vm.$src || ''
if (isSupportWebp && is([png, jpg], src)) query += '/format,webp'
/**
* 质量变换仅对jpg、webp有效。(png已被转为webp)
* @see https://help.aliyun.com/document_detail/44705.html?spm=a2c4g.11186623.6.1256.347d69cb9tB4ZR
*/
if (is([png, jpg, webp], src)) query += '/quality,Q_75'

vm.$src = query
return vm
},

[srcProcess.CROP_IMAGE](vm) {
const {$src = '', width, height, autocrop, src} = vm

if (!autocrop || is(svg, src) || !src) return vm
const DPR = 2
let dpr = (window && window.devicePixelRatio) || DPR
if (dpr === 1) {
dpr = DPR
}
const actions = ['/resize']
const WIDTH = `w_${width * dpr}`
const HEIGHT = `h_${height * dpr}`
const AUTOCROP = `m_fill`

if (isNaN(width) && isNaN(height)) {
return vm
}

if (!isNaN(width) && !isNaN(height)) {
actions.push(AUTOCROP)
}

if (!isNaN(height)) {
actions.push(HEIGHT)
}

if (!isNaN(width)) {
actions.push(WIDTH)
}

const resizeQuery = actions.join(',')

vm.$src = resizeQuery + $src

return vm
},

[srcProcess.APPEND_QUERY](vm) {
const {src, extraQuery} = vm
let query = vm.$src || ''
if (extraQuery) query += '/' + extraQuery
if (query) {
src +=
(src.indexOf('?') > -1 ? '&' : '?') + 'x-oss-process=image' + query
query =
src +
(src.indexOf('?') > -1 ? '&' : '?') +
'x-oss-process=image' +
query
}
return src

vm.$src = query || src
return vm
}
},
qiniu: {
getSrc({src, isSupportWebp, extraQuery}) {
[srcProcess.CONVERT_WEBP](vm) {
const {src, isSupportWebp} = vm
let query = vm.$src || ''
// imageMogr2 接口可支持处理的原图片格式有 psd、jpeg、png、gif、webp、tiff、bmp
if (is(svg, src)) return src
src += src.indexOf('?') > -1 ? '&' : '?'
src += 'imageMogr2'
if (isSupportWebp && is([png, jpg], src)) src += '/format/webp'
src += '/quality/75'
if (extraQuery) src += '/' + extraQuery
return src
if (is(svg, src)) {
return vm
}
if (isSupportWebp && is([png, jpg], src)) query += '/format/webp'
query += '/quality/75'

vm.$src = query
return vm
},

[srcProcess.APPEND_QUERY](vm) {
const {src, extraQuery} = vm
let query = vm.$src || ''
if (extraQuery) query += '/' + extraQuery
if (query) {
query = src + (src.indexOf('?') > -1 ? '&' : '?') + 'imageMogr2' + query
}

vm.$src = query || src
return vm
}
},
self: {
getSrc({src, isSupportWebp}) {
[srcProcess.CONVERT_WEBP](vm) {
const {src, isSupportWebp} = vm
if (isSupportWebp && is([png, jpg], src)) {
src = src.indexOf('?') > -1 ? src.replace('?', '.webp?') : src + '.webp'
vm.$src =
src.indexOf('?') > -1 ? src.replace('?', '.webp?') : src + '.webp'
} else {
vm.$src = src
}
return src
return vm
}
},
none: {
getSrc({src}) {
return src
[srcProcess.CONVERT_WEBP](vm) {
vm.$src = vm.src
return vm
}
}
}

export default vm => {
vm.$src = ''
const providerPipe = providerConfig[vm.provider]
const output = pipe([
providerPipe[srcProcess.CONVERT_WEBP],
providerPipe[srcProcess.CROP_IMAGE],
providerPipe[srcProcess.APPEND_QUERY]
])(vm)
return output.$src
}
12 changes: 10 additions & 2 deletions src/v-img.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</template>

<script>
import providerConfig from './provider-config'
import {providerConfig, default as getSrc} from './provider-config'
/**
* TODO:
Expand Down Expand Up @@ -92,6 +92,14 @@ export default {
error: {
type: String,
default: ''
},
/**
* 是否开启自动裁剪
*/
autocrop: {
type: Boolean,
default: true
}
},
Expand Down Expand Up @@ -142,7 +150,7 @@ export default {
}
},
imageSrc() {
return providerConfig[this.provider].getSrc(this)
return getSrc(this)
},
loadingImage() {
return this.placeholder || this.$vImg.placeholder
Expand Down
Loading

0 comments on commit 5bbff8a

Please sign in to comment.