* [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/master
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",

Reply via email to