Merge branch 'hotfix/waterfall' into 'master'

Hotfix/waterfall



See merge request !4
This commit is contained in:
zhangmin 2017-02-27 10:42:51 +08:00
commit 533133a537
11 changed files with 319 additions and 1 deletions

View File

@ -51,7 +51,8 @@ ComponentNames.forEach(name => {
// services
'Dialog',
'Toast',
'Indicator'
'Indicator',
'Waterfall'
].indexOf(componentName) === -1) {
installTemplate.push(render(ISNTALL_COMPONENT_TEMPLATE, {
name: componentName,

View File

@ -10,6 +10,7 @@
"dialog": "./packages/dialog/index.js",
"picker": "./packages/picker/index.js",
"radio-group": "./packages/radio-group/index.js",
"waterfall": "./packages/waterfall/index.js",
"loading": "./packages/loading/index.js",
"panel": "./packages/panel/index.js",
"card": "./packages/card/index.js"

View File

@ -0,0 +1,84 @@
<script>
export default {
data() {
return {
list: [1, 2, 3, 4, 5],
loading: false,
finished: false
};
},
methods: {
loadMore() {
if (this.list.length >= 200) {
this.finished = true;
return;
}
this.loading = true;
setTimeout(() => {
let lastNumber = this.list[this.list.length - 1];
for (let i = 0; i < 5; i ++) {
lastNumber += 1;
this.list.push(lastNumber);
}
this.loading = false;
}, 2500);
},
loadMoreUpper() {
if (this.list[0] < 0) return;
this.list.unshift(-1);
}
},
computed: {
isWaterfallDisabled: function() {
return this.loading || this.finished;
}
}
};
</script>
<style lang="css">
.waterfall {
height: 300px;
overflow: scroll;
}
.waterfall-item {
line-height: 20px;
padding: 5px 0;
}
</style>
## Waterfall组件
### 基础用法
:::demo 样例代码
```html
<div class="waterfall">
<div
v-waterfall-lower="loadMore"
v-waterfall-upper="loadMoreUpper"
waterfall-disabled="isWaterfallDisabled"
waterfall-offset="400"
>
<div
class="waterfall-item"
v-for="item in list"
style="text-align: center;"
>
{{ item }}
</div>
<div v-if="loading" style="text-align: center;">
loading
</div>
</div>
</div>
```
:::
### API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| waterfall-disabled | 是否禁止瀑布流触发 | Boolean | false | |
| waterfall-offset | 触发瀑布流加载的阈值 | Number | 300 | |

View File

@ -0,0 +1,8 @@
## 0.0.2 (2017-01-20)
* 改了bug A
* 加了功能B
## 0.0.1 (2017-01-10)
* 第一版

View File

@ -0,0 +1,26 @@
# @youzan/waterfall
!!! 请在此处填写你的文档最简单描述 !!!
[![version][version-image]][download-url]
[![download][download-image]][download-url]
[version-image]: http://npm.qima-inc.com/badge/v/@youzan/<%= name %>.svg?style=flat-square
[download-image]: http://npm.qima-inc.com/badge/d/@youzan/<%= name %>.svg?style=flat-square
[download-url]: http://npm.qima-inc.com/package/@youzan/<%= name %>
## Demo
## Usage
## API
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------|
| className | 自定义额外类名 | string | '' | '' |
## License
[MIT](https://opensource.org/licenses/MIT)

View File

@ -0,0 +1,3 @@
import Waterfall from './src/main.js';
export default Waterfall;

View File

@ -0,0 +1,10 @@
{
"name": "waterfall",
"version": "0.0.1",
"description": "瀑布流",
"main": "./lib/index.js",
"author": "pangxie1991",
"license": "MIT",
"devDependencies": {},
"dependencies": {}
}

View File

@ -0,0 +1,94 @@
import Utils from './utils.js';
const CONTEXT = '@@Waterfall';
const OFFSET = 300;
// 绑定事件到元素上
// 读取基本的控制变量
function doBindEvent() {
this.scrollEventListener = Utils.debounce(handleScrollEvent.bind(this), 200);
this.scrollEventTarget = Utils.getScrollEventTarget(this.el);
var disabledExpr = this.el.getAttribute('waterfall-disabled');
var disabled = false;
if (disabledExpr) {
this.vm.$watch(disabledExpr, (value) => {
this.disabled = value;
});
disabled = Boolean(this.vm[disabledExpr]);
}
this.disabled = disabled;
var offset = this.el.getAttribute('waterfall-offset');
this.offset = Number(offset) || OFFSET;
this.scrollEventTarget.addEventListener('scroll', this.scrollEventListener);
this.scrollEventListener();
}
// 处理滚动函数
function handleScrollEvent() {
let element = this.el;
let scrollEventTarget = this.scrollEventTarget;
// 已被禁止的滚动处理
if (this.disabled) return;
let targetScrollTop = Utils.getScrollTop(scrollEventTarget);
let targetBottom = targetScrollTop + Utils.getVisibleHeight(scrollEventTarget);
// 判断是否到了底
let needLoadMoreToLower = false;
if (element === scrollEventTarget) {
needLoadMoreToLower = scrollEventTarget.scollHeight - targetBottom < this.offset;
} else {
let elementBottom = Utils.getElementTop(element) - Utils.getElementTop(scrollEventTarget) + Utils.getVisibleHeight(element);
needLoadMoreToLower = elementBottom - Utils.getVisibleHeight(scrollEventTarget) < this.offset;
}
if (needLoadMoreToLower) {
this.cb['lower'] && this.cb['lower']({ target: scrollEventTarget, top: targetScrollTop });
}
// 判断是否到了顶
let needLoadMoreToUpper = false;
if (element === scrollEventTarget) {
needLoadMoreToUpper = targetScrollTop < this.offset;
} else {
let elementTop = Utils.getElementTop(element) - Utils.getElementTop(scrollEventTarget);
needLoadMoreToUpper = elementTop + this.offset > 0;
}
if (needLoadMoreToUpper) {
this.cb['upper'] && this.cb['upper']({ target: scrollEventTarget, top: targetScrollTop });
}
}
export default function(type) {
return {
bind(el, binding, vnode) {
if (!el[CONTEXT]) {
el[CONTEXT] = {
el,
vm: vnode.context,
cb: {}
};
}
el[CONTEXT].cb[type] = binding.value;
vnode.context.$on('hook:mounted', function() {
if (Utils.isAttached(el)) {
doBindEvent.call(el[CONTEXT]);
}
});
},
update(el) {
el[CONTEXT].scrollEventListener();
},
unbind(el) {
const context = el[CONTEXT];
context.scrollEventTarget.removeEventListener('scroll', context.scrollEventListener);
}
};
};

View File

@ -0,0 +1,14 @@
import Waterfall from './directive.js';
import Vue from 'vue';
const install = function(Vue) {
Vue.directive('WaterfallLower', Waterfall('lower'));
Vue.directive('WaterfallUpper', Waterfall('upper'));
};
if (!Vue.prototype.$isServer) {
Vue.use(install);
}
Waterfall.install = install;
export default Waterfall;

View File

@ -0,0 +1,75 @@
export default {
debounce(func, wait, immediate) {
var timeout, args, context, timestamp, result;
return function() {
context = this;
args = arguments;
timestamp = new Date();
var later = function() {
var last = (new Date()) - timestamp;
if (last < wait) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
result = func.apply(context, args);
}
};
if (!timeout) {
timeout = setTimeout(later, wait);
}
return result;
};
},
// 找到最近的触发滚动事件的元素
getScrollEventTarget(element) {
var currentNode = element;
// bugfix, see http://w3help.org/zh-cn/causes/SD9013 and http://stackoverflow.com/questions/17016740/onscroll-function-is-not-working-for-chrome
while (currentNode && currentNode.tagName !== 'HTML' && currentNode.tagName !== 'BODY' && currentNode.nodeType === 1) {
var overflowY = this.getComputedStyle(currentNode).overflowY;
if (overflowY === 'scroll' || overflowY === 'auto') {
return currentNode;
}
currentNode = currentNode.parentNode;
}
return window;
},
// 判断元素是否被加入到页面节点内
isAttached(element) {
var currentNode = element.parentNode;
while (currentNode) {
if (currentNode.tagName === 'HTML') {
return true;
}
if (currentNode.nodeType === 11) {
return false;
}
currentNode = currentNode.parentNode;
}
return false;
},
// 获取滚动高度
getScrollTop(element) {
return 'scrollTop' in element ? element.scrollTop : element.pageYOffset;
},
// 获取元素距离顶部高度
getElementTop(element) {
if (element === window) {
return this.getScrollTop(window);
}
return element.getBoundingClientRect().top + this.getScrollTop(window);
},
getVisibleHeight(element) {
if (element === window) {
return element.innerHeight;
}
return element.getBoundingClientRect().height;
},
getComputedStyle: document.defaultView.getComputedStyle.bind(document.defaultView)
};

View File

@ -9,6 +9,7 @@ import Popup from '../packages/popup/index.js';
import Dialog from '../packages/dialog/index.js';
import Picker from '../packages/picker/index.js';
import RadioGroup from '../packages/radio-group/index.js';
import Waterfall from '../packages/waterfall/index.js';
import Loading from '../packages/loading/index.js';
import Panel from '../packages/panel/index.js';
import Card from '../packages/card/index.js';
@ -50,6 +51,7 @@ module.exports = {
Dialog,
Picker,
RadioGroup,
Waterfall,
Loading,
Panel,
Card