Skip to content

Commit

Permalink
2018-08-14 例行上线
Browse files Browse the repository at this point in the history
* 修复轮播图mip-img嵌套问题,增加mip-img长图浏览效果 (#177)

* 懒加载支持mip-img嵌套在其他元素下

* 解决长屏图片的问题

* 增加img来解决动画问题

* 支持长图浏览,修改动画代码但效果不变

* 完善测试用例,增加example

* 解决动画白边问题

* 修改carousel的测试用例

* 调整 mipDataPromises 的 resolve 时机 (#183)

* fix: 181 mipDataPromises resolve adjust

* Do not override render in Vue.customElement

* 增加配置项,允许直接读取目标页面的配置以决定标题
  • Loading branch information
PengXing authored Aug 16, 2018
2 parents dbc2679 + b1c9b05 commit a6ad2f2
Show file tree
Hide file tree
Showing 11 changed files with 288 additions and 60 deletions.
4 changes: 3 additions & 1 deletion docs/guide/all-sites-mip/page-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ if (isRootPage) {

如果页面需要展现全页面级别的遮罩层(如弹出对话框时),因为 iframe 的关系,并不能遮挡头部,如下图左边所示。

![Page Mask](https://boscdn.baidu.com/assets/mip2/page/page-mask.png)

![Page Mask](http://boscdn.bpc.baidu.com/assets/mip2/page/page-mask-2.png)


而调用 `togglePageMask` 方法可以就通知 Page 把头部也进行遮挡,从而完成全页面的遮罩,如上图右边所示。

Expand Down
20 changes: 20 additions & 0 deletions packages/mip/examples/builtin-components/mip-img.html
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,26 @@ <h2>放大图片可多图浏览</h2>
src="https://www.mipengine.org/static/img/sample_03.jpg">
</mip-img>

<h2>长图浏览</h2>

<pre class="code">&lt;mip-img
layout="responsive"
width="200"
height="500"
popup
alt="baidu mip img"
src="http://bos.nj.bpc.baidu.com/v1/assets/mip/mip2-component-lifecycle.png"&gt;
&lt;/mip-img&gt;</pre>

<mip-img
layout="responsive"
width="200"
height="500"
popup
alt="baidu mip img"
src="http://bos.nj.bpc.baidu.com/v1/assets/mip/mip2-component-lifecycle.png">
</mip-img>

</body>
<script src="../../dist/mip.js"></script>
</html>
2 changes: 1 addition & 1 deletion packages/mip/examples/page/data.html
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
}
</script>
</mip-data>
<!-- <mip-data src="./data/testData.json"></mip-data> -->
<mip-data src="./data/testData.json"></mip-data>
<mip-data>
<script type="application/json">
{
Expand Down
47 changes: 29 additions & 18 deletions packages/mip/src/components/mip-bind/mip-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@
import CustomElement from '../../custom-element'
import jsonParse from '../../util/json-parse'

/*
* Remove promise from global mipDataPromises array
* @param {Promise} target promise need to be removed
*/
function dropPromise (target) {
let index = mipDataPromises.indexOf(target)
mipDataPromises.splice(index, ~index ? 1 : 0)
}

class MipData extends CustomElement {
build () {
let src = this.element.getAttribute('src')
Expand All @@ -29,33 +38,35 @@ class MipData extends CustomElement {
/*
* get initial data asynchronouslly
*/
/* istanbul ignore next */
getData (url) {
if (!url) {
return
}

let promise = fetch(url, {
credentials: 'include'
let stuckResolve
let stuckReject
// only resolve/reject when sth truly comes to a result
// such as only to resolve when res.json() done
let stuckPromise = new Promise(function (resolve, reject) {
stuckResolve = resolve
stuckReject = reject
})
mipDataPromises.push(stuckPromise)

mipDataPromises.push(promise)

promise
fetch(url, {credentials: 'include'})
.then(res => {
if (res.ok) {
res.json().then(data => MIP.$set(data))
res.json().then(data => {
MIP.$set(data)
dropPromise(stuckPromise)
stuckResolve()
})
} else {
console.error('Fetch request failed!')
dropPromise(stuckPromise)
stuckReject()
}
})
.catch(console.error)
.finally(() => {
for (let i = 0; i < mipDataPromises.length; i++) {
if (mipDataPromises[i] === promise) {
mipDataPromises.splice(i, 1)
}
}
.catch(e => {
console.error(e)
dropPromise(stuckPromise)
stuckReject()
})
}

Expand Down
44 changes: 30 additions & 14 deletions packages/mip/src/components/mip-carousel.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,31 +42,47 @@ function prerenderSetSrc (allMipImgs, index, num, arraySrc) {
for (let j = 0; j < imgs.length; j++) {
imgs[j].setAttribute('src', arraySrc[i])
}
} else {
allMipImgs[i].querySelector('mip-img').setAttribute('src', arraySrc[i])
}
}
}
/**
* 修改 src 为某张图的 src
* @param {NodeList} childList 一般是 mip-img 标签的集合
* @param {number } j j
* @param {number} imgIndex imgIndex是显示的第一张图片的在arraySrc中的index
* @param {Array} arraySrc 所有图片的src组成的数组
* @return {NodeList} 返回 childList
*/
function changeSrc (childList, j) {
let src = ''
// 考虑 mip-img 是被嵌套在 a 里面的情况
if (childList[j].tagName === 'MIP-IMG') {
src = childList[j].getAttribute('src')
} else {
src = childList[j].querySelector('mip-img').getAttribute('src')
}
function changeSrc (childList, imgIndex, arraySrc) {
for (let i = 0; i < childList.length; i++) {
if (childList[i].tagName === 'MIP-IMG') {
childList[i].setAttribute('src', src)
childList[i].setAttribute('src', arraySrc[imgIndex])
} else {
childList[i].querySelector('mip-img').setAttribute('src', arraySrc[imgIndex])
}
}
return childList
}

/**
* 获取carousel下所有mip-img的src,目前只处理一层和两层的,3层也当两层处理
* @param {Array.<HTMLElement>} childNodes getChildNodes函数得出的数组
* @return {Array.<string>} mip-img中的src组成的数组
*/
function getAllMipImgSrc (childNodes) {
let arr = []
for (let i = 0; i < childNodes.length; i++) {
if (childNodes[i].tagName === 'MIP-IMG') {
arr.push(childNodes[i].getAttribute('src'))
} else {
let node = childNodes[i].querySelector('mip-img')
if (node) {
arr.push(node.getAttribute('src'))
}
}
}
return arr
}
// 按tagName创建一个固定class的tag
function createTagWithClass (className, tagName) {
tagName = tagName || 'div'
Expand Down Expand Up @@ -228,8 +244,8 @@ class MIPCarousel extends CustomElement {
// 获取carousel下的所有节点
let childNodes = getChildNodes(ele)
// 获取所有的 src
let arraySrc = childNodes.map(value => value.getAttribute('src'))
childNodes = changeSrc(childNodes, imgIndex)
let arraySrc = getAllMipImgSrc(childNodes)
childNodes = changeSrc(childNodes, imgIndex, arraySrc)

// 图片显示个数
// 其实图片个数应该为实际个数+2.copy了头和尾的两部分
Expand Down Expand Up @@ -471,7 +487,7 @@ class MIPCarousel extends CustomElement {
setTimeout(function () {
translateFn(curGestureClientx, '0ms', wrapBox)
btnLock.stop = 1
}, 300)
}, 400)
}
btnLock.stop = 1
indicatorChange(imgIndex)
Expand Down
54 changes: 41 additions & 13 deletions packages/mip/src/components/mip-img.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import viewer from '../viewer'
const naboo = util.naboo

let errHandle
let Gesture = util.Gesture
let css = util.css
let rect = util.rect

Expand Down Expand Up @@ -84,6 +83,18 @@ function getImgOffset (img) {
function getImgsSrc () {
return [...document.querySelectorAll('mip-img')].filter(value => value.hasAttribute('popup')).map(value => value.getAttribute('src'))
}
/**
* 找出当前视口下的图片
* @param {HTMLElement} carouselWrapper carouselWrapper
* @return {HTMLElement} img
*/
function getCurrentImg (carouselWrapper) {
// 例如:'translate3d(-90px,0,0)'
let str = carouselWrapper.style.webkitTransform
let result = /translate3d\(-?([0-9]+)/i.exec(str)
let number = parseInt(result[1]) / viewport.getWidth()
return carouselWrapper.querySelectorAll('mip-img')[number]
}
// 创建弹层 dom
function createPopup (element, img) {
// 获取图片数组
Expand All @@ -92,10 +103,7 @@ function createPopup (element, img) {

let popup = document.createElement('div')
css(popup, 'display', 'block')
// 阻止纵向滑动
new Gesture(popup, {
preventY: true
})

popup.className = 'mip-img-popUp-wrapper'
popup.setAttribute('data-name', 'mip-img-popUp-name')

Expand All @@ -105,18 +113,19 @@ function createPopup (element, img) {
let carouselWrapper = document.createElement('div')
// 计算 wrapper 窗口大小
let imgOffset = getImgOffset(img)
let PopupImgPos = getPopupImgPos(imgOffset.width, imgOffset.height)
let popupImgPos = getPopupImgPos(imgOffset.width, imgOffset.height)
popupImgPos.top = 0
css(carouselWrapper, {
'position': 'absolute'
})
css(carouselWrapper, PopupImgPos)
css(carouselWrapper, popupImgPos)
// 创建 mip-carousel
let carousel = document.createElement('mip-carousel')

carousel.setAttribute('layout', 'height-fixed')
carousel.setAttribute('index', index + 1)
carousel.setAttribute('width', PopupImgPos.width)
carousel.setAttribute('height', PopupImgPos.height)
carousel.setAttribute('width', popupImgPos.width)
carousel.setAttribute('height', popupImgPos.height)

for (let i = 0; i < imgsSrcArray.length; i++) {
let mipImg = document.createElement('mip-img')
Expand Down Expand Up @@ -150,7 +159,10 @@ function bindPopup (element, img) {
})
let popup = createPopup(element, img)
let popupBg = popup.querySelector('.mip-img-popUp-bg')
let popupImg = popup.querySelector('mip-carousel')
let mipCarousel = popup.querySelector('mip-carousel')
let popupImg = new Image()
popupImg.setAttribute('src', img.src)
popup.appendChild(popupImg)

let imgOffset = getImgOffset(img)

Expand All @@ -162,10 +174,22 @@ function bindPopup (element, img) {
skipTransition: true,
extraClass: 'black'
})
// 找出当前视口下的图片
let currentImg = getCurrentImg(popup.querySelector('.mip-carousel-wrapper'))
popupImg.setAttribute('src', currentImg.getAttribute('src'))
let previousPos = getImgOffset(img)
// 获取弹出图片滑动的距离,根据前面的设定,top大于0就不是长图,小于0才是滑动的距离
let currentImgPos = getImgOffset(currentImg)
currentImgPos.top < 0 && (previousPos.top -= currentImgPos.top)
currentImgPos.left < 0 && (previousPos.left -= currentImgPos.left)
css(popupImg, 'display', 'block')
css(mipCarousel, 'display', 'none')
naboo.animate(popupBg, {
opacity: 0
}).start()
naboo.animate(popupImg, getImgOffset(img)).start(function () {

naboo.animate(popup, {'display': 'none'})
naboo.animate(popupImg, previousPos).start(() => {
css(img, 'visibility', 'visible')
css(popup, 'display', 'none')
popup.removeEventListener('click', imagePop, false)
Expand All @@ -181,10 +205,14 @@ function bindPopup (element, img) {
window.addEventListener('resize', onResize)

css(popupImg, imgOffset)
css(popupImg, 'position', 'fixed')
css(mipCarousel, getPopupImgPos(imgOffset.width, imgOffset.height))
css(mipCarousel, 'display', 'none')
css(popupBg, 'opacity', 1)

naboo.animate(popupImg, getPopupImgPos(imgOffset.width, imgOffset.height)).start()
naboo.animate(popupImg, getPopupImgPos(imgOffset.width, imgOffset.height)).start(() => {
css(popupImg, 'display', 'none')
css(mipCarousel, 'display', 'block')
})
css(img, 'visibility', 'hidden')
css(img.parentNode, 'zIndex', 'inherit')
}, false)
Expand Down
9 changes: 6 additions & 3 deletions packages/mip/src/components/mip-shell/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ class MipShell extends CustomElement {
// If true, always load configures from `<mip-shell>` and overwrite shellConfig when opening new page
this.alwaysReadConfigOnLoad = true

// If true, always use title in shell config of target page when switing page
// Otherwise, use title from last page (`data-title` and shell config and innerText)
this.alwaysUseTitleInShellConfig = false

// If true, page switching transition contains header
this.transitionContainsHeader = true
}
Expand Down Expand Up @@ -269,8 +273,6 @@ class MipShell extends CustomElement {

// Other parts
this.renderOtherParts()

// window.MIP.viewer.fixedElement.init()
}

renderHeader (container) {
Expand All @@ -283,7 +285,8 @@ class MipShell extends CustomElement {
borderColor,
backgroundColor = '#ffffff'
} = pageMeta.header
if (this.targetPageTitle) {

if (this.targetPageTitle && !this.alwaysUseTitleInShellConfig) {
title = pageMeta.header.title = this.targetPageTitle
}
let showBackIcon = !pageMeta.view.isIndex
Expand Down
3 changes: 3 additions & 0 deletions packages/mip/src/viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,9 @@ let viewer = {
this.page.notifyRootPage({
type: MESSAGE_PAGE_RESIZE
})
if (event.target && typeof event.target.scrollIntoView === 'function') {
setTimeout(() => event.target.scrollIntoView(), 500)
}
}, true)
event.delegate(document, 'input', 'blur', event => {
this.page.notifyRootPage({
Expand Down
6 changes: 0 additions & 6 deletions packages/mip/src/vue-custom-element/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ function install (Vue) {
Vue.config.ignoredElements = [/^mip-/i]

Vue.customElement = (tag, componentDefinition) => {
// 如果不设置 template 和 render 函数,默认设置 render 函数返回 null,避免 warning
let {template, render} = componentDefinition
if (!template && typeof render !== 'function') {
componentDefinition.render = () => null
}

const props = getProps(componentDefinition)
function callLifeCycle (ctx, name) {
if (typeof componentDefinition[name] === 'function') {
Expand Down
Loading

0 comments on commit a6ad2f2

Please sign in to comment.