`
xhload3d
  • 浏览: 208282 次
社区版块
存档分类
最新评论

基于HTML5树组件延迟加载技术实现

阅读更多

HT for WebHTML5树组件有延迟加载的功能,这个功能对于那些需要从服务器读取具有层级依赖关系数据时非常有用,需要获取数据的时候再向服务器发起请求,这样可减轻服务器压力,同时也减少了浏览器的等待时间,让页面的加载更加流畅,增强用户体验。

http://www.hightopo.com/guide/readme.html

进入正题,今天用来做演示的Demo是,客户端请求服务器读取系统文件目录结构,通过HT for WebHTML5树组件显示系统文件目录结构。

首先,我们先来设计下服务器,这次Demo的服务器采用Node.js,用到了Node.js的expresssocket.io、fs和http这四个模块,Node.js的相关知识,我在这里就不阐述了,网上的教材一堆,这里推荐下socket.io的相关入门http://socket.io/get-started/chat/

服务端代码代码:

var fs = require('fs'),
    express = require('express'),
    app = express(),
    server = require('http').createServer(app),
    io = require('socket.io')(server),
    root = ‘/Users/admin/Projects/ht-for-web/guide‘;

io.on('connection', function(socket){
    socket.on('explore', function(url){
        socket.emit('file', walk(url || root));
    });
});

app.use(express.static('/Users/admin/Projects/ht-for-web'));

server.listen(5000, function(){
    console.log('server is listening at port 5000');
});

io监听了connection事件,并获得一个socket;socket再监听一个叫explore的自定义事件,通过url参数获取到数据后,派发一个叫file的自定义事件,供客户端监听并做相应处理;通过app.use结合express.static设置项目路径;最后让server监听5000端口。

到此,一个简单的服务器就搭建好了,现在可以通过http://localhost:5000来访问服务器了。等等,好像缺了点什么。对了,获取系统文件目录结构的方法忘记给了,OK,那么我们就先来看看获取整站文件的代码是怎么写的:

function walk(pa) {
    var dirList = fs.readdirSync(pa),
        key = pa.substring(pa.lastIndexOf('/') + 1),
        obj = {
            name: key,
            path: pa,
            children: [],
            files: []
        };
    dirList.forEach(function(item) {
        var stats = fs.statSync(pa + '/' + item);
        if (stats.isDirectory()) {
            obj.children.push(walk(pa + '/' + item));
        }
        else {
            obj.files.push({name: item, dir: pa + '/' + item});
        }
    });

    return obj;
}

如大家所见,采用递归的方式,逐层遍历子目录,代码也没什么高深的地方,相信大家都看得懂。那我们来看看运行效果吧:

 

duang~文件目录结构出来了,是不是感觉酷酷的,这代码量不小吧。其实,代码并不多,贴出来大家瞅瞅:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>tree-loader</title>
    <script src="/socket.io/socket.io.js"></script>
    <script src="/lib/core/ht.js"></script>
    <script>
        var socket = io(), idMap = {};
        function init() {
            var dm = window.dm = new ht.DataModel(),
                    tree = new ht.widget.TreeView(dm);
            
            tree.addToDOM();

            socket.on('file', function(data) {
                var root = dm.getDataById(idMap[data.path]);
                createChildren(data.children || [], root, dm);
                createFiles(data.files || [], root, dm);
            });
            socket.emit('explore');
        }

        function createChildren(children, parent, dm) {
            children.forEach(function(child) {
                var n = createData(child, parent);
                dm.add(n);
                createChildren(child.children || [], n, dm);
                createFiles(child.files || [], n, dm);
            });
        }

        function createFiles(files, parent, dm){
            files.forEach(function(file){
                var n = createData(file, parent);
                dm.add(n);
            });
        }

        function createData(data, parent){
            var n = new ht.Data();
            n.setName(data.name);
            n.setParent(parent);
            n.a('path', data.path);
            idMap[data.path] = n.getId();
            return n;
        }
    </script>
</head>
<body onload="init();">
</body>
</html>

这就是全部的HTML代码,加上空行总共也就50几行,怎么样,有没有感觉HT for Web很强大。废话不多说,来看看这些代码都干了些什么:

  • 要用到socket.io就需要在页面引入<script src=“/socket.io/socket.io.js”></script>,其实在我的项目中并不存在/socket.io/socket.io.js文件,但是却能正常使用,具体什么原因,我就不多说,大家自己研究去吧;
  • 最重要的是要引入HT for Web的核心包<script src=“/lib/core/ht.js”></script>,这个包不引入的话,下面的HT for Web组件就无法使用;
  • 接下来就是代码了,首先创建一个数据容器DataModel,用来存放文件目录的节点数据,再创建一个TreeView对象并引用刚创建到数据容器,接下来通过socket监听file事件,获取服务器返回的数据,在回调函数中通过调用createChildren和createFiles函数,创建文件目录节点对象,并添加到数据容器中,最后是向服务器发起数据请求,即通过socket派发explore事件。

整体的思路是这样子的,当然这离我们要实现的树组件的延迟加载技术还有些差距,那么,HT for WebHTML5树组件的延迟加载技术是怎么实现的呢?不要着急,马上开始探讨。

首先我们需要改造下获取文件目录的方法walk,因为前面介绍的方法中,使用的是加载整站文件目录,所以我们要将walk方法改造成只获取一级目录结构,改造起来很简单,就是将递归部分改造成获取当前节点就可以了,具体代码如下:

obj.children.push(walk(pa + '/' + item));
// 将上面对代码改成下面的代码
obj.children.push({name: item, path: pa + '/' + item});

这样子服务器就只请求当前请求路径下的第一级文件目录结构。接下来就是要调整下客户端代码了,首先需要给tree设置上loader:

tree.setLoader({
    load: function(data) {
        socket.emit('explore', data.a('path'));
        data.a('loaded', true);
    },
    isLoaded: function(data) {
        return data.a('loaded');
    }
});

loader包含了两个方法,load和isLoaded,这两个方法的功能分别是加载数据和判断数据是否已经加载,在load方法中,对socket派发explore事件,当前节点的path为参数,向服务器请求数据,之后将当前节点的loaded属性设置为true;在isLoaded方法中,返回当前节点的loaded属性,如果返回为true,那么tree将不会在执行load方法向服务器请求数据。

接下来需要移除createChildren的两个回调方法,并且在createFiles方法中为创建出来的节点的loaded属性设置成true,这样在不是目录的节点前就不会有展开的图标。createChildren和createFiles两个方法修改后的代码如下:

function createChildren(children, parent, dm) {
    children.forEach(function(child) {
        var n = createData(child, parent);
        dm.add(n);
    });
}

function createFiles(files, parent, dm){
    files.forEach(function(file){
        var n = createData(file, parent);
        n.a('loaded', true);
        dm.add(n);
    });
}

如此,HT for Web的HTML5树组件延迟加载技术就设计完成了,我在服务器的控制台打印出请求路径,看看这个延迟加载是不是真的,如下图:

 

看吧,控制台打印的是4条记录,第一条是请求跟目录时打印的,我在浏览器中展开里三个目录,在控制台打印了其对应的目录路径。

等等,现在这个目录看起来好烦,只有文字,除了位子前的展开图标可以用来区别文件和目录外,没有其他什么区别,所以我决定对其进行一番改造,让每一级目录都有图标,而且不同文件对应不同的图标,来看看效果吧:

 

怎么样,是不是一眼就能看出是什么文件,这个都是样式上面的问题,我就不再一一阐述了,直接上代码:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <script src="/socket.io/socket.io.js"></script>
    <script src="/build/ht-debug.js"></script>
    <script>
        var socket = io(), idMap = {};
        function init() {
            var icons = ['css', 'dir-open', 'dir', 'file', 'flash', 'gif', 'html', 'jar',
                'java', 'mp3', 'pdf', 'png', 'script', 'txt', 'video', 'xml', 'zip'];
            icons.forEach(function(c){
                ht.Default.setImage(c, 16, 16, '/test/wyl/images/' + c + '.png');
            });

            var dm = window.dm = new ht.DataModel(),
                    tree = new ht.widget.TreeView(dm);
            tree.setLoader({
                load: function(data) {
                    socket.emit('explore', data.a('path'));
                    data.a('loaded', true);
                },
                isLoaded: function(data) {
                    return data.a('loaded');
                }
            });
            tree.getLabelFont = function(data){
                return '13px Helvetica, Arial, sans-serif';
            };
            tree.getLabelColor = function (data) {
                return this.isSelected(data) ? 'white' : 'black';
            };
            tree.getSelectBackground = function (data) {
                return '#408EDB';
            };
            tree.getIcon = function (data) {
                var icon = data.getIcon() || 'file';
                if (data.a('isdir')) {
                    if (this.isExpanded(data)) {
                        icon = 'dir-open';
                    } else {
                        icon = 'dir';
                    }
                }
                return icon;
            };
            tree.addToDOM();

            socket.on('file', function(data) {
                var root = dm.getDataById(idMap[data.path]);
                createChildren(data.children || [], root, dm);
                createFiles(data.files || [], root, dm);
            });
            socket.emit('explore');
        }

        function createChildren(children, parent, dm) {
            children.forEach(function(child) {
                var n = createData(child, parent);
                n.a('isdir', true);
                dm.add(n);
            });
        }

        function createFiles(files, parent, dm){
            files.forEach(function(file){
                var n = createData(file, parent);
                n.a('loaded', true);
                dm.add(n);
            });
        }

        function createData(data, parent){
            var name = data.name,
                    icon = 'file';
            if (/.jar$/.test(name)) icon = 'jar';
            else if (/.css$/.test(name)) icon = 'css';
            else if (/.gif$/.test(name)) icon = 'gif';
            else if (/.png$/.test(name)) icon = 'png';
            else if (/.js$/.test(name)) icon = 'script';
            else if (/.html$/.test(name)) icon = 'html';
            else if (/.zip$/.test(name)) icon = 'zip';
            var n = new ht.Data();
            n.setName(data.name);
            n.setParent(parent);
            n.setIcon(icon);
            n.a('path', data.path);
            idMap[data.path] = n.getId();
            return n;
        }
    </script>
</head>
<body onload="init();">
</body>
</html>

在最后,附上完整的服务器代码:

var fs = require('fs'),
    express = require('express'),
    app = express(),
    server = require('http').createServer(app),
    io = require('socket.io')(server),
    root = '/Users/admin/Projects/ht-for-web/guide';

io.on('connection', function(socket){
    socket.on('explore', function(url){
        socket.emit('file', walk(url || root));
    });
});

app.use(express.static('/Users/admin/Projects/ht-for-web'));

server.listen(5000, function(){
    console.log('server is listening at port 5000');
});

function walk(pa) {
    var dirList = fs.readdirSync(pa),
        key = pa.substring(pa.lastIndexOf('/') + 1),
        obj = {
            name: key,
            path: pa,
            children: [],
            files: []
        };
    dirList.forEach(function(item) {
        var stats = fs.statSync(pa + '/' + item);
        if (stats.isDirectory()) {
            obj.children.push({name: item, path: pa + '/' + item});
        }
        else {
            obj.files.push({name: item, dir: pa + '/' + item});
        }
    });

    return obj;
}

 http://www.hightopo.com/guide/readme.html

3
4
分享到:
评论

相关推荐

    基于html5 webaudio api 实现的播放器.zip

    这个"基于html5 webaudio api 实现的播放器.zip"压缩包内容可能包含了一个使用WebAudio API构建的音乐播放器项目的源代码。下面将详细介绍HTML5 WebAudio API及其在多媒体开发中的应用。 一、HTML5 WebAudio API ...

    dtree含复选框延迟加载.rar

    这个场景下,"dtree含复选框延迟加载.rar" 提供的资源可能是一个基于JavaWeb的解决方案,用于创建具有复选框的树形控件,并且支持延迟加载。在这个系统中,用户可以查看和选择树中的节点,同时只有在需要时才会加载...

    cui组件 jquery组件库

    为了提高性能,CUI组件库采用延迟加载和模块化设计,只在需要时初始化组件,减少不必要的资源消耗。 6. **文档与社区支持**: 完善的文档和活跃的社区支持是CUI组件库的一大亮点,开发者可以轻松获取教程、示例和...

    仿抖音短视频小程序APP组件(超高性能)自动预加载

    【标题】"仿抖音短视频小程序APP组件(超高性能)自动预加载" 描述了一款专为小程序设计的组件,该组件借鉴了抖音的界面风格和功能特性,具有高性能和自动预加载的特点。开发者使用uniapp框架来构建这个组件,旨在...

    JSTree(js写的树形菜单,支持加载10000节点以上)

    JSTree作为一个强大且灵活的JavaScript树形菜单组件,为开发者提供了解决大数据量加载问题的有效工具。其高效、易用和可扩展的特性,使其在各种Web应用中广泛应用,无论是企业级后台管理界面,还是用户友好的前端...

    基于 MUI 框架实现的 HTML5+ 兼容.zip

    MUI框架则是基于HTML5+进行构建的一个开源前端框架,其目标是为开发者提供一套轻量级、高效、易用的移动开发解决方案。本项目"基于 MUI 框架实现的 HTML5+ 兼容"着重讨论如何利用MUI框架来充分利用HTML5+的功能,以...

    手机端h5页面适配+预加载+获取资源加载进度模板

    在移动设备上,H5(HTML5)页面的适配、预加载以及资源加载进度的显示对于提升用户体验至关重要。下面将详细阐述这些知识点,并提供一些实际应用的策略。 1. **H5页面适配**: - **百分比布局**:在H5页面设计时,...

    基于vue2的图片懒加载项目后台代理百度图片api接口实现滚动懒加载当前视图区域加载

    这个库是专门为Vue2设计的,用于实现图片的延迟加载。它监听滚动事件,当图片进入视口时,才会去加载对应的图片资源,这样可以显著提升页面的加载速度。"vue-lazyload"支持多种占位符,如模糊图、骨架屏等,提供更好...

    基于HTML5的ARPG前端.zip

    本文将深入探讨基于HTML5的ARPG前端开发,揭示其背后的原理与技术栈。 首先,HTML5引入的新特性如Canvas和WebGL,为动态图形渲染提供了强大支持。Canvas作为2D图形绘制API,允许开发者通过JavaScript动态绘制游戏...

    基于HTML5的报表插件

    在“基于HTML5的报表插件”中,我们主要探讨的是如何利用这些技术来创建交互式、响应式的报表,提升用户体验。 iChartjs是这个主题中的核心组件,它是一个专门针对HTML5设计的数据图表库。iChartjs提供了多种图表...

    微信小程序实现图片预加载组件

    在微信小程序中,为了提升用户体验,图片预加载技术显得尤为重要,特别是对于图片密集型的应用,如画廊或图像展示类的页面。预加载确保图片在用户实际需要之前就已经加载完毕,使得用户在浏览时能够迅速看到完整的...

    基于Vue的web端超长数据表格动态加载

    综上所述,基于Vue.js的web端超长数据表格动态加载是一个综合运用虚拟DOM、分页、滚动监听、懒加载、组件化设计和服务端渲染等多种技术的工程实践。通过这些技术,我们可以构建出高效、流畅的大型数据表格应用,改善...

    基于Mootools库的Web分页技术实现.doc

    【基于Mootools库的Web分页技术实现】 在Web应用程序中,随着数据量的增长,分页技术成为了必要的功能,以提升用户体验并减轻服务器压力。Mootools是一个强大的JavaScript库,它提供了模块化、面向对象的框架,适用...

    js和html5实现网络拓扑图

    总的来说,使用JavaScript和HTML5实现网络拓扑图的自动排列展示,不仅需要理解HTML5的图形绘制机制,还需要掌握Qunee库的用法,以及网络拓扑图的布局策略。这是一项涉及前端开发、数据处理和用户交互设计的综合任务...

    基于HTML5+Nodejs+百度人脸识别音乐播放器的设计与实现.docx

    该文档讲述了如何设计和实现一个基于HTML5、Node.js和百度人脸识别技术的音乐播放器。这个创新项目结合了人工智能和音乐娱乐,通过识别人脸情绪来推送相应的音乐,或者根据情绪改变界面,以提供个性化的音乐体验。...

    dataLazyload延迟加载

    在实际应用中,dataLazyload技术可以与其他前端技术结合,如结合Vue、React等前端框架,实现更复杂的组件级别的延迟加载。此外,还可以配合使用服务端的分页或流式加载策略,进一步优化用户体验。 总之,...

    Jquery EasyUI 异步树,适合大数据量无限级加载

    异步树则通过按需加载(或称为懒加载)技术解决了这个问题,只在用户展开特定节点时才请求并加载其子节点,从而提高了性能和用户体验。 jQuery EasyUI 提供的 `tree` 组件支持异步加载,这对于处理大数据量的无限级...

    extjs tree 异步加载树型

    ExtJS Tree 是一个基于 ExtJS 框架的组件,用于构建可交互的、层级结构的树形控件。在 Web 开发中,它经常被用来展示目录结构、组织架构或者复杂的分类数据。异步加载树型是 ExtJS Tree 的一个重要特性,允许只在...

    基于vue3的方形抽奖组件

    在本项目中,我们关注的是一个基于...总的来说,这个基于Vue3的方形抽奖组件项目利用了Vue3的新特性和最佳实践,提供了一个高效且易于维护的抽奖功能实现,同时结合现代前端工具链,确保了开发效率和项目的可扩展性。

Global site tag (gtag.js) - Google Analytics