Skip to content

Commit

Permalink
Merge pull request #17 from FEMessage/dev
Browse files Browse the repository at this point in the history
  • Loading branch information
levy9527 authored Jan 21, 2020
2 parents dc4d62b + 5bbff8a commit 77bd753
Show file tree
Hide file tree
Showing 9 changed files with 360 additions and 72 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>
```
35 changes: 35 additions & 0 deletions docs/customize.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
## 自定义 loading 和 error 时的图案有两种方法

### 注册组件时全局设置,适合全局修改
```javascript
import Vue from 'vue'
import VImg from '@femessage/v-img'

Vue.ues(VImg, {
placeholder: 'https://deepexi-moby.oss-cn-shenzhen.aliyuncs.com/femessage/bean_eater.svg',
error: 'https://deepexi-moby.oss-cn-shenzhen.aliyuncs.com/femessage/iconmonstr-refresh-6.svg'
})
```

### 使用组件时,单独给组件设置
自定义图案的使用逻辑: 组件属性设置 > 全局设置 > 默认设置

### 修改占位图的大小
load 时可以用类名 `.on-loading`, error 时可以用类名 `.on-error` 覆盖默认的样式

```vue
<template>
<div>
自定义 loading 图案 </br>
<v-img width="375" height="375" placeholder="https://deepexi-moby.oss-cn-shenzhen.aliyuncs.com/femessage/bean_eater.svg"/></br>
自定义 error 的图案 </br>
<v-img src="none" width="375" height="375" error="https://deepexi-moby.oss-cn-shenzhen.aliyuncs.com/femessage/iconmonstr-refresh-6.svg"/>
</div>
</template>
<style>
.v-img.on-loading, .v-img.on-error {
background-size: auto !important;
}
</style>
```
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
11 changes: 10 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
// Import vue component
import Component from './v-img.vue'
import background from './background'
import placeholder from './spinner.svg'

const defaultOptions = {
placeholder,
error:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFIAAABSCAMAAADw8nOpAAAArlBMVEUAAAAAAAD///9paWkyMjL////////////29vb////09PTn5+fh4eGvr6/////6+vqZmZm8vLz39/fj4+P8/PyBgYH////////////////Gxsb////////////v7+/MzMzr6+v///+4uLj////o6OhNTU3Y2NjQ0ND9/f35+fn////////////t7e3////////////////z8/Pb29v////y8vLw8PDU1NT////////ym0LiAAAAOXRSTlMaAPooH+3z2LwFtYZ5QvXUNkvDgOAul49vV1RHGRKfWZThSPiMI2pf6szLva2ahHhPQa9wIamkYyJOAjtMAAAD1ElEQVRYw8WZ6XbaMBBGp/K+L4DBxUDZQkjInpB+7/9ipSapQPKGOT69PxNzbY3Go5FMP2rIxqPkPphrjGnz4D4ZjbO6X1QqJ2liQMJI0kk7pfW8YwD0eOrOvFBRVSX0Zu401gGw3bN1sXLyqAEsdiKSiJyYAdrj5CJlNvSBoDegEga9APCHWWOl9eQDZkSVRCbgP1nNlC8GYHtUi2cDxksDpTUEjJ/UiJ8GMLTqlO93YI5KDVEdhrv3auVYR39BF7DoQx9XKVMGW6GLUGywtFw5An7RxfwCRpKSG3vUgh53CsoUeKNWvAFpkXLM+DNe/pxsLCvfdR7HNvHU30WldQebill/Pph9ben3t/b0piwfbNxZgnKIfuHVA9dc4gS2dcLCXOpjeK58AVsUCacMEuyjSLpgeDlVWgacghGvdHDqpA4M60T5BEOVi8ItStE28vtu4IkrMx9y7XEZvvBN5+2nF0Yb94Pf5UGVHgF+9k85lGdb3eMIe/1cE8f79R2MrSLP+vBbOfEhVVwTR2wpaoqjISdeizUZ/uRL+QiTBKbIMaLCxPq6n6lKz/F4VFoaIjGOX78pS2z3mKuv4noEzcqVzwjEQLPjDFAps6PzRvhzgOdcuRPLhToXjTKb/K63ilg+dn+VE8YGYtLmo6ZKboqGPmBsclCmiIUp1QCIr7zMBw6I+RwjPSgT8V184NdWoeThscUBJgelIcy3suTDruQTB4SgRTB+UAa9KEge1dPHgRWdoSOjsRjKVz6eGtx80sVgjmmE6XkG6Tzhaljnl4bCazeiBO55EucRatYfmPLdXSR0jxmdssorQsOFUX4jZrinAJ4UyqZr5SIvckI1CmguBCPAAbfZ1HD07+cKMScNipwZm1plqIFzksYKNGI4r3r5UhBRLTOcMP/3WCpYsXJB9TjcuFzQibLlwPlaIoRegdZmeniDceTjNMaYFyfRiprg+bkxWAtJVJjqduO+EtBCIdWLX0hfbebcS3F3kZSUjU0zpbrFisSyUVLc9tTQuSCpuJWUYH9A7dCRlS0U+3bGCEbpcsa8VkoHSfmiG7dSxkgrWoPpRS7eGlQ1MG6b/c+uss1iFWsaH5fYZtU0g6XrxUzj/xKawbqW1Sx+mhX4dlNoWesba321lvvAIA8Lb5qExrq2/b/thee7vy2O2FTa/tdvUoLVzFMOdwkjvvvjcRY2KRdspZZ6g63UFRu+fc2Gr4NtaQeb5w62+B0cRHR0XHL9oU73R0/XH5B1c4zX/WEj5/f1R6LdH9xef7x8/SF410f1139Q+P+fPa74ONPBJ6Q/+TfzjGYmPq8AAAAASUVORK5CYII='
}

// `Vue.use` automatically prevents you from using
// the same plugin more than once,
// so calling it multiple times on the same plugin
// will install the plugin only once
Component.install = Vue => {
Component.install = (Vue, options = {}) => {
Vue.prototype.$vImg = {...defaultOptions, ...options}

Vue.component(Component.name, Component)

Vue.directive('img', {
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
}
7 changes: 0 additions & 7 deletions src/reload.svg

This file was deleted.

36 changes: 17 additions & 19 deletions src/spinner.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 77bd753

Please sign in to comment.