123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445 |
- // [z-paging]scroll相关模块
- import u from '.././z-paging-utils'
- import Enum from '.././z-paging-enum'
- // #ifdef APP-NVUE
- const weexDom = weex.requireModule('dom');
- // #endif
- export default {
- props: {
- //使用页面滚动,默认为否,当设置为是时则使用页面的滚动而非此组件内部的scroll-view的滚动,使用页面滚动时z-paging无需设置确定的高度且对于长列表展示性能更高,但配置会略微繁琐
- usePageScroll: {
- type: Boolean,
- default: u.gc('usePageScroll', false)
- },
- //是否可以滚动,使用内置scroll-view和nvue时有效,默认为是
- scrollable: {
- type: Boolean,
- default: u.gc('scrollable', true)
- },
- //控制是否出现滚动条,默认为是
- showScrollbar: {
- type: Boolean,
- default: u.gc('showScrollbar', true)
- },
- //是否允许横向滚动,默认为否
- scrollX: {
- type: Boolean,
- default: u.gc('scrollX', false)
- },
- //iOS设备上滚动到顶部时是否允许回弹效果,默认为否。关闭回弹效果后可使滚动到顶部与下拉刷新更连贯,但是有吸顶view时滚动到顶部时可能出现抖动。
- scrollToTopBounceEnabled: {
- type: Boolean,
- default: u.gc('scrollToTopBounceEnabled', false)
- },
- //iOS设备上滚动到底部时是否允许回弹效果,默认为是。
- scrollToBottomBounceEnabled: {
- type: Boolean,
- default: u.gc('scrollToBottomBounceEnabled', true)
- },
- //在设置滚动条位置时使用动画过渡,默认为否
- scrollWithAnimation: {
- type: Boolean,
- default: u.gc('scrollWithAnimation', false)
- },
- //值应为某子元素id(id不能以数字开头)。设置哪个方向可滚动,则在哪个方向滚动到该元素
- scrollIntoView: {
- type: String,
- default: u.gc('scrollIntoView', '')
- },
- },
- data() {
- return {
- scrollTop: 0,
- oldScrollTop: 0,
- scrollViewStyle: {},
- scrollViewContainerStyle: {},
- scrollViewInStyle: {},
- pageScrollTop: -1,
- scrollEnable: true,
- privateScrollWithAnimation: -1,
- cacheScrollNodeHeight: -1
- }
- },
- watch: {
- oldScrollTop(newVal) {
- !this.usePageScroll && this._scrollTopChange(newVal,false);
- },
- pageScrollTop(newVal) {
- this.usePageScroll && this._scrollTopChange(newVal,true);
- },
- usePageScroll: {
- handler(newVal) {
- this.loaded && this.autoHeight && this._setAutoHeight(!newVal)
- // #ifdef H5
- if (newVal) {
- this.$nextTick(()=>{
- const mainScrollRef = this.$refs['zp-scroll-view'].$refs.main;
- if (mainScrollRef) {
- mainScrollRef.style = {};
- }
- })
- }
- // #endif
- },
- immediate: true
- },
- finalScrollTop(newVal) {
- if (!this.useChatRecordMode) {
- this.renderPropScrollTop = newVal < 6 ? 0 : 10;
- }
- },
- },
- computed: {
- finalScrollWithAnimation() {
- if (this.privateScrollWithAnimation !== -1) {
- const scrollWithAnimation = this.privateScrollWithAnimation === 1;
- this.privateScrollWithAnimation = -1;
- return scrollWithAnimation;
- }
- return this.scrollWithAnimation;
- },
- finalScrollViewStyle() {
- if (this.superContentZIndex != 1) {
- this.scrollViewStyle['z-index'] = this.superContentZIndex;
- this.scrollViewStyle['position'] = 'relative';
- }
- return this.scrollViewStyle;
- },
- finalScrollTop() {
- return this.usePageScroll ? this.pageScrollTop : this.oldScrollTop;
- },
- finalIsOldWebView() {
- return this.isOldWebView && !this.usePageScroll;
- }
- },
- methods: {
- //滚动到顶部,animate为是否展示滚动动画,默认为是
- scrollToTop(animate, checkReverse = true) {
- // #ifdef APP-NVUE
- if (checkReverse && this.useChatRecordMode) {
- if(!this.nIsFirstPageAndNoMore){
- this.scrollToBottom(animate, false);
- return;
- }
- }
- // #endif
- this.$nextTick(() => {
- this._scrollToTop(animate, false);
- // #ifdef APP-NVUE
- if (this.nvueFastScroll && animate) {
- setTimeout(() => {
- this._scrollToTop(false, false);
- }, 150);
- }
- // #endif
- })
- },
- //滚动到底部,animate为是否展示滚动动画,默认为是
- scrollToBottom(animate, checkReverse = true) {
- // #ifdef APP-NVUE
- if (checkReverse && this.useChatRecordMode) {
- if(!this.nIsFirstPageAndNoMore){
- this.scrollToTop(animate, false);
- return;
- }
- }
- // #endif
- this.$nextTick(() => {
- this._scrollToBottom(animate);
- // #ifdef APP-NVUE
- if (this.nvueFastScroll && animate) {
- setTimeout(() => {
- this._scrollToBottom(false);
- }, 150);
- }
- // #endif
- })
- },
- //滚动到指定view(vue中有效)。sel为需要滚动的view的id值,不包含"#";offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
- scrollIntoViewById(sel, offset, animate) {
- this._scrollIntoView(sel, offset, animate);
- },
- //滚动到指定view(vue中有效)。nodeTop为需要滚动的view的top值(通过uni.createSelectorQuery()获取);offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
- scrollIntoViewByNodeTop(nodeTop, offset, animate) {
- this.scrollTop = this.oldScrollTop;
- this.$nextTick(() => {
- this._scrollIntoViewByNodeTop(nodeTop, offset, animate);
- })
- },
- //滚动到指定位置(vue中有效)。y为与顶部的距离,单位为px;offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
- scrollToY(y, offset, animate) {
- this.scrollTop = this.oldScrollTop;
- this.$nextTick(() => {
- this._scrollToY(y, offset, animate);
- })
- },
- //滚动到指定view(nvue中有效)。index为需要滚动的view的index(第几个);offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
- scrollIntoViewByIndex(index, offset, animate) {
- this._scrollIntoView(index, offset, animate);
- },
- //滚动到指定view(nvue中有效)。view为需要滚动的view(通过`this.$refs.xxx`获取),不包含"#";offset为偏移量,单位为px;animate为是否展示滚动动画,默认为否
- scrollIntoViewByView(view, offset, animate) {
- this._scrollIntoView(view, offset, animate);
- },
- //当使用页面滚动并且自定义下拉刷新时,请在页面的onPageScroll中调用此方法,告知z-paging当前的pageScrollTop,否则会导致在任意位置都可以下拉刷新
- updatePageScrollTop(value) {
- this.pageScrollTop = value;
- },
- //当使用页面滚动并且设置了slot="top"时,默认初次加载会自动获取其高度,并使内部容器下移,当slot="top"的view高度动态改变时,在其高度需要更新时调用此方法
- updatePageScrollTopHeight() {
- this._updatePageScrollTopOrBottomHeight('top');
- },
- //当使用页面滚动并且设置了slot="bottom"时,默认初次加载会自动获取其高度,并使内部容器下移,当slot="bottom"的view高度动态改变时,在其高度需要更新时调用此方法
- updatePageScrollBottomHeight() {
- this._updatePageScrollTopOrBottomHeight('bottom');
- },
- //更新slot="left"和slot="right"宽度,当slot="left"或slot="right"宽度动态改变时调用
- updateLeftAndRightWidth() {
- this.$nextTick(() => {
- this._updateLeftAndRightWidth();
- })
- },
- //更新z-paging内置scroll-view的scrollTop
- updateScrollViewScrollTop(scrollTop, animate = true) {
- this.privateScrollWithAnimation = animate ? 1 : 0;
- this.scrollTop = this.oldScrollTop;
- this.$nextTick(() => {
- this.scrollTop = scrollTop;
- this.oldScrollTop = this.scrollTop;
- });
- },
-
- //当滚动到顶部时
- _scrollToUpper() {
- this.$emit('scrolltoupper');
- this.$emit('scrollTopChange', 0);
- this.$nextTick(() => {
- this.oldScrollTop = 0;
- })
- if (!this.useChatRecordMode) return;
- if (this.loadingStatus === Enum.More.NoMore) return;
- this._onLoadingMore('click');
- },
- //滚动到顶部
- _scrollToTop(animate = true, isPrivate = true) {
- // #ifdef APP-NVUE
- const el = this.$refs['zp-n-list-top-tag'];
- if (this.usePageScroll) {
- this._getNodeClientRect('zp-page-scroll-top', false).then((node) => {
- const nodeHeight = node ? node[0].height : 0;
- weexDom.scrollToElement(el, {
- offset: -nodeHeight,
- animated: animate
- });
- });
- } else {
- if (!this.isIos && this.nvueListIs === 'scroller') {
- this._getNodeClientRect('zp-n-refresh-container', false).then((node) => {
- const nodeHeight = node ? node[0].height : 0;
- weexDom.scrollToElement(el, {
- offset: -nodeHeight,
- animated: animate
- });
- });
- } else {
- weexDom.scrollToElement(el, {
- offset: 0,
- animated: animate
- });
- }
- }
- return;
- // #endif
- if (this.usePageScroll) {
- this.$nextTick(() => {
- uni.pageScrollTo({
- scrollTop: 0,
- duration: animate ? 100 : 0,
- });
- });
- return;
- }
- this.privateScrollWithAnimation = animate ? 1 : 0;
- this.scrollTop = this.oldScrollTop;
- this.$nextTick(() => {
- this.scrollTop = 0;
- this.oldScrollTop = this.scrollTop;
- });
- },
- //滚动到底部
- async _scrollToBottom(animate = true) {
- // #ifdef APP-NVUE
- const el = this.$refs['zp-n-list-bottom-tag'];
- if (el) {
- weexDom.scrollToElement(el, {
- offset: 0,
- animated: animate
- });
- } else {
- u.consoleErr('滚动到底部失败,因为您设置了hideNvueBottomTag为true');
- }
- return;
- // #endif
- if (this.usePageScroll) {
- this.$nextTick(() => {
- uni.pageScrollTo({
- scrollTop: Number.MAX_VALUE,
- duration: animate ? 100 : 0,
- });
- });
- return;
- }
- try {
- this.privateScrollWithAnimation = animate ? 1 : 0;
- const pagingContainerNode = await this._getNodeClientRect('.zp-paging-container');
- const scrollViewNode = await this._getNodeClientRect('.zp-scroll-view');
- const pagingContainerH = pagingContainerNode ? pagingContainerNode[0].height : 0;
- const scrollViewH = scrollViewNode ? scrollViewNode[0].height : 0;
- if (pagingContainerH > scrollViewH) {
- this.scrollTop = this.oldScrollTop;
- this.$nextTick(() => {
- this.scrollTop = pagingContainerH - scrollViewH + this.virtualPlaceholderTopHeight;
- this.oldScrollTop = this.scrollTop;
- });
- }
- } catch (e) {}
- },
- //滚动到指定view
- _scrollIntoView(sel, offset = 0, animate = false, finishCallback) {
- try {
- this.scrollTop = this.oldScrollTop;
- this.$nextTick(() => {
- // #ifdef APP-NVUE
- const refs = this.$parent.$refs;
- if (!refs) return;
- const dataType = Object.prototype.toString.call(sel);
- let el = null;
- if (dataType === '[object Number]') {
- const els = refs[`z-paging-${sel}`];
- el = els ? els[0] : null;
- } else if (dataType === '[object Array]') {
- el = sel[0];
- } else {
- el = sel;
- }
- if (el) {
- weexDom.scrollToElement(el, {
- offset: -offset,
- animated: animate
- });
- } else {
- u.consoleErr('在nvue中滚动到指定位置,cell必须设置 :ref="`z-paging-${index}`"');
- }
- return;
- // #endif
- if (sel.indexOf('#') != -1) {
- sel = sel.replace('#', '');
- }
- this._getNodeClientRect('#' + sel, false).then((node) => {
- if (node) {
- let nodeTop = node[0].top;
- this._scrollIntoViewByNodeTop(nodeTop, offset, animate);
- if (finishCallback) {
- finishCallback();
- }
- }
- });
- });
- } catch (e) {}
- },
- //通过nodeTop滚动到指定view
- _scrollIntoViewByNodeTop(nodeTop, offset = 0, animate = false) {
- this._scrollToY(nodeTop, offset, animate, true);
- },
- //滚动到指定位置
- _scrollToY(y, offset = 0, animate = false, addScrollTop = false) {
- this.privateScrollWithAnimation = animate ? 1 : 0;
- if (this.usePageScroll) {
- uni.pageScrollTo({
- scrollTop: y - offset,
- duration: animate ? 100 : 0
- });
- } else {
- if(addScrollTop){
- y += this.oldScrollTop;
- }
- this.scrollTop = y - offset;
- this.oldScrollTop = this.scrollTop;
- }
- },
- //scroll-view滚动中
- _scroll(e) {
- this.$emit('scroll', e);
- const scrollTop = e.detail.scrollTop;
- // #ifndef APP-NVUE
- this.finalUseVirtualList && this._updateVirtualScroll(scrollTop, this.oldScrollTop - scrollTop);
- // #endif
- this.oldScrollTop = scrollTop;
- const scrollDiff = e.detail.scrollHeight - this.oldScrollTop;
- !this.isIos && this._checkScrolledToBottom(scrollDiff);
- },
- //scrollTop改变时触发
- _scrollTopChange(newVal, isPageScrollTop){
- this.$emit('scrollTopChange', newVal);
- this.$emit('update:scrollTop', newVal);
- this._checkShouldShowBackToTop(newVal);
- const scrollTop = this.isIos ? (newVal > 5 ? 6 : 0) : newVal;
- if (isPageScrollTop) {
- this.wxsPageScrollTop = scrollTop;
- } else {
- this.wxsScrollTop = scrollTop;
- }
- },
- //更新使用页面滚动时slot="top"或"bottom"插入view的高度
- _updatePageScrollTopOrBottomHeight(type) {
- // #ifndef APP-NVUE
- if (!this.usePageScroll) return;
- // #endif
- this._doCheckScrollViewShouldFullHeight(this.realTotalData);
- const node = `.zp-page-${type}`;
- const marginText = `margin${type.slice(0,1).toUpperCase() + type.slice(1)}`;
- let safeAreaInsetBottomAdd = this.safeAreaInsetBottom;
- this.$nextTick(() => {
- let delayTime = 0;
- // #ifdef MP-BAIDU || APP-NVUE
- delayTime = 50;
- // #endif
- setTimeout(() => {
- this._getNodeClientRect(node).then((res) => {
- if (res) {
- let pageScrollNodeHeight = res[0].height;
- if (type === 'bottom') {
- if (safeAreaInsetBottomAdd) {
- pageScrollNodeHeight += this.safeAreaBottom;
- }
- } else {
- this.cacheTopHeight = pageScrollNodeHeight;
- }
- this.$set(this.scrollViewStyle, marginText, `${pageScrollNodeHeight}px`);
- } else if (safeAreaInsetBottomAdd) {
- this.$set(this.scrollViewStyle, marginText, `${this.safeAreaBottom}px`);
- }
- });
- }, delayTime)
- })
- },
- //获取slot="left"和slot="right"宽度并且更新布局
- _updateLeftAndRightWidth(){
- if (!this.finalIsOldWebView) return;
- this.$nextTick(() => {
- let delayTime = 0;
- // #ifdef MP-BAIDU
- delayTime = 10;
- // #endif
- setTimeout(() => {
- ['left','right'].map(position => {
- this._getNodeClientRect(`.zp-page-${position}`).then((res) => {
- this.$set(this.scrollViewContainerStyle, position, res ? res[0].width + 'px' : '0px');
- });
- })
- }, delayTime)
- })
- }
- }
- }
|