* [html5] add feature offset appear.
Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/5554d51e Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/5554d51e Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/5554d51e Branch: refs/heads/0.16-dev Commit: 5554d51ecd632b1a7826574541efda99240a5105 Parents: 524fbd1 Author: MrRaindrop <tekk...@gmail.com> Authored: Mon Sep 25 16:11:35 2017 +0800 Committer: MrRaindrop <tekk...@gmail.com> Committed: Mon Sep 25 16:11:35 2017 +0800 ---------------------------------------------------------------------- html5/render/vue/README.md | 4 + html5/render/vue/mixins/base.js | 4 +- html5/render/vue/utils/component.js | 160 ++++++++++++++++++----------- package.json | 2 +- packages/weex-vue-render/README.md | 4 + packages/weex-vue-render/package.json | 2 +- 6 files changed, 112 insertions(+), 64 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/5554d51e/html5/render/vue/README.md ---------------------------------------------------------------------- diff --git a/html5/render/vue/README.md b/html5/render/vue/README.md index d2b8c89..ad7c61f 100644 --- a/html5/render/vue/README.md +++ b/html5/render/vue/README.md @@ -176,6 +176,10 @@ vue: { * not to prevent default behaviour of click events unless the click-binding element is inside a `<a>` link, or it is a `<a>` link and has a `prevent` attribute on it. +#### 0.12.17 + +* support offset appear. + ## component -> dom map | component | dom element | children | note | http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/5554d51e/html5/render/vue/mixins/base.js ---------------------------------------------------------------------- diff --git a/html5/render/vue/mixins/base.js b/html5/render/vue/mixins/base.js index 06bc980..28c7703 100644 --- a/html5/render/vue/mixins/base.js +++ b/html5/render/vue/mixins/base.js @@ -19,7 +19,6 @@ import { getThrottleLazyload, watchAppear, - triggerAppear, triggerDisappear, extend } from '../utils' @@ -73,8 +72,7 @@ export default { if (this.$el && (i = j = this.$vnode) && (i = i.data) && (j = j.componentOptions)) { this.$el.attrs = extend({}, i.attrs, j.propsData) } - triggerAppear(this) - watchAppear(this) + watchAppear(this, true) }, destroyed () { http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/5554d51e/html5/render/vue/utils/component.js ---------------------------------------------------------------------- diff --git a/html5/render/vue/utils/component.js b/html5/render/vue/utils/component.js index eb8ded7..f1e9ee0 100644 --- a/html5/render/vue/utils/component.js +++ b/html5/render/vue/utils/component.js @@ -36,9 +36,52 @@ export function getParentScroller (vm) { return _getParentScroller(vm.$parent) } -export function hasIntersection (rect, ctRect) { - return (rect.left < ctRect.right && rect.right > ctRect.left) - && (rect.top < ctRect.bottom && rect.bottom > ctRect.top) +function horizontalBalance (rect, ctRect) { + return rect.left < ctRect.right && rect.right > ctRect.left +} + +function verticalBalance (rect, ctRect) { + return rect.top < ctRect.bottom && rect.bottom > ctRect.top +} + +/** + * return a data array with two boolean value, which are: + * 1. visible in current ct's viewport. + * 2. visible with offset in current ct's viewport. + */ +export function hasIntersection (rect, ctRect, dir, offset) { + dir = dir || 'up' + const isHorizontal = dir === 'left' || dir === 'right' + const isVertical = dir === 'up' || dir === 'down' + if (isHorizontal && !verticalBalance(rect, ctRect)) { + return [false, false] + } + if (isVertical && !horizontalBalance(rect, ctRect)) { + return [false, false] + } + offset = parseInt(offset || 0) * weex.config.env.scale + switch (dir) { + case 'up': + return [ + rect.top < ctRect.bottom && rect.bottom > ctRect.top, + rect.top < ctRect.bottom + offset && rect.bottom > ctRect.top - offset + ] + case 'down': + return [ + rect.bottom > ctRect.top && rect.top < ctRect.bottom, + rect.bottom > ctRect.top - offset && rect.top < ctRect.bottom + offset + ] + case 'left': + return [ + rect.left < ctRect.right && rect.right > ctRect.left, + rect.left < ctRect.right + offset && rect.right > ctRect.left - offset + ] + case 'right': + return [ + rect.right > ctRect.left && rect.left < ctRect.right, + rect.right > ctRect.left - offset && rect.left < ctRect.right + offset + ] + } } /** @@ -46,7 +89,7 @@ export function hasIntersection (rect, ctRect) { * @param {HTMLElement} el a dom element. * @param {HTMLElement} container optional, the container of this el. */ -export function isElementVisible (el, container) { +export function isElementVisible (el, container, dir, offset) { if (!el.getBoundingClientRect) { return false } const bodyRect = { top: 0, @@ -57,30 +100,11 @@ export function isElementVisible (el, container) { const ctRect = (container === document.body) ? bodyRect : container ? container.getBoundingClientRect() : bodyRect - return hasIntersection( - el.getBoundingClientRect(), - ctRect) -} - -export function isComponentVisible (component) { - if (component.$el) { - const scroller = getParentScroller(component) - if (scroller && scroller.$el) { - return hasIntersection( - component.$el.getBoundingClientRect(), - scroller.$el.getBoundingClientRect() - ) - } - else { - return isElementVisible(component.$el) - } - } - return false + return hasIntersection(el.getBoundingClientRect(), ctRect, dir, offset) } // to trigger the appear/disappear event. -function triggerEvent (elm, handlers, isShow, dir) { - const evt = isShow ? 'appear' : 'disappear' +function triggerEvent (elm, handlers, evt, dir) { let listener = handlers[evt] if (listener && listener.fn) { listener = listener.fn @@ -111,16 +135,30 @@ export function getEventHandlers (context) { return handlers } +function getAppearOffset (el) { + return el && el.getAttribute('appear-offset') +} + +function checkHandlers (handlers) { + return [ + !!(handlers.appear || handlers.disappear), + !!(handlers.offsetAppear || handlers.offsetDisappear) + ] +} + /** * Watch element's visibility to tell whether should trigger a appear/disappear * event in scroll handler. */ -export function watchAppear (context) { +export function watchAppear (context, fireNow) { const el = context && context.$el if (!el) { return } + const appearOffset = getAppearOffset(el) const handlers = getEventHandlers(context) - if (!handlers.appear && !handlers.disappear) { + const checkResults = checkHandlers(handlers) + // no appear or offsetAppear handler was bound. + if (!checkResults[0] && !checkResults[1]) { return } @@ -134,16 +172,23 @@ export function watchAppear (context) { isWindow = true } + if (fireNow) { + const visibleData = isElementVisible(el, container, null, appearOffset) + detectAppear(context, visibleData, null) + } + // add current vm to the container's appear watch list. if (!container._watchAppearList) { container._watchAppearList = [] } container._watchAppearList.push(context) - if (container._scrollWatched) { return } /** * Code below will only exec once for binding scroll handler for parent container. */ + if (container._scrollWatched) { + return + } container._scrollWatched = true const scrollHandler = throttle(event => { /** @@ -154,42 +199,29 @@ export function watchAppear (context) { const scrollTop = isWindow ? window.pageYOffset : container.scrollTop const preTop = container._lastScrollTop container._lastScrollTop = scrollTop - const dir = scrollTop < preTop + const dir = (scrollTop < preTop ? 'down' : scrollTop > preTop - ? 'up' : null - + ? 'up' : container._prevDirection) || null + container._prevDirection = dir const watchAppearList = container._watchAppearList || [] const len = watchAppearList.length for (let i = 0; i < len; i++) { const vm = watchAppearList[i] - const visible = isElementVisible(vm.$el, isWindow ? document.body : container) - detectAppear(vm, visible, dir) + const el = vm.$el + const ct = isWindow ? document.body : container + const appearOffset = getAppearOffset(el) + const visibleData = isElementVisible(el, ct, dir, appearOffset) + detectAppear(vm, visibleData, dir) } }, 25, true) container.addEventListener('scroll', scrollHandler, false) } /** - * trigger a appear event. - */ -export function triggerAppear (context, visible) { - if (!context || !context.$el) { return } - if (!visible) { - let container = document.body - const scroller = getParentScroller(context) - if (scroller && scroller.$el) { - container = scroller.$el - } - visible = isElementVisible(context.$el, container) - } - return detectAppear(context, visible) -} - -/** * trigger a disappear event. */ export function triggerDisappear (context) { - return detectAppear(context, false) + return detectAppear(context, [false, false]) } /** @@ -198,26 +230,36 @@ export function triggerDisappear (context) { * @param {boolean} visible * @param {string} dir */ -export function detectAppear (context, visible, dir = null) { +export function detectAppear (context, visibleData, dir = null, appearOffset) { const el = context && context.$el + const [visible, offsetVisible] = visibleData if (!el) { return } const handlers = getEventHandlers(context) /** * No matter it's binding appear/disappear or both of them. Always - * should test it's visibility and change the context._visible. + * should test it's visibility and change the context/._visible. * If neithor of them was bound, then just ignore it. */ - if (!handlers['appear'] && !handlers['disappear']) { return } /** * if the component hasn't appeared for once yet, then it shouldn't trigger * a disappear event at all. */ - if (!visible && !context._appearedOnce) { return } - if (!context._visible === visible) { - if (!context._appearedOnce) { - context._appearedOnce = true + if (context._appearedOnce || visible) { + if (context._visible !== visible) { + if (!context._appearedOnce) { + context._appearedOnce = true + } + context._visible = visible + triggerEvent(el, handlers, visible ? 'appear' : 'disappear', dir) + } + } + if (context._offsetAppearedOnce || offsetVisible) { + if (context._offsetVisible !== offsetVisible) { + if (!context._offsetAppearedOnce) { + context._offsetAppearedOnce = true + } + context._offsetVisible = offsetVisible + triggerEvent(el, handlers, offsetVisible ? 'offsetAppear' : 'offsetDisappear', dir) } - context._visible = visible - triggerEvent(el, handlers, visible, dir) } } http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/5554d51e/package.json ---------------------------------------------------------------------- diff --git a/package.json b/package.json index 49a5d76..d67d637 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "subversion": { "browser": "0.5.0", "framework": "0.21.11", - "vue-render": "0.12.16", + "vue-render": "0.12.17", "transformer": ">=0.1.5 <0.5" }, "description": "A framework for building Mobile cross-platform UI", http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/5554d51e/packages/weex-vue-render/README.md ---------------------------------------------------------------------- diff --git a/packages/weex-vue-render/README.md b/packages/weex-vue-render/README.md index d2b8c89..ad7c61f 100644 --- a/packages/weex-vue-render/README.md +++ b/packages/weex-vue-render/README.md @@ -176,6 +176,10 @@ vue: { * not to prevent default behaviour of click events unless the click-binding element is inside a `<a>` link, or it is a `<a>` link and has a `prevent` attribute on it. +#### 0.12.17 + +* support offset appear. + ## component -> dom map | component | dom element | children | note | http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/5554d51e/packages/weex-vue-render/package.json ---------------------------------------------------------------------- diff --git a/packages/weex-vue-render/package.json b/packages/weex-vue-render/package.json index 57fed3f..c60617b 100644 --- a/packages/weex-vue-render/package.json +++ b/packages/weex-vue-render/package.json @@ -1,6 +1,6 @@ { "name": "weex-vue-render", - "version": "0.12.16", + "version": "0.12.17", "description": "Weex built-in components for Vue 2.x.", "license": "Apache-2.0", "main": "dist/index.common.js",