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) {