Layui源码解读之use函数(模块加载)

news2024/10/6 14:40:16

一、layui.use 用法

layui.use() 函数用于模块加载

layui.use([mods], callback)

  1. mods:如果填写(选填),必须是一个 layui 合法的模块名(不能包含目录)。
    从 layui 2.6 开始,若 mods 不填,只传一个 callback 参数,则表示引用所有内置模块。

  2. callback:即为模块加载完毕的回调函数。
    从 layui 2.6 开始,该回调会在 html 文档加载完毕后再执行,确保你的代码在任何地方都能对元素进行操作。

例子: 加载指定模块

layui.use(['layer', 'laydate'], function(){
  var layer = layui.layer
  ,laydate = layui.laydate;

  //do something
});

例子: 引用所有模块(layui 2.6 开始支持)

layui.use(function(){
  var layer = layui.layer
  ,laydate = layui.laydate
  ,table = layui.table;

  //do something
});

二、layui.use 源码

// 使用特定模块
Layui.prototype.use = function(apps, callback, exports, from) {
    var that = this;
    var dir = config.dir = config.dir ? config.dir : getPath; // 获取路径
    var head = doc.getElementsByTagName('head')[0]; // 获取第一个header

    // 对传入的 apps 参数进行处理
    apps = function(){

        // 传入字符串时, 应转为数组 layui.use('form',...)
        if(typeof apps === 'string'){
            return [apps];
        }

        // 第一个参数为 function 时, 则自动加载所有内置模块,且执行的回调即为该 function 参数
        else if (typeof apps === 'function') {
            callback = apps;
            return ['app'];
        }
        return apps;
    }(); // 立即执行

    // 如果页面已经存在 jQuery 1.7+ 库且所定义的模块依赖 jQuery,则不加载内部 jquery 模块
    if(win.jQuery && jQuery.fn.on) {
        that.each(apps, function(index, item){

            // 找到内部 jquery, 并删除
            if(item === 'jquery'){
                apps.splice(index, 1);
            }
        });
        layui.jquery = layui.$ = jQuery; // layui 为实例对象
    }

    var item = apps[0]; // 获取 apps 数组第一位元素
    var timeout = 0; // 初始化超时时间为 0
    exports = exports || [];

    // 获取静态资源host
    config.host = config.host || (dir.match(/\/\/([\s\S]+?)\//)||['//'+ location.host +'/'])[0]

    // 加载完毕
    function onScriptLoad(e, url){
        var readyRegExp = navigator.platform === 'PLaySTATION 3' ? /^complete$/ : /^(complete|loaded)$/; // 根据平台选择正则表达式

        // 当前文件已经加载完毕
        if(e.type === 'load' || (readyRegExp.test(e.currentTarget || e.srcElement).readyState)){
            config.modules[item] = url; // 存储模块真实路径
            head.removeChild(node); // 从 head 中移除 node
            (function poll(){

                // 判断 timeout > 2500 ?
                if(++timeout > config.timeout * 1000 / 4) {

                    // 超时报错
                    return error(item + ' is not a valid module', 'error'); // 记得 return, 停止执行
                }

                // 判断当前模块状态是否为 true ,为 true 执行 onCallback, 否则轮询
                config.status[item] ? onCallback() : setTimeout(poll, 4);
            })()
        }
    }

    // 回调函数
    function onCallback(){

        // 向 exports 中推入模块
        exports.push(layui[item]); // layui 为实例对象中除了 v 属性标识版本号, 其余全为模块

        apps.length > 1
        ? that.use(apps.slice(1), callback, exports, from)
        : ( typeof callback === 'function' && function(){

            // 保证文档加载完毕再执行调用
            if(layui.jquery && typeof layui.jquery === 'function' && from !== 'define' ) {
                return layui.jquery(function (){
                    callback.apply(layui, exports);
                });
            }
            callback.apply(layui, exports);
        }());
    }

    // 如果引入了聚合板,内置的模块则不必重复加载
    if(apps.length === 0 || (layui['layui.all'] && modules[item])){
        return onCallback(), that;
    }

    // 获取加载的模块 URL
    // 如果是内置模块, 则按照 dir 参数拼接模块路径
    // 如果是扩展模块, 则判断模块路径值是否以 {/} 开头,
    // 如果路径值是 {/} 开头, 则模块路径即为后面紧跟的字符。
    // 否则, 则按照 base 参数拼接模块路径
    var url = (modules[item] ? (dir + 'modules/')
        : (/^\{\/\}/.test(that.modules[item]) ? '' : (config.base || ''))
    ) + (that.modules[item] || item) + '.js';

    url = url.replace(/^\{\/\}/, '');

    // 如果扩展模块(即:非内置模块)对象已经存在,则不必再加载
    if(!config.modules[item] && layui[item]){
        config.modules[item] = url; // 并记录起该扩展模块的 url
    }

    // 首次加载模块
    if(!config.modules[item]){
        var node = doc.createElement('script'); // 创建script

        node.async = true; // 异步
        node.charset = 'utf-8'; // 文件格式

        // 请求的文件后面添加版本号
        node.src = url + function(){

            // 是否存在版本
            var version = config.version === true
            ? (config.v || (new Date()).getTime())
            : (config.version || '');

            return version ? ('?v=' + version) : '';
        }();

        head.appendChild(node); // 挂载节点

        // 对 IE 添加监听
        if(node.attachEvent && !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && !isOpera){
            node.attachEvent('onreadystatechange', function(e){
                onScriptLoad(e, url);
            });
        } else {
            node.addEventListener('load', function(e){
                onScriptLoad(e, url);
            }, false)
        }

        config.modules[item] = url;
    } else { // 非首次加载
        (function poll(){
            if(++timeout > config.timeout * 1000 / 4) {
                return error(item + ' is not a valid module', 'error');
            };

            // 已加载到模块中
            (typeof config.modules[item] === 'string' && config.status[item])
            ? onCallback()
            : setTimeout(poll, 4);
        }()); // 轮询 必须是立即执行函数
    }

    return that;
}

三、layui.use 关键代码分析

var dir = config.dir = config.dir ? config.dir : getPath; // 获取路径

获取 layui 所在的目录,用于以后加载相关资源。获取完路径之后存储到 config 全局变量和局部变量 dir 中。

layui 是如何知道它的路径的呐?这里就要说一下 layui 获取路径函数 getPath(立即执行函数)

var getPath = function () {

    // 当前doc中如果有 currentScript 属性, 就返回 src
    // currentScript 更多内容查看 https://developer.mozilla.org/zh-CN/docs/Web/API/Document/currentScript
    var jsPath =  doc.currentScript
    ? doc.currentScript.src
    : function() {
        var js = doc.scripts; // 获取当前页面所有 script 标签
        var last = js.length - 1;
        var src;

        // 倒叙遍历(有利于性能)
        for(var i = last; i > 0 ;i--){

            // 当前 script 处于可交互状态时,赋值 src
            // 更多 readyState 内容查看 https://developer.mozilla.org/zh-CN/docs/Web/API/Document/readyState
            if(js[i].readyState === 'interactive'){
                src = js[i].src;
                break;
            }
        }
        return src || js[last].src; // 默认返回 src, 如果 src 不存在, 则返回数组中最后一个 script 的 src 值
    }();

    // jsPath 是形如'http://127.0.0.1:5500/src/layui.cpy.js'这样的值, 不符合需要,所以进行处理
    return config.dir = GLOBAL.dir || jsPath.substring(0, jsPath.lastIndexOf('/') + 1); 
}(); // 立即执行函数

getPath 是一个立即执行函数。首先会判断当前环境支不支持 doc.currentScript 如果支持 doc.currentScript,直接从 doc.currentScript.src 获取当前脚本运行的地址。如果不支持 doc.currentScript,则遍历文档所有的<script>标签,判断哪个<script>标签的readyState为’interactive’,则说明此标签的src属性为当前脚本运行的地址。

这里需要了解的有

  1. doc.currentScript 属性返回当前正在运行的脚本所属的 <script> 元素

    例如

    html文件

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
    <script src="./getPath.js"></script>
    </body>
    </html>
    

    getPath.js文件

    console.log(document.currentScript);
    

    请添加图片描述

     可以看出返回的是script标签元素,当前环境支持时,可以通过document.currentScript.src获取当前运行脚本所属的src属性值。如下图
    

    请添加图片描述

  2. 遍历 script 标签时,readyState 属性。

    Document.readyState 属性描述了document 的加载状态。

    当该属性值发生变化时,会在 document 对象上触发 readystatechange 事件。

    readyState 属性取一下值

    • loading(document正在加载)
    • interactive(可交互。文档已被解析,"正在加载"状态结束,但是诸如图像,样式表和框架之类的子资源仍在加载。)
    • complete(完成。文档和所有子资源已完成加载。表示 load 状态的事件即将被触发。)

var head = doc.getElementsByTagName(‘head’)[0];

获取 html 中 head dom 元素,用于后面向 head 中挂载元素使用。

例如

head.appendChild(node); // 挂载节点

apps 立即执行函数

// 对传入的 apps 参数进行处理
apps = function(){

    // 传入字符串时, 应转为数组 layui.use('form',...)
    if(typeof apps === 'string'){
        return [apps];
    }

    // 第一个参数为 function 时, 则自动加载所有内置模块,且执行的回调即为该 function 参数
    else if (typeof apps === 'function') {
        callback = apps;
        return ['app'];
    }
    return apps;
}(); // 立即执行

立即执行函数中做的事情是,把 string 和 function 类型的参数转为字符串数组形式并返回给 apps ,数组中是layui要加载的模块。需要注意的是当 apps 为函数类型时,layui 会引用所有内置模块并且 apps 函数直接赋值给 callback 用于以后逻辑处理。

jquery 处理逻辑

if(win.jQuery && jQuery.fn.on) {
    that.each(apps, function(index, item){

        // 找到内部 jquery, 并删除
        if(item === 'jquery'){
            apps.splice(index, 1);
        }
    });
    layui.jquery = layui.$ = jQuery; // layui 为实例对象
}

会先判断当前环境中是否已经引入 jquery,如果引入就遍历要加载的模块(apps),找到要加载的模块名为 jquery 的,然后删除。如果已经删除或者没找到 jquery (说明没有引入 jquery 模块)就直接把当前环境中存在的 jquery 赋值给 layui

config.host = config.host || (dir.match(///([\s\S]+?)//)||[‘//’+ location.host +‘/’])[0]

获取 host,这里的 host 和 url 中通过 host取得的值不一样。这里前面加了’//‘后面加了’/'。
所以最终的形式如下

// //127.0.0.1:5500/ 或者 //域名:4097/

聚合板 这个功能不是很常用到,这里直接上代码,不多解释(代码也比较简单)

var modules = config.builtin = {
    lay: 'lay', // 基础 DOM 操作
    layer: 'layer', // 弹层
    laydate: 'laydate', // 日期
    laypage: 'laypage', // 分页
    laytpl: 'laytpl', // 模板引擎
    layedit: 'layedit', // 富文本编辑器
    form: 'form', // 表单集
    upload: 'upload', // 上传
    dropdown: 'dropdown', // 下拉菜单
    transfer: 'transfer', // 穿梭框
    tree: 'tree', // 树结构
    table: 'table', // 表格
    element: 'element', // 常用元素操作
    rate: 'rate', // 评分组件
    colorpicker: 'colorpicker', // 颜色选择器
    silder: 'slider', // 滑块
    carousel: 'carousel', // 轮播
    flow: 'flow', // 流加载
    util: 'util', // 工具块
    code: 'code', // 代码修饰器
    jquery: 'jquery', // DOM 库
    all: 'all',
    'layui.all': 'layui.all' // 聚合标识
}

var item = apps[0]; // 获取 apps 数组第一位元素

if(apps.length === 0 || (layui['layui.all'] && modules[item])){
    return onCallback(), that; // onCallback 函数后续会详细说明
}

拼接 url

var url = (modules[item] ? (dir + 'modules/')
        : (/^\{\/\}/.test(that.modules[item]) ? '' : (config.base || ''))
    ) + (that.modules[item] || item) + '.js';

    url = url.replace(/^\{\/\}/, '');

获取加载的模块 URL。如果是内置模块, 则按照 dir 参数拼接模块路径, 否则如果是扩展模块, 则判断模块路径值是否以 {/} 开头, 如果路径值是 {/} 开头, 则模块路径即为后面紧跟的字符。否则, 则按照 base 参数拼接模块路径。

这里举例拓展模块的写法,这样就知道为何需要写’/^{/}/.test(that.modules[item]'这样的正则表达式。最后拼接完 url 后,把 {/} 去除,就得到了后续发送请求的 url。

//config的设置是全局的
layui.config({
  base: '/res/js/' //假设这是你存放拓展模块的根目录
}).extend({ //设定模块别名
  mymod: 'mymod' //如果 mymod.js 是在根目录,也可以不用设定别名
  ,mod1: 'admin/mod1' //相对于上述 base 目录的子目录
});

//你也可以忽略 base 设定的根目录,直接在 extend 指定路径(主要:该功能为 layui 2.2.0 新增)
layui.extend({
  mod2: '{/}http://cdn.xxx.com/lib/mod2' // {/}的意思即代表采用自有路径,即不跟随 base 路径
})

config.modules

config.modules 中用于存放模块物理路径

首次加载模块

if(!config.modules[item]){
    var node = doc.createElement('script'); // 创建script

    node.async = true; // 异步
    node.charset = 'utf-8'; // 文件格式

    // 请求的文件后面添加版本号
    node.src = url + function(){

        // 是否存在版本
        var version = config.version === true
        ? (config.v || (new Date()).getTime())
        : (config.version || '');

        return version ? ('?v=' + version) : '';
    }();

    head.appendChild(node); // 挂载节点

    // 对 IE 添加监听
    if(node.attachEvent && !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && !isOpera){
        node.attachEvent('onreadystatechange', function(e){
            onScriptLoad(e, url);
        });
    } else {
        node.addEventListener('load', function(e){
            onScriptLoad(e, url);
        }, false)
    }

    config.modules[item] = url;
}

会判断当前模块的物理路径是否已经在modules中,如果不在说明首次加载,否则进入非首次加载逻辑。
进入首次加载逻辑后,紧接着

  1. 创建 script 标签,并且设置 async 属性。

    async 属性具有一下两个主要性质

    • async 执行与文档顺序无关,先加载哪个就先执行哪个
    • async 脚本加载完成后立即执行,可以在DOM尚未完全下载完成就加载和执行
  2. 设置 src 属性值,需要注意的是 src 中会添加版本号

  3. 挂载

最后监听 load 或者 onreadystatechange 事件,当加载完毕后执行 onScriptLoad 函数。

onScriptLoad 函数

function onScriptLoad(e, url){
    var readyRegExp = navigator.platform === 'PLaySTATION 3' ? /^complete$/ : /^(complete|loaded)$/; // 根据平台选择正则表达式
    
    // 当前文件已经加载完毕
    if(e.type === 'load' || (readyRegExp.test(e.currentTarget || e.srcElement).readyState)){
        config.modules[item] = url; // 存储模块真实路径
        head.removeChild(node); // 从 head 中移除 node
        (function poll(){

            // 判断 timeout > 2500 ?
            if(++timeout > config.timeout * 1000 / 4) {

                // 超时报错
                return error(item + ' is not a valid module', 'error'); // 记得 return, 停止执行
            }

            // 判断当前模块状态是否为 true ,为 true 执行 onCallback, 否则轮询
            config.status[item] ? onCallback() : setTimeout(poll, 4);
        })()
    }
}
  1. 根据平台类型选择正则表达式
  2. 判断当前文件是否加载完毕
  3. 加载完毕后,会记录到 modules属性中,并把 script 标签从 head 中移出
  4. 最后轮询判断。 判断当前模块是否加载,如果没有加载继续轮询,直到超过指定超时时间限制,如果标识为已经加载则执行 onCallback 函数

config.status[item] 什么时候变为 true ?

请求到模块后,在模块内会调用 layui.define 函数,在该函数内的 setApp 函数中改变状态为 true

例如 lay 模块

if(window.layui && layui.define){
    layui.define(function(exports){ //layui 加载
    exports(MOD_NAME, lay); // 导出模块
    });
}

onCallback 函数

function onCallback(){

    // 向 exports 中推入模块
    exports.push(layui[item]); // layui 为实例对象中除了 v 属性标识版本号, 其余全为模块

    apps.length > 1 
    ? that.use(apps.slice(1), callback, exports, from)
    : ( typeof callback === 'function' && function(){

        // 保证文档加载完毕再执行调用
        if(layui.jquery && typeof layui.jquery === 'function' && from !== 'define' ) {
            return layui.jquery(function (){
                callback.apply(layui, exports);
            });
        }
        callback.apply(layui, exports);
    }());
}
  1. 首先会向 exports 数组中推入模块,里面的内容可以用于实例化
    例如 lay 模块
    var lay = function(selector){
      return new LAY(selector);
    }
    
    if(window.layui && layui.define){
      layui.define(function(exports){ //layui 加载
        exports(MOD_NAME, lay); // 导出模块
      });
    }
    
    这里的 lay 函数就是要向 exports 数组中推入的内容
  2. 判断是否还有依赖模块,有的话循环调用相同逻辑,没有的话就使用 apply 函数给 callback 动态绑定 this 并且传入 exports 参数

非首次加载

非首次加载和首次加载中poll函数类似,这里不做赘述

如有问题,欢迎指出

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/600963.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

StarRocks案例3: 通过[broadcast] 优化慢SQL

文章目录 一. 问题描述二. 解决方案三. 一些拓展 一. 问题描述 最近在使用StarRocks的时候&#xff0c;发现一个问题 table_a 10W 左右数据&#xff0c;通过where条件过滤数据后 剩下 10行数据。 table_b 5亿左右数据&#xff0c;通过where过滤条件后 剩下 5kw 数据。 table…

java物流快递寄件配送信息管理系统springboot+vue

物流信息管理系统分为管理员功能模块、配送员功能模块和用户功能模块三大部分&#xff0c;下面将对这三大功能模块分别进行介绍。 管理员功能模块&#xff1a;管理员登录后可对系统进行全面管理&#xff0c;管理员登录后主要实现的功能模块包括个人中心、用户管理、配送员管理、…

Deno:下载安装示例和打包为可执行文件

Deno&#xff1a;一个 安全的 JavaScript 和 TypeScript 运行时环境 目录 文档安装DenoHello World将程序打包成可执行程序 文档 官方文档 https://deno.com/manual 安装Deno Deno的解释器是一个可执行的单文件&#xff0c;下载解压即可使用 1、下载Deno 下载地址&#xf…

NFC无源标签协议

1、NFC写图片数据命令 无源NFC接口基于ISO/IEC 14443-3 A类标准&#xff1b; 命令起始地址结束地址数据 11164 67字节,每次写入的命令和地址都是一样的&#xff1b; 第一包数据必须发送该字符串数据"picksmart&M1&H128&W296&S1&C1"&#xff…

【C++】C++ 中的 IO 流

文章目录 一、C语言的输入输出二、什么是流三、C IO 流1、C 标准 IO 流2、C 文件 IO 流 四、stringstream 介绍 一、C语言的输入输出 在C语言中我们使用最频繁的输入输出方式是 scanf () 与 printf()&#xff1a; scanf()&#xff1a;从标准输入设备 (键盘) 读取数据&#xf…

数据库优化之常用的show table status及ALTER TABLE 重建表

文章目录 ⭐️ MySQL优化-碎片优化一、show table status from db_name【 如何判断是否有碎片&#xff1f;】1、碎片查询分析2、产生碎片的原因 二、MySQL 的表空间设置和优化策略【 如何清理碎片&#xff1f;】1、innodb_file_per_table 参数设置为 ON&#xff08;基本上是默认…

从小白到大佬,入门Linux系统收发网络数据包的秘密/

Linux 服务器收到网络数据包&#xff0c;需求经过哪些处置&#xff0c;一步步将数据传给应用进程的呢&#xff1f;应用进程发送数据包时&#xff0c;Linux 又是如何操作将数据包发送进来的呢&#xff1f;今天我们就来聊聊这个话题。 在准备好接纳网络数据包之前&#xff0c;Li…

python---基础小总结

1.常量和布尔值相加 当常量和布尔值相加的时候,如果是True就视为1来和常量相加. 反之,如果是False的话就视为0和常量相加. 但是这样的操作是没有任何意义的! 2.EG:以下情况是会报错的! 3.EG:加不加分号都可以,但是最好不加

相机的格式

图片的格式大体上可以分为yuv格式和RGB格式&#xff0c;以及png,jpg格式&#xff1b; 其中yuv格式对应的摄像头的格式可以是YUYV、UYVV、YVYU、VYUY&#xff1b; rgb格式的图片对应的摄像头格式为RGB,BGR,ARGB8888格式&#xff1b; 一、RGB8888和ARGB8888像素格式如果搞混了…

网站反爬虫策略的分析与研究

随着互联网的发展&#xff0c;爬虫技术也越来越成熟&#xff0c;越来越多的网站开始采取反爬虫策略来保护自己的数据和资源。以下是网站反爬虫策略的分析与研究&#xff1a; IP封禁&#xff1a;网站可以通过封禁某些IP地址来防止爬虫的访问。这种方法比较简单&#xff0c;但是容…

使用ChatGPT设计多选题

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

Spring-Retry实现及原理

前言 重试&#xff0c;其实我们其实很多时候都需要的&#xff0c;为了保证容错性&#xff0c;可用性&#xff0c;一致性等。一般用来应对外部系统的一些不可预料的返回、异常等&#xff0c;特别是网络延迟&#xff0c;中断等情况。还有在现在流行的微服务治理框架中&#xff0…

PDF4NET 13.1.0 Crack

PDF4NET 13.1.0 添加对云多边形和云方形注释的支持。 2023 年 6 月 1 日 - 16:50 新版本 特征 PDF4NET 添加了对 Cloud polygon 和 Cloud square 注释的支持。在文本标记注释中添加了对四点的支持。重大变化&#xff1a;重构了圆形、方形、折线和多边形注释的边框。PDF4NET.Ren…

Linux-线程基础

Linux线程基础 一&#xff0c;线程概念什么是线程Linux如何实现的线程 二&#xff0c;页表与虚拟内存虚拟内存多级页表 三&#xff0c;线程的特点线程的优点线程的缺点线程异常线程用途线程与进程比较 四&#xff0c;线程控制创建线程线程终止线程等待线程取消线程分离 五&…

python+vue宠物用品商城网站系统3zy71

依照这一现实为基础&#xff0c;设计一个快捷而又方便的网上宠物管理系统是一项十分重要并且有价值的事情。对于传统的宠物管理控制模型来说&#xff0c;在线宠物管理系统具有许多不可比拟的优势&#xff0c;首先是快速更新宠物分类、宠物信息、热销排行榜、宠物寄养&#xff0…

【嵌入式烧录/刷写文件】-1.8-S19文件转换为Hex文件

案例背景(共5页精讲)&#xff1a; 有如下一段Motorola S-record(S19/SREC/mot/SX)文件&#xff0c;将其转换为Hex文件。 S0110000486578766965772056312E30352EA6 S123910058595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576775B S123912078797A7B7C7D7E7F8081…

CodeWhisperer 初体验

今年算是 AI 正式破圈的一年&#xff0c;无数的工具&#xff0c;产品横空出世。无论在面向企业的大语言模型&#xff0c;还是帮助个人的 AI 工具&#xff0c;数不胜数。其中关于 AI 编程助手领域&#xff0c;近年来也涌现了很多不错的产品&#xff0c;例如 Copilot, Cursor, 还…

网络爬虫技术在搜索引擎中的应用

网络爬虫技术在搜索引擎中扮演着非常重要的角色&#xff0c;主要应用在以下几个方面&#xff1a; 网页抓取&#xff1a;搜索引擎需要从互联网上抓取大量的网页&#xff0c;以建立自己的索引库。网络爬虫技术可以帮助搜索引擎快速、高效地抓取网页。 网页解析&#xff1a;搜索引…

vue 自适应的方法

1、使用 filter来处理。 2、使用vue3.x中的 filter &#xff08;&#xff09;方法&#xff0c;但是要注意 filter &#xff08;&#xff09;方法的返回是一个字符串&#xff0c;在进行渲染时可能会有问题。 3、使用 react. js中的 require &#xff08;&#xff09;方法&#x…

实时数仓中数据实时输出的思考与实现

随着数据量不断增长以及提升企业竞争力的需求增长&#xff0c;实时数仓已经成为了许多业务和组织的重要数据架构之一。在实时数仓中&#xff0c;数据实时输入和数据实时分析是关键步骤&#xff0c;但同样重要的是如何将处理后的数据输出到各种目标上。本文将探讨实时数仓中数据…