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:03 UTC

[10/20] incubator-weex git commit: * [html5] support sticky children in vertical scroller & list.

* [html5] support sticky children in vertical scroller & list.


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

Branch: refs/heads/0.14-dev
Commit: e31783a95ecc4d36a314a33ed95bb04ea6622be3
Parents: 16fab9c
Author: MrRaindrop <te...@gmail.com>
Authored: Wed Jun 7 17:40:13 2017 +0800
Committer: MrRaindrop <te...@gmail.com>
Committed: Wed Jun 7 17:40:13 2017 +0800

----------------------------------------------------------------------
 .../render/vue/components/scrollable/header.js  |  2 +-
 html5/render/vue/core/style.js                  | 95 +++++++++++++++-----
 html5/render/vue/index.js                       |  3 +-
 html5/render/vue/mixins/index.js                |  4 +-
 html5/render/vue/mixins/scrollable.js           |  3 +
 html5/render/vue/mixins/sticky.js               | 65 ++++++++++++++
 html5/render/vue/styles/base.css                |  4 +-
 html5/render/vue/utils/component.js             | 20 +++--
 8 files changed, 163 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31783a9/html5/render/vue/components/scrollable/header.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/components/scrollable/header.js b/html5/render/vue/components/scrollable/header.js
index 3644177..cbb4783 100644
--- a/html5/render/vue/components/scrollable/header.js
+++ b/html5/render/vue/components/scrollable/header.js
@@ -70,7 +70,7 @@ export default {
       on: createEventMap(this),
       ref: 'header',
       staticClass: 'weex-header weex-ct',
-      class: { sticky: this.sticky, iossticky: this.supportSticky },
+      class: { 'weex-sticky': this.sticky, 'weex-ios-sticky': this.supportSticky },
       staticStyle: extractComponentStyle(this)
     }, this.$slots.default)
   }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31783a9/html5/render/vue/core/style.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/core/style.js b/html5/render/vue/core/style.js
index 8bb3029..f90d1a9 100644
--- a/html5/render/vue/core/style.js
+++ b/html5/render/vue/core/style.js
@@ -23,7 +23,10 @@ import {
   extendTruthy,
   trimComment,
   normalizeStyle,
-  autoPrefix
+  autoPrefix,
+  isArray,
+  getParentScroller,
+  supportSticky
 } from '../utils'
 import { tagBegin, tagEnd } from '../utils/perf'
 /* istanbul ignore next */
@@ -230,11 +233,47 @@ export function getComponentStyle (context, extract) {
           }
         }
       })
-      delete style[k]
+      if (k !== 'position') { delete style[k] }
     }
   }
+
+  /**
+   * If position is 'sticky', then add it to the stickyChildren of the parent scroller.
+   */
+  const pos = style.position
+  const reg = /sticky$/
+  if (isArray(pos) && pos[0].match(reg) || (pos + '').match(reg)) {
+    delete style.position
+    // use native sticky.
+    if (supportSticky()) {
+      context.$nextTick(function () {
+        const el = context.$el
+        if (el) {
+          el.classList.add('weex-ios-sticky')
+        }
+      })
+    }
+    // use re-implementation of sticky.
+    else if (!context._stickyAdded) {
+      const uid = context._uid
+      const scroller = getParentScroller(context)
+      if (scroller) {
+        context._stickyAdded = true
+        if (!scroller._stickyChildren) {
+          scroller._stickyChildren = {}
+        }
+        scroller._stickyChildren[uid] = context
+      }
+      context.$nextTick(function () {
+        const el = context.$el
+        if (el) {
+          context._initOffsetTop = el.offsetTop
+        }
+      })
+    }
+  }
+
   return style
