精华内容
下载资源
问答
  • vue实现滚动加载更多数据

    千次阅读 2018-12-08 16:54:33
    1、参考线位置lineHeight:即判断滚动到何处触发事件;  2、页面卷入的高度scrollHeight;  3、浏览器窗口的高度windowHeight。 当页面首次登录的时候已经加载第一页数据,记录第一页数据参考线的高度firstPageH...

    原理:

    1、参考线位置lineHeight:即判断滚动到何处触发事件; 
    2、页面卷入的高度scrollHeight; 
    3、浏览器窗口的高度windowHeight。

    当页面首次登录的时候已经加载第一页数据,记录第一页数据参考线的高度firstPageH,计算每页增加数据的高度pageH,当增加第N页数据时参考线的高度位置: lineHeight=firstPageH+pageH*N;


    代码:

     created(){
        var _this=this;
        $(window).scroll(function(){
          var lineHeight=700+930*_this.pageSN;  //默认第一页时 _this.pageSN=1;
          var windowHeight=$(window).height();
          var scrollTop=document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
          if(scrollTop+windowHeight>=lineHeight){
            _this.pageSN++;   
            _this.goPage(_this.pageSN); // 执行增加页面数据操作
          } 
        });
      }

     


    页面常见高度、宽度相关计算

    网页可见区域宽: document.body.clientWidth 
    网页可见区域高: document.body.clientHeight 
    网页可见区域宽: document.body.offsetWidth (包括边线的宽) 
    网页可见区域高: document.body.offsetHeight (包括边线的高) 
    网页正文全文宽: document.body.scrollWidth 
    网页正文全文高: document.body.scrollHeight 
    网页被卷去的高: document.body.scrollTop 
    网页被卷去的左: document.body.scrollLeft 
    网页正文部分上: window.screenTop 
    网页正文部分左: window.screenLeft 
    屏幕分辨率的高: window.screen.height 
    屏幕分辨率的宽: window.screen.width 
    屏幕可用工作区高度: window.screen.availHeight 
    屏幕可用工作区宽度: window.screen.availWidth

    //jQuery函数 
    (window).height();//浏览器当前窗口可视区域高度(window).height();//浏览器当前窗口可视区域高度(document).height(); //浏览器当前窗口文档的高度 
    (document.body).height();//浏览器当前窗口文档body的高度(document.body).height();//浏览器当前窗口文档body的高度(document.body).outerHeight(true) //浏览器当前窗口文档body的总高度 包括border padding margin 
    (window).width() //浏览器当前窗口可视区域的宽度(window).width() //浏览器当前窗口可视区域的宽度(document).width()//浏览器当前窗口文档的宽度 
    (document.body).width()      //浏览器时下窗口文档body的高度(document.body).width()      //浏览器时下窗口文档body的高度(document.body).outerWidth(true) //浏览器时下窗口文档body的总宽度 包括border padding


    https://blog.csdn.net/shengmeshi/article/details/77948248

    展开全文
  • 横向滑动加载更多的控件的实现

    千次阅读 2015-12-28 20:15:02
    公司业务要求做一个横向滑动的,可以加载更多的控件。参考了郭霖大神关于下拉刷新的博客,地址为:http://blog.csdn.net/guolin_blog/article/details/9255575。在此基础上进行了改进,使之能适应横向加载更多的...

    概述:
    公司业务要求做一个横向滑动的,可以加载更多的控件。参考了郭霖大神关于下拉刷新的博客,地址为:http://blog.csdn.net/guolin_blog/article/details/9255575。在此基础上进行了改进,使之能适应横向加载更多的需求。横向滑动的控件采用的是RecyclerView,在外面包裹了本文介绍的控件。
    思路:
    控件继承自RelativeLayout,并重写dispatchTouchEvent()事件,当横向滑动的RecyclerView的右边缘滑动到控件的右边缘时,将隐藏的侧拉头跟随手势慢慢拉出。这中间伴随着侧拉头的状态实时的改变。松手时,如果侧拉的距离已经足够多,则回调onRefresh()方式。当回调结束时,需要手动停止刷新状态,让侧拉头再次隐藏。
    好了,废话不多说,上代码:

    package xxx;
    
    import android.content.Context;
    import android.os.AsyncTask;
    import android.support.v7.widget.RecyclerView;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewConfiguration;
    import android.view.animation.RotateAnimation;
    import android.widget.ImageView;
    import android.widget.ProgressBar;
    import android.widget.RelativeLayout;
    
    import xxx.R;
    
    /**
     * 可进行左拉加载更多的自定义控件。
     * 原理:1、当横向网格右边缘滑动到父控件右边缘时,让隐藏的侧拉头逐渐出现;
     *      2、松手后,开始刷新;
     *      3、完成后隐藏侧拉头
     * 
     * @author jxl
     * 
     */
    public class RefreshableView extends RelativeLayout {
    
        private static final String TAG = "hello";
    
        /**
         * 左拉状态
         */
        public static final int STATUS_PULL_TO_REFRESH = 0;
    
        /**
         * 释放立即刷新状态
         */
        public static final int STATUS_RELEASE_TO_REFRESH = 1;
    
        /**
         * 正在刷新状态
         */
        public static final int STATUS_REFRESHING = 2;
    
        /**
         * 刷新完成或未刷新状态
         */
        public static final int STATUS_REFRESH_FINISHED = 3;
    
        /**
         * 左拉头部回滚的速度
         */
        public static final int SCROLL_SPEED = -20;
    
        /**
         * 左拉加载更多的回调接口
         */
        private PullToRefreshListener mListener;
    
        /**
         * 左拉头的View
         */
        private View header;
    
        /**
         * 需要去左拉刷新的横置RecyclerView
         */
        private RecyclerView refreshView;
    
        /**
         * 刷新时显示的进度条
         */
        private ProgressBar progressBar;
    
        /**
         * 指示左拉和释放的箭头
         */
        private ImageView arrow;
    
        /**
         * 左拉头的布局参数
         */
        private LayoutParams headerLayoutParams;
    
        /**
         * 为了防止不同界面的左拉加载更多在上次更新时间上互相有冲突,使用id来做区分
         */
        private int mId = -1;
    
        /**
         * 左拉头的宽度
         */
        private int hideHeaderWidth;
    
        /**
         * 当前处理什么状态,可选值有STATUS_PULL_TO_REFRESH, STATUS_RELEASE_TO_REFRESH,
         * STATUS_REFRESHING 和 STATUS_REFRESH_FINISHED
         */
        private int currentStatus = STATUS_REFRESH_FINISHED;;
    
        /**
         * 记录上一次的状态是什么,避免进行重复操作
         */
        private int lastStatus = currentStatus;
    
        /**
         * 手指按下时的屏幕横坐标
         */
        private float xDown;
    
        /**
         * 在被判定为滚动之前用户手指可以移动的最大值。
         */
        private int touchSlop;
    
        /**
         * 是否已加载过一次layout,这里onLayout中的初始化只需加载一次
         */
        private boolean loadOnce;
    
        /**
         * 当前是否可以左拉,只有RecyclerView滚动到头的时候才允许左拉
         */
        private boolean ableToPull;
    
        /**
         * 是否允许加载
         */
        private boolean allowPull = true;
    
        /**
         * 左拉加载更多控件的构造函数
         * 
         * @param context
         * @param attrs
         */
        public RefreshableView(Context context, AttributeSet attrs) {
            super(context, attrs);
            touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        }
    
        /**
         * 进行一些关键性的初始化操作,比如:添加一个左拉头的布局,将左拉头向右偏移进行隐藏。
         */
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            super.onLayout(changed, l, t, r, b);
            if (changed && !loadOnce) {
                header = getChildAt(1);
                progressBar = (ProgressBar) header.findViewById(R.id.progress_bar);
                arrow = (ImageView) header.findViewById(R.id.arrow);
    
                refreshView = (RecyclerView) getChildAt(0);
                if(refreshView.getWidth() >= getWidth()) {
                    hideHeaderWidth = - header.getWidth();
                    headerLayoutParams = (LayoutParams) header.getLayoutParams();
                    headerLayoutParams.rightMargin = hideHeaderWidth;
                    headerLayoutParams.addRule(CENTER_VERTICAL);
                    headerLayoutParams.addRule(ALIGN_PARENT_END);
                    header.setVisibility(View.INVISIBLE);//开始时要隐藏侧拉头
                } else {//如果refreshView 为空,则不允许侧拉加载更多
                    header.setVisibility(View.GONE);
                    ableToPull = false;
                }
    
                loadOnce = true;
            }
        }
    
        /**
         * 设置是否开启下拉加载更多
         * @param allowPull
         */
        public void setAllowPull(boolean allowPull) {
            this.allowPull = allowPull;
        }
    
        /**
         * 当refreshView 被触摸时调用,其中处理了各种左拉加载更多的具体逻辑。
         */
        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            setIsAbleToPull(event);
            if (ableToPull) {
                header.setVisibility(View.VISIBLE);
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        xDown = event.getRawX();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        float xMove = event.getRawX();
                        int distance = (int) (xMove - xDown);
                        // 如果手指右滑状态,并且左拉头是完全隐藏的,就屏蔽左拉事件
                        if (distance >= 0 && headerLayoutParams.rightMargin <= hideHeaderWidth) {
                            return super.dispatchTouchEvent(event);
                        }
                        if (distance > -touchSlop) {
                            return false;
                        }
                        if (currentStatus != STATUS_REFRESHING) {
                            if (headerLayoutParams.rightMargin >= 0) {
                                currentStatus = STATUS_RELEASE_TO_REFRESH;
                            } else {
                                currentStatus = STATUS_PULL_TO_REFRESH;
                            }
                            // 通过偏移左拉头的topMargin值,来实现左拉效果
                            headerLayoutParams.rightMargin = (-distance / 2) + hideHeaderWidth;
                            header.setLayoutParams(headerLayoutParams);
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                    default:
                        if (currentStatus == STATUS_RELEASE_TO_REFRESH) {
                            // 松手时如果是释放立即刷新状态,就去调用正在刷新的任务
                            new RefreshingTask().execute();
                        } else if (currentStatus == STATUS_PULL_TO_REFRESH) {
                            // 松手时如果是左拉状态,就去调用隐藏左拉头的任务
                            new HideHeaderTask().execute();
                        }
                        break;
                }
                // 时刻记得更新左拉头中的信息
                if (currentStatus == STATUS_PULL_TO_REFRESH
                        || currentStatus == STATUS_RELEASE_TO_REFRESH) {
                    updateHeaderView();
                    // 当前正处于左拉或释放状态,要让refreshView 失去焦点,否则被点击的那一项会一直处于选中状态
                    refreshView.setPressed(false);
                    refreshView.setFocusable(false);
                    refreshView.setFocusableInTouchMode(false);
                    lastStatus = currentStatus;
                    // 当前正处于左拉或释放状态,通过返回true屏蔽掉refreshView 的滚动事件
                    return true;
                }
            }
            return super.dispatchTouchEvent(event);
        }
    
        /**
         * 给左拉加载更多控件注册一个监听器。
         * 
         * @param listener
         *            监听器的实现。
         * @param id
         *            为了防止不同界面的左拉加载更多在上次更新时间上互相有冲突, 请不同界面在注册左拉加载更多监听器时一定要传入不同的id。
         */
        public void setOnRefreshListener(PullToRefreshListener listener, int id) {
            mListener = listener;
            mId = id;
        }
    
        /**
         * 当所有的刷新逻辑完成后,记录调用一下,否则你的refreshView 将一直处于正在刷新状态。
         */
        public void finishRefreshing() {
            currentStatus = STATUS_REFRESH_FINISHED;
            new HideHeaderTask().execute();
        }
    
        /**
         * 根据当前refreshView 的滚动状态来设定 {@link #ableToPull}
         * 的值,每次都需要在onTouch中第一个执行,这样可以判断出当前应该是滚动refreshView ,还是应该进行左拉。
         * 
         * @param event
         */
        private void setIsAbleToPull(MotionEvent event) {
            View lastChild = refreshView.getChildAt(refreshView.getChildCount() -1);
            if(lastChild != null) {
                //如果最后一个item的右边缘小于等于控件的款宽度,说明refreshView 已经滑动到左边或者左拉,此时应该允许左拉加载更多
                if(lastChild.getRight() <= getWidth()) {
                    ableToPull = true;
                } else {
                    if (headerLayoutParams.rightMargin != hideHeaderWidth) {
                        headerLayoutParams.rightMargin = hideHeaderWidth;
                        header.setLayoutParams(headerLayoutParams);
                    }
                    ableToPull = false;
                }
            } else {
                //如果没有元素,不允许加载更多
                ableToPull = false;
            }
            if(!allowPull) {
                ableToPull = false;
            }
        }
    
        /**
         * 更新左拉头中的信息。
         */
        private void updateHeaderView() {
            if (lastStatus != currentStatus) {
                if (currentStatus == STATUS_PULL_TO_REFRESH) {
                    arrow.setVisibility(View.VISIBLE);
                    progressBar.setVisibility(View.GONE);
                    rotateArrow();
                } else if (currentStatus == STATUS_RELEASE_TO_REFRESH) {
                    arrow.setVisibility(View.VISIBLE);
                    progressBar.setVisibility(View.GONE);
                    rotateArrow();
                } else if (currentStatus == STATUS_REFRESHING) {
                    progressBar.setVisibility(View.VISIBLE);
                    arrow.clearAnimation();
                    arrow.setVisibility(View.GONE);
                }
            }
        }
    
        /**
         * 根据当前的状态来旋转箭头。
         */
        private void rotateArrow() {
            float pivotX = arrow.getWidth() / 2f;
            float pivotY = arrow.getHeight() / 2f;
            float fromDegrees = 0f;
            float toDegrees = 0f;
            if (currentStatus == STATUS_PULL_TO_REFRESH) {
                fromDegrees = 180f;
                toDegrees = 360f;
            } else if (currentStatus == STATUS_RELEASE_TO_REFRESH) {
                fromDegrees = 0f;
                toDegrees = 180f;
            }
            RotateAnimation animation = new RotateAnimation(fromDegrees, toDegrees, pivotX, pivotY);
            animation.setDuration(100);
            animation.setFillAfter(true);
            arrow.startAnimation(animation);
        }
    
        /**
         * 正在刷新的任务,在此任务中会去回调注册进来的左拉加载更多监听器。
         * 
         * @author jxl
         */
        class RefreshingTask extends AsyncTask<Void, Integer, Integer> {
    
            @Override
            protected Integer doInBackground(Void... params) {
                int topMargin = headerLayoutParams.rightMargin;
                while (true) {
                    topMargin = topMargin + SCROLL_SPEED;
                    if (topMargin <= 0) {
                        topMargin = 0;
                        break;
                    }
                    publishProgress(topMargin);
                    sleep(10);
                }
                currentStatus = STATUS_REFRESHING;
                publishProgress(0);
                return topMargin;
            }
    
            @Override
            protected void onProgressUpdate(Integer... topMargin) {
                updateHeaderView();
                headerLayoutParams.rightMargin = topMargin[0];
                header.setLayoutParams(headerLayoutParams);
            }
    
            @Override
            protected void onPostExecute(Integer topMargin) {
                if (mListener != null) {
                    mListener.onRefresh();
                }
            }
        }
    
        /**
         * 隐藏左拉头的任务,当未进行左拉加载更多或左拉加载更多完成后,此任务将会使左拉头重新隐藏。
         * 
         * @author jxl
         */
        class HideHeaderTask extends AsyncTask<Void, Integer, Integer> {
    
            @Override
            protected Integer doInBackground(Void... params) {
                int topMargin = headerLayoutParams.rightMargin;
                while (true) {
                    topMargin = topMargin + SCROLL_SPEED;
                    if (topMargin <= hideHeaderWidth) {
                        topMargin = hideHeaderWidth;
                        break;
                    }
                    publishProgress(topMargin);
                    sleep(10);
                }
                return topMargin;
            }
    
            @Override
            protected void onProgressUpdate(Integer... topMargin) {
                headerLayoutParams.rightMargin = topMargin[0];
                header.setLayoutParams(headerLayoutParams);
            }
    
            @Override
            protected void onPostExecute(Integer topMargin) {
                headerLayoutParams.rightMargin = topMargin;
                header.setLayoutParams(headerLayoutParams);
                currentStatus = STATUS_REFRESH_FINISHED;
            }
        }
    
        /**
         * 使当前线程睡眠指定的毫秒数。
         * 
         * @param time
         *            指定当前线程睡眠多久,以毫秒为单位
         */
        private void sleep(int time) {
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 左拉加载更多的监听器,使用左拉加载更多的地方应该注册此监听器来获取刷新回调。
         * 
         * @author jxl
         */
        public interface PullToRefreshListener {
    
            /**
             * 刷新时会去回调此方法,在方法内编写具体的刷新逻辑。注意此方法是在子线程中调用的, 你可以不必另开线程来进行耗时操作。
             */
            void onRefresh();
    
        }
    
    }
    
        下面看下侧拉头的布局:
    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="75dp"
        android:layout_height="match_parent" >
    
        <RelativeLayout 
            android:layout_width="75dp"
            android:layout_height="match_parent"
            android:layout_centerInParent="true"
            android:background="@android:color/transparent">
    
            <ImageView 
               android:id="@+id/arrow"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
               android:layout_centerInParent="true"
               android:src="@drawable/arrow"
               />
           <ProgressBar 
               android:id="@+id/progress_bar"
               android:layout_width="45dp"
               android:layout_height="45dp"
               android:layout_centerInParent="true"
               android:visibility="gone"
               />
        </RelativeLayout>
    </RelativeLayout>
        相对于郭大神的布局,这里做了简化,去除了状态描述和时间记录,看起来比较清爽。
        下面是引用此下拉头的布局文件:
    
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingTop="@dimen/38dp">
    
        ……
    
        <xxx.RefreshableView
            android:id="@+id/refreshable_view"
            android:layout_width="match_parent"
            android:layout_height="381dp">
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/media_list"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scrollbars="none"/>
    
            <include
                layout="@layout/pull_to_refresh"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"/>
        </xxx.RefreshableView>
    </RelativeLayout>
        引用时要将侧拉头写在需要刷新的布局右边,像那上面那样。
        最后是引用刷新控件的代码。因为公司业务保密,只能贴出本文相关的代码:
    
    public class MediaListActivity extends Activity implements  RefreshableView.PullToRefreshListener{
    
     @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.media_list_layout);
    
            refreshView = (RefreshableView) findViewById(R.id.refreshable_view);
            refreshView.setOnRefreshListener(this, 0);
        }
    
        ……
    
         /**
         * 侧拉加载的回调接口
         */
        @Override
        public void onRefresh() {
            isRefresh = true;
            //此处执行刷新操作
            refreshView.finishRefreshing();
        }
    }
        主要代码都在这了,运行后,将RecyclerView向左滑动到头时,侧拉头中的箭头会逐渐伸出,悬浮在RecyclerView上方。
        松手后一个变成一个进度条在旋转。待刷新完成,进度条隐藏消失。至此,侧拉加载更多完成。
        在此基础上可以很方便的改成上拉,只需要将里面的横向的一些数据改成竖向的数据即可。
        另,滑动到最右边时,往左滑动会触发长按事件的bug已经修复。
    
    展开全文
  • vue瀑布流组件滑动加载更多

    万次阅读 2017-07-18 17:56:19
    建议先看上一篇再来食用本文,如果直接想看源码文末就是~上一篇讲到在项目中使用上拉加载更多组件,但是由于实际项目开发中由于需求变更或者说在webview中上拉加载有些机型在上拉时候会把webview也一起上拉导致上拉...

    建议先看vue瀑布流组件上拉加载更多再来食用本文,如果直接想看源码文末就是~

    文末新增组件优化,之所以没有删优化前的代码是想让以后自己还能看到走过的路。

    上一篇讲到在项目中使用上拉加载更多组件,但是由于实际项目开发中由于需求变更或者说在webview中上拉加载有些机型在上拉时候会把webview也一起上拉导致上拉加载不灵敏等问题,我们有时候也会换成滑动到底部自动加载的功能。

    既然都是加载更多,很多代码思想势必相似,主要区别在于上拉和滑动到底部这个操作上,所以,我们需要注意:

    1. 上拉加载是point指针touch触摸事件,现在因为是滑动加载,需要添加scroll事件去监听然后执行相应回调
    2. 上拉加载主要计算触摸滚动距离,滑动加载主要计算container底部和视窗上边缘的距离

    事件绑定改成:

       mounted() {
          ···
          this.dom.addEventListener('scroll', this.scroll, false)
          ···
        },
    
        beforeDestroy() {
            ···
            this.dom.removeEventListener('scroll', this.scroll, false)
            ···
        },

    事件回调改为:

         /**
           * 滚动钩子
           */
          scroll() {
            const viewHeight = global.innerHeight
            let parentNode
            if (this.container !== global) {
              parentNode = this.$el
            } else {
              parentNode = this.$el.parentNode
            }
            if (parentNode) {
              // 获取Vue实例使用的根 DOM 元素相对于视口的位置
              const rect = parentNode.getBoundingClientRect()
              // this.distance 离底部多少距离开始加载
              // 如果此元素底边距离视口顶部的距离小于视口高度加上distance之和,就加载下一页
              if ((rect.bottom <= viewHeight + this.distance) && this.loadable && !this.loading) {
                this.load()
              }
            }
          },

    源码如下:

    <template>
      <div class="loadmore" ref="loadmore">
        <div class="loadmore__body">
          <slot></slot>
        </div>
        <div class="loadmore__footer">
          <span v-if="loading">
            <i class="tc-loading"></i>
            <span>正在加载</span>
          </span>
          <span v-else-if="loadable">加载更多</span>
          <span v-else>没有更多了</span>
        </div>
      </div>
    </template>
    
    <script type="text/babel">
      import axios from 'axios'
    
      const CancelToken = axios.CancelToken
    
      export default {
        data() {
          return {
            /**
             * 总页数(由服务端返回)
             * @type {number}
             */
            count: 0,
    
            /**
             * 是否正在拖拽中
             * @type {boolean}
             */
            dragging: false,
    
            /**
             * 已加载次数
             * @type {number}
             */
            times: 0,
    
            /**
             * 已开始记载
             * @type {boolean}
             */
            started: false,
    
            /**
             * 正在加载中
             * @type {boolean}
             */
            loading: false,
    
            dom: null,
          }
        },
    
        props: {
          /**
           * 初始化后自动开始加载数据
           */
          autoload: {
            type: Boolean,
            default: true,
          },
    
          /**
           * 离组件最近的可滚动父级元素(用于监听事件及获取滚动条位置)
           */
          container: {
            // Selector or Element
            default: () => (global),
          },
    
          /**
           * Axios请求参数配置对象
           * {@link https://github.com/mzabriskie/axios#request-config}
           */
          options: {
            type: Object,
            default: null,
          },
    
          /**
           * 起始页码
           */
          page: {
            type: Number,
            default: 1,
          },
    
          /**
           * 每页加载数据条数
           */
          rows: {
            type: Number,
            default: 10,
          },
    
          /**
           * 数据加载请求地址
           */
          url: {
            type: String,
            default: '',
          },
    
          /**
           * 距离底部多远加载
           */
          distance: {
            type: Number,
            default: 200,
          },
        },
    
        computed: {
          /**
           * 是否可以加载
           * @returns {boolean} 是与否
           */
          loadable() {
            return !this.started || (this.page + this.times) <= this.count
          },
        },
    
        mounted() {
          if (this.container !== global) {
            this.dom = document.querySelector(this.container)
          } else {
            this.dom = this.container
          }
          if (!this.dom) {
            return
          }
          this.dom.addEventListener('scroll', this.scroll, false)
          if (this.autoload && !this.loading) {
            this.load()
          }
        },
    
        // eslint-disable-next-line
        beforeDestroy() {
          if (this.dom) {
            this.dom.removeEventListener('scroll', this.scroll, false)
          }
        },
    
        methods: {
          /**
           * 滚动钩子
           */
          scroll() {
            const viewHeight = global.innerHeight
            let parentNode
            if (this.container !== global) {
              parentNode = this.$el
            } else {
              parentNode = this.$el.parentNode
            }
            if (parentNode) {
              const rect = parentNode.getBoundingClientRect()
              if ((rect.bottom <= viewHeight + this.distance) && this.loadable && !this.loading) {
                this.load()
              }
            }
          },
          /**
           * 加载一组数据的方法
           */
          load() {
            if (this.loading) {
              return
            }
            this.started = true
            this.loading = true
    
            const params = {
              currentPage: this.page + this.times,
              pageSize: this.rows,
            }
            const options = Object.assign({}, this.options, {
              url: this.url,
              cancelToken: new CancelToken((cancel) => {
                this.cancel = cancel
              }),
            })
    
            if (String(options.method).toUpperCase() === 'POST') {
              options.data = Object.assign({}, options.data, params)
            } else {
              options.params = Object.assign({}, options.params, params)
            }
    
            this.$axios.request(options).then((res) => {
              const data = res.result
              this.times += 1
              this.loading = false
              this.count = data.pageCount
              this.$emit('success', data.list)
              this.$emit('complete')
            }).catch((e) => {
              this.loading = false
              this.$emit('error', e)
              this.$emit('complete')
            })
          },
    
          /**
           * 重置加载相关变量
           */
          reset() {
            this.count = 0
            this.times = 0
            this.started = false
            this.loading = false
          },
    
          /**
           *重新开始加载
           */
          restart() {
            this.reset()
            this.load()
          },
        },
      }
    </script>
    

    ———————-我是分割线——————–

    2017-09-18 组件优化

    我们在写组件时候,通常会大致先分为两种,业务组件通用组件,业务组件通和业务逻辑相关,一般作为一个业务模块的局部组件,
    比如列表中的列表项组件;通用组件适用面广,不会和业务有牵扯,比如弹出框组件。

    所以我们开始封装一个组件的时候,就要划分业务逻辑,做什么,不做什么,从外部接收什么,向外部提供什么,这个边界应该非常清楚

    但是之前的封装的loadmore组件不太符合这一点,可能是项目一开始比较关注功能的实现,将其当成的一个业务组件撰写,现在有一点需要优化:

    之前我们传入了各种请求相关的参数,包括url在组件内部完成加载和页码控制等一系列操作,显然这不太符合组件功能职责单一化的原则,
    其实组件内部并不关心加载到第几页或者是需要请求什么后端接口,而只要父组件告诉自己是否还可以加载就可以了,
    至于加载请求列表,子组件通知父组件去加载就OK。

    最终我们得到一个和业务完全分离的通用组件,代码如下:

    <template>
      <div class="loadmore" ref="loadmore">
        <div class="loadmore__body">
          <slot></slot>
        </div>
        <div class="loadmore__footer">
          <span v-if="loading">
            <i class="tc-loading"></i>
            <span>正在加载</span>
          </span>
           <span v-else-if="loading">正在加载...</span>
          <span v-else>没有更多了</span>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        /**
         * 是否加载
         */
        loading: {
          type: Boolean,
          default: false,
        },
    
        /**
         * 滚动外部容器, 选择器字符串
         */
        container: {
          default: () => (global),
        },
    
        /**
         * 距离底部多远加载
         */
        distance: {
          type: Number,
          default: 200,
        },
      },
    
      data() {
        return {
          dom: null, // 外部容器dom
        }
      },
      mounted() {
        if (this.container !== global) {
          this.dom = document.querySelector(this.container)
        } else {
          this.dom = this.container
        }
        if (!this.dom) {
          return
        }
        this.dom.addEventListener('scroll', this.scroll, false)
        if (this.autoload && !this.loading) {
          this.load()
        }
      },
    
      methods: {
        /**
         * 滚动钩子
         */
        scroll() {
          if (!this.loading) {
            return
          }
          const viewHeight = global.innerHeight
          let parentNode
          if (this.container !== global) {
            parentNode = this.$el
          } else {
            parentNode = this.$el.parentNode
          }
          if (parentNode) {
            const rect = parentNode.getBoundingClientRect()
            if ((rect.bottom <= viewHeight + this.distance)) {
              this.load()
            }
          }
        },
        /**
         * 加载一组数据的方法
         */
        load() {
          this.$emit('load')
        },
      },
      beforeDestroy() {
        if (this.dom) {
          this.dom.removeEventListener('scroll', this.scroll, false)
        }
      },
    }
    </script>
    <style lang="stylus" rel="stylesheet/stylus" scoped>
    .loadmore {
      user-select: none;
    
      &__footer {
        color: #e4e4e4;
        padding: 20px;
        text-align: center;
      }
    
      .tc-loading {
        ~ span {
          vertical-align: middle;
        }
      }
    }
    </style>
    
    展开全文
  • 利用MPAndroidChat 画出折线图并与后台对接了数据,现在要求:向左滑动可以加载更多数据, 具体不知道如何实现,调用什么方法。希望大神们搭手帮助解决,谢谢 ![图片说明]...
  • 下拉刷新 实现下拉刷新目前能想到的有两种方式 调用系统的API,系统有提供下拉刷新的API...忘记请自行回顾上一篇 微信小程序实战篇-电商(二)当滚动到顶部/左边,会触发 scrolltoupper 事件,所以我们可以利...

    下拉刷新

    实现下拉刷新目前能想到的有两种方式

    1. 调用系统的API,系统有提供下拉刷新的API接口

       

      下拉刷新API.png

    2. 监听scroll-view,自定义下拉刷新,还记得scroll-view里面有一个bindscrolltoupper属性吗?忘记请自行回顾上一篇 微信小程序实战篇-电商(二)当滚动到顶部/左边,会触发 scrolltoupper 事件,所以我们可以利用这个属性,来实现下拉刷新功能。

    两种方法都可以,第一种比较简单,易上手,毕竟一些逻辑系统已经给你处理好了,第二种适合那种想要自定义下拉刷新样式的小程序,我们讲解电商,就用第一种,系统提供的就好,主要是教会大家怎么用。以首页为例

    1. home.json 参数配置
    "enablePullDownRefresh": true
    

    我们哪个页面需要下拉刷新,就在哪个页面对应的xxx.json文件配置上面属性,这个属性从字面意思也可以知道,是否允许下拉刷新,当然,如何你不想一个个配置允许下拉刷新,你可以直接在全局变量app.json的window里面配置上面这个属性,这样整个项目都允许下拉刷新了,这个一定要加的,因为系统默认是不具备下拉刷新功能的

    1. home.js
    
    
      //下拉刷新
      onPullDownRefresh:function()
      {
        wx.showNavigationBarLoading() //在标题栏中显示加载
        
        //模拟加载
        setTimeout(function()
        {
          // complete
          wx.hideNavigationBarLoading() //完成停止加载
          wx.stopPullDownRefresh() //停止下拉刷新
        },1500);
      },

    ** onPullDownRefresh** 下拉刷新事件监听,具体看一下里面的代码,wx.showNavigationBarLoading() 与wx.hideNavigationBarLoading() 这两句话是用来控制小菊花的显示和隐藏,由于我们现在还没有讲解网络请求,所以我就模拟了一下网络加载,通过setTimeout方法,写一个时间延迟的方法,这个方法可以模拟网络加载所消耗的时间,还有就是当网络加载完成我们要停止下拉刷新wx.stopPullDownRefresh() 。

    这个到目前为止下拉刷新的功能已经完成了,但是还不够完美,还是有点怪怪的,就是下拉刷新没有动画,有木有~我那时也感到奇怪,微信封装的下拉刷新怎么可能这样呐,后来我参考别人写的代码,发现一个小坑,先看一下我填完坑的效果吧

     

    怎么样,是不是顺眼多了,想知道我是怎么加入这个动画的嘛,让我来给你揭晓,其实很简单,只需要一句话代码在app.json中window里配置下面属性,这个是配置整个系统的背景颜色,为什么我配置系统颜色就会出现下拉刷新了呐,原因就在下拉刷新的动画本身就有,只不过当我们没配置背景颜色,系统默认就为白色,动画也是白色,所以我们就看不到动画效果,是不是有点坑,哈哈~~

    "backgroundColor": "#f0145a"

    加载更多

    实现加载更多也同理有两种方式

    1. 调用系统的API
    2. 监听scroll-view,bindscrolltolower滑动到底部的监听

    我还是拿第一种实现方式讲解,处理方式和下拉刷新略有不同,不过也大同小异吧,还是以首页为例

    1. home.js
    
      //加载更多
      onReachBottom: function () {
        console.log('加载更多')
        setTimeout(() => {
          this.setData({
            isHideLoadMore: true,
            recommends: [
              {
                goodId: 7,
                name: 'OLAY玉兰油精油沐浴露玫瑰滋养二合一450ml',
                url: 'bill',
                imageurl: 'http://mz.djmall.xmisp.cn/files/product/20161213/148162245074.jpg',
                newprice: "¥36.60",
                oldprice: "¥40.00",
              },
              {
                goodId: 10,
                name: '兰蔻玫瑰清滢保湿柔肤水嫩肤水化妆水400ml补水保湿温和不刺激',
                url: 'bill',
                imageurl: 'http://mz.djmall.xmisp.cn/files/product/20161201/148057937593.jpg',
                newprice: "¥30.00",
                oldprice: "¥80.00",
              }, {
                goodId: 11,
                name: 'Lancome/兰蔻清莹柔肤爽肤水/粉水400ml补水保湿玫瑰水化妆水',
                url: 'bill',
                imageurl: 'http://mz.djmall.xmisp.cn/files/product/20161201/148057953326.jpg',
                newprice: "¥30.00",
                oldprice: "¥80.00",
              },
              {
                goodId: 12,
                name: '美国CLINIQUE倩碧黄油无油/特效润肤露125ml',
                url: 'bill',
                imageurl: 'http://mz.djmall.xmisp.cn/files/product/20161201/14805828016.jpg',
                newprice: "¥239.00",
                oldprice: "¥320.00",
              },
              {
                goodId: 13,
                name: '法国LANCOME兰蔻柔皙轻透隔离防晒乳霜50ML2017年3月到期',
                url: 'bill',
                imageurl: 'http://mz.djmall.xmisp.cn/files/product/20161201/148058014894.jpg',
                newprice: "¥130.00",
                oldprice: "¥180.00",
              },
            ],
          })
        }, 1000)
      }
    

    onReachBottom系统提供的触底事件的监听,和下拉刷新一样,我们也是模拟一些数据,加了一个时间延迟的事件,isHideLoadMore,一个自定义的值,用来控制显示和隐藏加载控件

    1. home.wxml
     <view class="weui-loadmore" hidden="{{isHideLoadMore}}">
        <view class="weui-loading"></view>
        <view class="weui-loadmore__tips">正在加载</view>
      </view>
    

    在home.wxml底部加入上面的代码,这是加载更多的控件,加载更多待遇就没下拉刷新待遇好,系统并没有提供加载更多的控件动画,所以我们需要自己制作

    1. home.wxss
    
    /*  加载更多   */
    .weui-loading {
      margin: 0 5px;
      width: 20px;
      height: 20px;
      display: inline-block;
      vertical-align: middle;
      -webkit-animation: weuiLoading 1s steps(12, end) infinite;
      animation: weuiLoading 1s steps(12, end) infinite;
      background: transparent url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMjAiIGhlaWdodD0iMTIwIiB2aWV3Qm94PSIwIDAgMTAwIDEwMCI+PHBhdGggZmlsbD0ibm9uZSIgZD0iTTAgMGgxMDB2MTAwSDB6Ii8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTlFOUU5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTMwKSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iIzk4OTY5NyIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgzMCAxMDUuOTggNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjOUI5OTlBIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDYwIDc1Ljk4IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0EzQTFBMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSg5MCA2NSA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNBQkE5QUEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoMTIwIDU4LjY2IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0IyQjJCMiIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgxNTAgNTQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjQkFCOEI5IiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKDE4MCA1MCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDMkMwQzEiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTE1MCA0NS45OCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNDQkNCQ0IiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTEyMCA0MS4zNCA2NSkiLz48cmVjdCB3aWR0aD0iNyIgaGVpZ2h0PSIyMCIgeD0iNDYuNSIgeT0iNDAiIGZpbGw9IiNEMkQyRDIiIHJ4PSI1IiByeT0iNSIgdHJhbnNmb3JtPSJyb3RhdGUoLTkwIDM1IDY1KSIvPjxyZWN0IHdpZHRoPSI3IiBoZWlnaHQ9IjIwIiB4PSI0Ni41IiB5PSI0MCIgZmlsbD0iI0RBREFEQSIgcng9IjUiIHJ5PSI1IiB0cmFuc2Zvcm09InJvdGF0ZSgtNjAgMjQuMDIgNjUpIi8+PHJlY3Qgd2lkdGg9IjciIGhlaWdodD0iMjAiIHg9IjQ2LjUiIHk9IjQwIiBmaWxsPSIjRTJFMkUyIiByeD0iNSIgcnk9IjUiIHRyYW5zZm9ybT0icm90YXRlKC0zMCAtNS45OCA2NSkiLz48L3N2Zz4=) no-repeat;
      background-size: 100%;
    }
    .weui-loadmore {
      width: 65%;
      margin: 1.5em auto;
      line-height: 1.6em;
      font-size: 14px;
      text-align: center;
    }
    .weui-loadmore__tips {
      display: inline-block;
      vertical-align: middle;
    }
    

    这个是我们自定义的样式,样式很简单,就是一个简单的加载小菊花,这里我要讲解的是 weui-loading 样式里设置 background,data:image/svg+xml;base64这个是什么意思呐,我们之前一般设置背景直接加入颜色,这个是background的另一种用法,加入图片,这个图片还有点特别是base64格式,并用svg绘制的,当然你还可以直接把url里面写入图片路径也是可以的,好,下面我们一起看一下效果吧!



    作者:代码君_Coder
    链接:https://www.jianshu.com/p/8c98af820fea
    來源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    展开全文
  • ‘ 循环滚动列表 ’ 和 ‘ 手动加载更多列表 ’; 一,手动加载更多列表 1,效果图: 2,逻辑 首次进入页面,列表展示数据的前20条,(根据自己项目的需要而定啊)支持鼠标滚轮滚动控制列表上下滚动。如果...
  • 原生JS 实现下拉加载更多 全局

    千次阅读 2019-05-17 10:46:06
    /获取滚动条当前的位置 function getScrollTop() { var scrollTop = 0; if(document.documentElement && document.documentElement.scrollTop) { scrollTop = document.documentElement.scrollTop; } else if...
  • 今天介绍微信小程序中scroll-view实现横向滚动和上拉加载的实现及需要注意的地方。 先看最终效果。横向滚动1.设置滚动项display:inline-block; 2.设置滚动视图容器white-space: nowrap; 3.滚动项不要用float为...
  • 微信小程序页面加载更多数据其实也不是很难,官方很好的给出了相应的组件和使用方法。只是需要在实际的开发中注意一下相关的问题点 1:需要使用到的组件和API scroll-view 基础库 1.0.0 开始支持,低版本需做...
  • 一、概述:由于小程序里面使用的都是变量控制,所以使用起来比较难掌握,今天做了一个文字从右向左滚动的实例,写法比较简单。效果如下图所示:二、实现过程:1、解决思路:一共两个text控件,当第一个text滚动完后...
  • 关于实现ListView下拉刷新和加载更多的实现,我想网上一搜就一堆。不过我就没发现比较实用的,要不就是实现起来太复杂,要不就是不健全的。因为小巫近期要开发新浪微博客户端,需要实现ListView的下拉刷新,所以就想...
  • React-实现上拉加载更多

    千次阅读 2017-12-21 18:20:55
    1. 写在前面 我最开始纠结当用户滑动时onTouchMove事件会不停的执行去调接口,于是我侥幸的想只用onTouchEnd事件去判...光判断滑到最底部是不够的,首先需要知道用户现在的操作,是点击还是滑动(向上、向下、向左、...
  • 当总页数为1页或者是最后一页时候,底部显示“没有更多数据”字样,否则显示“滑动加载更多”的字样。 一、组件的封装 1、html 2、js export default { props: { parentPullUpState: { default: 0 }, ...
  • 昨天有一需求,是希望页面加载完毕后向左自动滚动一定位置。一直以为只要给页面的 document.documentElement.scrollLeft 设置一个数值就生效,结果失望了~今天抽空一查,才发现:使用document.documentElement....
  • 从loading开始,加载更多后,“悄巴蜀”这个cell出来了,但是tableview先下滑动,在向上滑动,产生了抖动现象。 【原因】当loading的时候,contentInset.bottom是172,当loading隐藏的时候contentInset.bottom = ...
  • vue上拉加载更多

    千次阅读 2017-11-06 15:03:06
    都是滑动切换的,但是又得上拉加载,所以导致,很UI框架,我们用了,都有不同的bug出现,没办法,最后写了一个。代码如下(这个因为很地方会用,所以建议放在components/common下面): ...
  • Android UI--自定义ListView(实现下拉刷新+加载更多

    万次阅读 热门讨论 2013-10-09 16:43:26
    Android UI--自定义ListView(实现下拉刷新+加载更多) 关于实现ListView下拉刷新和加载更多的实现,我想网上一搜就一堆。不过我就没发现比较实用的,要不就是实现起来太复杂,要不就是不健全的。因为小巫近期要...
  • 2、当用户右滑(从右向左),滑动到一定距离时,加载下一张,删除第一张 3、当用户左滑(从左向右),滑动到一定距离时,加载上一张,删除最后一张 看下最后的效果图: 为了增加一定的趣味,做了一个...
  • RecycleView 添加底部加载更多

    千次阅读 2015-02-28 11:27:56
    //小于等于0 表示停止或向左滚动 isSlidingToLast = false ; } } public abstract void onLoadMore (); //要在实现类中实现 } ok了,最后贴个demo吧: @EActivity (R.layout.activity_...
  • 下拉刷新上拉加载更多的扩展ListView  在很多APP我们都能看到,在一个列表上面,将手指往屏幕下面滑动,列表上方就会出现一个隐藏的View,一般写有“下拉刷新”等字样,意味着,我们将手指往下面滑动,字样又会变成 ...
  • timg.jpg首先看效果图image.pngimage.pngimage.pngimage....因为考虑到总的页数是一个不确认的值,所以我这里用了小程序中横向滚动方式展示所有的数据3.接下来在js中声明了一个数组,专门存储总页数,通过遍历后进行...
  • 案例由于业务的需要,需求方需要实现一个大量图片同时加载的需求。在实现这个需求的过程中,可能会遇到很的坑,这里小编也总结了一些优化方案,我们可以一起来看看。具体场景在描述如何解决问题,我们现在先来申明...
  • iScroll是一个高性能,资源占用少,无依赖,平台的javascript滚动插件。 它可以在桌面,移动设备和智能电视平台上工作。它一直在大力优化性能和文件大小以便在新旧设备上提供最顺畅的体验。 iScroll不仅仅是 ...
  • 仿美团开源项目整体架构和首页其实早就完成了,前段时间家里各种事情搞得心力交瘁,停了一段时间。甚至一度动摇继续这个项目的决心,因为最近在学前端,在技术的深度和广度之间一直纠结摇摆不定。一个声音是继续...
  • 对应的主流策略之一是先在当前版块展示一部分内容,剩余内容以查看更多的方式来隐藏,以保证用户当前良好的阅读体验。 但是我们总不能所有场景直接往标题右边一放了事,而不考虑业务及交互层面的使用。接下来我结合...
  • 最近在一些博客看到侧边栏某些板块,随着滚动条的滑动,而跟着滑动或者固定的效果,感觉非常的人性化,一来可以弥补当一个页面很长,但侧边栏太短的时候的空白,二来可以合理利用空间展示更多信息,可以大大的提高...
  • 功能完善 我们为 PowerScrollView 完善了业务使用的核心诉求,包括自动曝光、滚动到某个 index 、瀑布流、刷新加载更多等能力。下面将重点介绍前两部分。 自动曝光能力 在 Flutter 中,通常不得不将曝光放在 build ...
  • 在视差滚动网页的设计上,无论是移动端还是桌面端,如今的设计师都有了足够深入的探索,并且对于功能和体验上的挖掘,都有了比较成熟的经验。无论是导航悬停式的滚动还是水平滚动和分屏3D特效,视差滚动这一设计趋势...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 26,312
精华内容 10,524
关键字:

向左滚动加载更多