You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@weex.apache.org by so...@apache.org on 2017/06/16 04:06:00 UTC

[07/20] incubator-weex git commit: * [html5] fix appear events.

* [html5] fix appear events.


Project: http://git-wip-us.apache.org/repos/asf/incubator-weex/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-weex/commit/d8125036
Tree: http://git-wip-us.apache.org/repos/asf/incubator-weex/tree/d8125036
Diff: http://git-wip-us.apache.org/repos/asf/incubator-weex/diff/d8125036

Branch: refs/heads/0.14-dev
Commit: d8125036f7dbe9f5ecf1c1060e4676f62c030cfb
Parents: 8b39d07
Author: MrRaindrop <te...@gmail.com>
Authored: Wed Jun 7 11:44:23 2017 +0800
Committer: MrRaindrop <te...@gmail.com>
Committed: Wed Jun 7 11:44:23 2017 +0800

----------------------------------------------------------------------
 html5/render/vue/mixins/base.js     |   9 +-
 html5/render/vue/utils/component.js | 159 +++++++++++++++++++++----------
 2 files changed, 117 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/d8125036/html5/render/vue/mixins/base.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/mixins/base.js b/html5/render/vue/mixins/base.js
index a1db14c..ad9fe15 100644
--- a/html5/render/vue/mixins/base.js
+++ b/html5/render/vue/mixins/base.js
@@ -19,6 +19,8 @@
 import {
   getThrottleLazyload,
   watchAppear,
+  triggerAppear,
+  triggerDisappear,
   extend
 } from '../utils'
 
@@ -98,7 +100,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)
   },
 
@@ -112,7 +114,10 @@ export default {
     if (process.env.NODE_ENV === 'development') {
       tagUpdated()
     }
-    watchAppear(this)
+  },
+
+  destroyed () {
+    triggerDisappear(this)
   },
 
   methods: {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/d8125036/html5/render/vue/utils/component.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/utils/component.js b/html5/render/vue/utils/component.js
index c810e8d..f724532 100644
--- a/html5/render/vue/utils/component.js
+++ b/html5/render/vue/utils/component.js
@@ -83,57 +83,118 @@ function triggerEvent (elm, handlers, isShow, dir) {
   }
 }
 
+/**
+ * get all event listeners. including v-on binding and ons in config.
+ */
+export function getEventHandlers (context) {
+  const parentListeners = context.$options && context.$options._parentListeners
+  const dataOn = context.$vnode && context.$vnode.data && context.$vnode.data.on
+  const on = extend({}, parentListeners, dataOn)
+  return on
+}
+
+/**
+ * Watch element's visibility to tell whether should trigger a appear/disappear
+ * event in scroll handler.
+ */
 export function watchAppear (context) {
-  if (!context || !context.$el) return null
-  const el = context.$el
-  context.$nextTick(() => {
-    if ((context.$options && context.$options._parentListeners)
-      || (context.$vnode && context.$vnode.data && context.$vnode.data.on)) {
-      const on = extend({}, context.$options._parentListeners, context.$vnode.data.on)
-      if (on.appear || on.disappear) {
-        const scroller = getParentScroller(context)
-        let isWindow = false
-        let container = window
-        if (scroller && scroller.$el) {
-          container = scroller.$el
-        }
-        else {
-          isWindow = true
-        }
-        const visible = isElementVisible(el, isWindow ? document.body : container)
-        if (context._visible !== visible) {
-          context._visible = visible
-          // if the component hasn't appeared for once yet, then it shouldn't trigger
-          // a disappear event at all.
-          if (context._appearedOnce) {
-            triggerEvent(el, on, visible, null)
-          }
-          else if (visible) {
-            context._appearedOnce = true
-            triggerEvent(el, on, true, null)
-          }
-        }
+  const el = context && context.$el
+  if (!el) { return }
+
+  const handlers = getEventHandlers(context)
+  if (!handlers.appear && !handlers.disappear) {
+    return
+  }
+
+  let isWindow = false
+  let container = window
+  const scroller = getParentScroller(context)
+  if (scroller && scroller.$el) {
+    container = scroller.$el
+  }
+  else {
+    isWindow = true
+  }
+
+  // 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.
+   */
+  container._scrollWatched = true
+  const scrollHandler = throttle(event => {
+    /**
+     * detect scrolling direction.
+     * direction only support up & down yet.
+     * TODO: direction support left & right.
+     */
+    const scrollTop = isWindow ? window.pageYOffset : container.scrollTop
+    const preTop = container._lastScrollTop
+    container._lastScrollTop = scrollTop
+    const dir = scrollTop < preTop
+      ? 'down' : scrollTop > preTop
+      ? 'up' : null
+
+    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)
+    }
+  }, 25, true)
+  container.addEventListener('scroll', scrollHandler, false)
+}
 
-        let lastScrollTop = container.scrollTop || window.pageYOffset
-        // no need to watch the same vComponent again.
-        if (!context._scrollWatched) {
-          context._scrollWatched = true
-          const handler = throttle(event => {
-            const visible = isElementVisible(el, isWindow ? document.body : container)
-            if (visible !== context._visible) {
-              context._visible = visible
-              const scrollTop = container.scrollTop || window.pageYOffset
-              const dir = scrollTop < lastScrollTop
-                ? 'down' : scrollTop > lastScrollTop
-                ? 'up' : null
-              triggerEvent(el, on, visible, dir)
-              lastScrollTop = scrollTop
-            }
-          }, 25, true)
+/**
+ * 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
+    }
+    const visible = isElementVisible(context.$el, container)
+  }
+  return detectAppear(context, visible)
+}
 
-          container.addEventListener('scroll', handler, false)
-        }
-      }
+/**
+ * trigger a disappear event.
+ */
+export function triggerDisappear (context) {
+  return detectAppear(context, false)
+}
+
+/**
+ * decide whether to trigger a appear/disappear event.
+ * @param {VueComponent} context
+ * @param {boolean} visible
+ * @param {string} dir
+ */
+export function detectAppear (context, visible, dir = null) {
+  const el = context && context.$el
+  if (!el) { return }
+  const handlers = getEventHandlers(context)
+  if (!handlers[visible ? 'appear' : '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
     }
-  })
+    context._visible = visible
+    triggerEvent(el, handlers, visible, dir)
+  }
 }