-  // return addPrefix(normalizeStyle(style))
 }
 
 export function extractComponentStyle (context) {
@@ -242,27 +281,37 @@ export function extractComponentStyle (context) {
 }
 
 /**
- * get { width, height } (size) of current component from components' styles.
+ * process sticky children in scrollable components.
+ * current only support list and vertical scroller.
  */
-export function getSize (context) {
-  if (!context.$vnode) {
-    if (process.env.NODE_ENV === 'development') {
-      return console.error('[vue-render] getComponentStyle failed: no $vnode in context.')
-    }
-    return {}
+export function processSticky (context) {
+  /**
+   * current browser support 'sticky' or '-webkit-sticky', so there's no need
+   * to do further more.
+   */
+  if (supportSticky()) {
+    return
   }
-  const data = context.$vnode.data
-  const wh = {}
-  const classes = typeof data.class === 'string' ? data.class.split(' ') : (data.class || [])
-  const staticClass = typeof data.staticClass === 'string' ? data.staticClass.split(' ') : (data.class || [])
-  const clsNms = staticClass.concat(classes)
-  function extendWHFrom (to, from) {
-    if (!from) { return }
-    from.width && (to.width = from.width)
-    from.height && (to.height = from.height)
+  // current only support list and vertical scroller.
+  if (container.scrollDirection === 'horizontal') {
+    return
+  }
+  const stickyChildren = context._stickyChildren
+  const len = stickyChildren && stickyChildren.length || 0
+  if (len <= 0) { return }
+
+  const container = context.$el
+  if (!container) { return }
+  const scrollTop = container.scrollTop
+
+  let stickyChild
+  for (let i = 0; i < len; i++) {
+    stickyChild = stickyChildren[i]
+    if (stickyChild._initOffsetTop < scrollTop) {
+      stickyChild._addSticky()
+    }
+    else {
+      stickyChild._removeSticky()
+    }
   }
-  extendWHFrom(wh, this._getScopeStyle(clsNms))
-  extendWHFrom(wh, data.staticStyle)
-  extendWHFrom(wh, data.style)
-  return wh
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31783a9/html5/render/vue/index.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/index.js b/html5/render/vue/index.js
index 9c3c38c..5795c6b 100644
--- a/html5/render/vue/index.js
+++ b/html5/render/vue/index.js
@@ -19,7 +19,7 @@
 import weex from './env'
 import { setVue } from './env'
 import components from './components'
-import { base, style } from './mixins'
+import { base, style, sticky } from './mixins'
 // import styleMixin from './mixins/style'
 
 /**
@@ -60,6 +60,7 @@ function init (Vue/*, options = {}*/) {
   //     + `[${Object.keys(components).join(', ')}].`)
   Vue.mixin(base)
   Vue.mixin(style)
+  Vue.mixin(sticky)
   // }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31783a9/html5/render/vue/mixins/index.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/mixins/index.js b/html5/render/vue/mixins/index.js
index f91bdd4..7807b1a 100644
--- a/html5/render/vue/mixins/index.js
+++ b/html5/render/vue/mixins/index.js
@@ -20,10 +20,12 @@ import base from './base'
 import style from './style'
 import scrollable from './scrollable'
 import inputCommon from './input-common'
+import sticky from './sticky'
 
 export {
   base,
   scrollable,
   style,
-  inputCommon
+  inputCommon,
+  sticky
 }

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31783a9/html5/render/vue/mixins/scrollable.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/mixins/scrollable.js b/html5/render/vue/mixins/scrollable.js
index 7adcf02..011c8e0 100644
--- a/html5/render/vue/mixins/scrollable.js
+++ b/html5/render/vue/mixins/scrollable.js
@@ -17,6 +17,7 @@
  * under the License.
  */
 import { getThrottleLazyload, throttle } from '../utils'
+import { processSticky } from '../core'
 
 const DEFAULT_OFFSET_ACCURACY = 10
 const DEFAULT_LOADMORE_OFFSET = 0
@@ -109,6 +110,8 @@ export default {
       getThrottleLazyload(25, this.$el, 'scroll')()
       getThrottledScroll(this)(event)
 
+      processSticky(this)
+
       // fire loadmore event.
       const inner = this.$refs.inner
       if (inner) {

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31783a9/html5/render/vue/mixins/sticky.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/mixins/sticky.js b/html5/render/vue/mixins/sticky.js
new file mode 100644
index 0000000..8beb91a
--- /dev/null
+++ b/html5/render/vue/mixins/sticky.js
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import {
+  getParentScroller
+} from '../utils'
+
+export default {
+  destroyed () {
+    if (!this._stickyAdded) { return }
+    const scroller = getParentScroller(this)
+    if (!scroller) { return }
+    delete scroller._stickyChildren[this._uid]
+  },
+
+  methods: {
+    _addSticky () {
+      const el = this.$el
+      if (!el || el.nodeType === 1) {
+        if (process.env.NODE_ENV === 'development') {
+          console.error(`[vue-render] $el doesn't exist to add sticky.`)
+        }
+        return
+      }
+      el.classList.add('sticky')
+      if (!this._placeholder) {
+        this._placeholder = el.cloneNode(true)
+      }
+      this._placeholder.style.display = 'block'
+      this._placeholder.style.width = this.$el.offsetWidth + 'px'
+      this._placeholder.style.height = this.$el.offsetHeight + 'px'
+      el.parentNode.insertBefore(this._placeholder, this.$el)
+    },
+
+    _removeSticky () {
+      const el = this.$el
+      if (!el || el.nodeType === 1) {
+        if (process.env.NODE_ENV === 'development') {
+          console.error(`[vue-render] $el doesn't exist to remove sticky.`)
+        }
+        return
+      }
+      el.classList.remove('sticky')
+      if (this._placeholder) {
+        this._placeholder.parentNode.removeChild(this._placeholder)
+      }
+      this._placeholder = null
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31783a9/html5/render/vue/styles/base.css
----------------------------------------------------------------------
diff --git a/html5/render/vue/styles/base.css b/html5/render/vue/styles/base.css
index 17d0738..37728df 100644
--- a/html5/render/vue/styles/base.css
+++ b/html5/render/vue/styles/base.css
@@ -106,14 +106,14 @@ body > .weex-scroller {
   height: 100%;
 }
 
-.iossticky {
+.weex-ios-sticky {
   position: -webkit-sticky !important;
   position: sticky !important;
   z-index: 9999;
   top: 0;
 }
 
-.sticky {
+.weex-sticky {
   position: fixed;
   top: 0;
   z-index: 9999;

http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/e31783a9/html5/render/vue/utils/component.js
----------------------------------------------------------------------
diff --git a/html5/render/vue/utils/component.js b/html5/render/vue/utils/component.js
index adcba9d..409d98a 100644
--- a/html5/render/vue/utils/component.js
+++ b/html5/render/vue/utils/component.js
@@ -19,12 +19,22 @@
 import { throttle, extend } from './func'
 import { createEvent } from './event'
 
-export function getParentScroller (vnode) {
-  if (!vnode) return null
-  if (vnode.weexType === 'scroller' || vnode.weexType === 'list') {
-    return vnode
+const scrollableTypes = ['scroller', 'list']
+
+export function getParentScroller (vm) {
+  if (!vm) return null
+  if (vm._parentScroller) {
+    return vm._parentScroller
+  }
+  function _getParentScroller (parent) {
+    if (!parent) { return }
+    if (scrollableTypes.indexOf(parent.weexType) > -1) {
+      vm._parentScroller = parent
+      return parent
+    }
+    return _getParentScroller(parent.$parent)
   }
-  return getParentScroller(vnode.$parent)
+  return _getParentScroller(vm.$parent)
 }
 
 export function hasIntersection (rect, ctRect) {