• 再战sortablejs


    本来,Sortablejs + css 模仿安卓桌面 是用来制作浏览器主页导航的,但是本人发现不大适合,有性能和操作性的原因,以及难以支持多级目录。反而原生的recyclerview列表控件更适合此任务,所以旁落,没有用上。

    而这次打算制作一个新的浏览器扩展,正好再次捡起,用于显示标签页网格、网址收藏网格等,不过发现可以再优化一二。

    sortable.js一共一百多kb。它使用插件式设计,内置插件有

    • AutoScroll - 拖动时自动滚动
    • MultiDrag 多选拖拽
    • OnSpill 拖拽到网格外部时,若开启revertOnSpill则撤销更改(对多选不完全有效),若开启removeOnSpill则删除元素。
    • Swap 修改拖拽排序为拖拽交换。

    优化MultiDrag

    默认的MultiDrag在点击空白区域时会清空选择。最新版本有人提出加入avoidImplicitDeselect选项,阻止隐式清除选择。

    我没有找到它的demo,但本人魔改的版本中有一个bug,那就是多选,然后微微拖拽一下选中内容(但是不触发onMove事件),再然后拖动未选中元素,就会导致选中元素消失。

    多选假移紊乱:

    fix:需要修改MultiDrag插件的dragStarted事件处理,当拖动的是未选中内容时,需适时重置一些变量,而不是直接返回 ——

    if(!isMultiDrag)
        folding = initialFolding = 0;
    
    • 1
    • 2

    优化 OnSpill

    spill本意溢出; 泼出sortablejs对此的判定很奇怪:

        hideGhostForTarget();
        var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;
        var target = document.elementFromPoint(touch.clientX, touch.clientY);
        unhideGhostForTarget();
    
        if (toSortable && !toSortable.el.contains(target)) {
          dispatchSortableEvent('spill');
          this.onSpill({
            dragEl: dragEl,
            putSortable: putSortable
          });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这是用el.contains判断的。先获取鼠标位置,然后用document.elementFromPoint获取鼠标指针下的元素,最后判断元素是否在网格容器中。

    更好的做法是判断鼠标是否在包围盒内,以及窗口是否有焦点(document.hasFocus())。不过包围盒只有el.getBoundingClientRect(),如果容器因为滚动等原因被遮挡,那判断的也不是很准确(见so讨论)。

    如果是文件夹则更难处理,因为那是两个可拖拽网格上下层叠,onspill判定更为复杂。本人索性在元素拖拽出文件夹时,动态关闭revertOnSpill

    拖拽到外部只要用于打开新的标签页。sortablejs可设置setData回调,为dataTransfer设置内容:

    , multiDrag: true
    , setData : function (dataTransfer, dragEl) {
    		dataTransfer.setData('text', dragEl.data.url);
    	}
    ……
    
    • 1
    • 2
    • 3
    • 4
    • 5

    优化动画性能

    当元素总数很多时,动画性能较低。

    Very slow and laggy in google chrome with many itemsSlow in Chrome when many elements in the page

    可以删除position:relative样式,但无法完全解决问题。可以动态关闭动画,为此本人引入两个变量multiAnimaTheta=300window.disani=false

    修改 MutiDrag::dragStarted

    if (rootEl.childElementCount<multiAnimaTheta 
            && _this2.options.animation) {
        …… css(multiDragElement, 'position', 'absolute');
        folding = 1; // 只在元素总数较少时开启神奇的动画聚拢效果
        initialFolding = 1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    修改_onMove

    if(!w.disani && fromEl!=toEl) { // 跨列表移动元素,同样要适时关闭动画
        w.disani = fromEl.childElementCount>multiAnimaTheta||toEl.childElementCount>multiAnimaTheta;
    }
    …… 
    (!w.disani && options.animation) 代替 options.animation
    
    • 1
    • 2
    • 3
    • 4
    • 5

    “微微鼓胀的圆角矩形”

    学名叫做"Squircle",我用的词典未收录。一开始记得这词类似于square,久之忘词了,wantwords也搜不出,最后还是谷歌查一下图片就出来了……
    请添加图片描述

    A squircle is a shape intermediate between a square and a circle

    原来是方/圆的结合体。

    用svg实现。

    外网这种设计网站很多,春秋时代啊:Squircley | SVG Squircle Maker
    请添加图片描述

    懒加载

    蚊子再小也是肉,反过来说也是vice versa。虽然sortablejs体积很小,但能省点流量就省点流量,虽也不缺,全当是为绿色环保做贡献吧。

    sortablejs可以实现懒加载:默认不加载,而是自己写el.draggble=true,处理ondragstart事件。

    在ondragstart中加载并初始化Sortable,然后手动调用Sortable对象的_onTapStart_onDragStart,成功交接拖拽逻辑:

    var tabS;
    function lazyDrag(e) {
    	debug('ondragstart', e);
    	bg.loadSortable(function() {  // 加载 sortable.js
    		debug('loadSortable', w.Sortable); // 确认加载成功
    		tabS=new Sortable(tabH, { // 初始化 Sortable 对象
    			multiDrag: true,
    			swapThreshold: 0.34,
    			revertOnSpill:true,
    			invertSwap: true,
    			selectedClass: 'selected', 
    			animation: 300,
    			ghostClass: 'blue-background-class',
    			group:"tabH",
    			root:true,
    			forceFallback: false,
    			sort:true,
    			……
    		});
    		// 交接拖拽逻辑!
    		tabS._onTapStart(e); 
    		tabS._onDragStart(e);
    	});
    }
    
    function initTabs() {
    	for(var i=0;i<tabs.length;i++) {
    		var t=createTab(i);
    		t.draggable = true; // 模拟拖拽
    		t.ondragstart = lazyDrag;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    此法简直浑然天成、天衣无缝。此处胜景,仿佛天生就在等待我的光临。

    固定项目

    Sortablejs 本身支持固定/不能拖拽排序的项目,在options.onMove中返回false即可,建议用 el.fixed 判断元素是否固定:

    	multiDrag: true,
    	onMove(evt) {
    		// 需要判断被拖拽元素与拖拽目标元素两个方面
    		if(evt.dragged.fixed||evt.related.fixed) 
    			return false;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    无法解决的问题

    1. 拖拽时无法滚动列表。
      由于系统特性,标准拖拽的过程中无按键、鼠标事件的传递。
      Drag + wheel scroll feature · Issue #935 · SortableJS/Sortable
      可以开启forceFallback模式,缺点是非标准拖拽,内容无法拖拽到其他窗口。

    2. 不支持多级目录

  • 相关阅读:
    C到C++的过渡
    python_requests笔记
    uploadifive上传工具php版使用
    #Paper Reading# Pre-trained Language Model based Ranking in Baidu Search
    C/C++类型转换
    SpringBoot实践(四十三):整理面试常问的问题
    Azure Integrator Delphi版
    macOS:苹果公司创造的传奇
    构建响应式网站的HTML5和CSS3最新技术
    selenium模拟登录无反应
  • 原文地址:https://blog.csdn.net/sinat_27171121/article/details/127667148