如何通过减少请求来改进 AJAX 实时搜索

2024-05-18

我正在构建一个 AJAX 实时搜索页面。到目前为止,一切都按预期运行,但我注意到我正在进行大量的 AJAX 调用。

我知道发生这种情况的地点和原因,但我找不到阻止这些 AJAX 调用发生的方法。

我将尝试给出快速解释,然后粘贴下面的代码。

在页面的左侧,我有一堆过滤器(例如位置、半径、兴趣、参与度、日期范围等)。它们中的每一个都有一个事件侦听器(例如更改)。当其中一个侦听器被触发时,我会更新查询参数并通过 AJAX 请求结果。

现在,当某人选择了 10 个兴趣(其中有 36 个),然后他分享 URL 时,就会出现问题,它看起来像这样:

现在首先,我会说我正在使用 iCheck.js 作为我的复选框。这意味着对“ifChecked”事件进行检查。 由于列表包含 10 个兴趣条目,因此“ifChecked”事件将被触发 10 次,从而导致 10 个 AJAX 请求。现在将其与 5 个 SDG、2 个参与、3 个位置……结合起来考虑,我最终会收到大量 AJAX 请求。 同时删除我的所有兴趣(有一个“删除”链接)时,它将触发“ifUnchecked”事件 10 次,从而再次执行 10 个 AJAX 请求。

这是我完整的 JS 代码,我尝试使用 HTML 等创建一个 jsfiddle,但代码与 CodeIgniter 框架有点混合,很难放置在那里。但 JS 代码足以让大家理解。

//Set vars available to entire scope for filtering
var searchLocation = null;
var searchRadius = 0;
var searchMin = 0;
var searchMax = 1000;
var searchMinPrice = 0;
var searchMaxPrice = 50000;
var searchSelectedInterests = [];
var searchSelectedSdgs = [];
var searchStartDate = moment().format('YYYY-MM-DD');
var searchEndDate = moment().add(1, 'years').format('YYYY-MM-DD');
var searchSelectedEngagements = [];

var getUrl = window.location;
var baseUrl = getUrl .protocol + "//" + getUrl.host + "/" + getUrl.pathname.split('/')[1];

$(document).ready(function(){
    'use strict';

    // Square Checkbox & Radio
    $('.skin-square input').iCheck({
        checkboxClass: 'icheckbox_square-blue'
    });
    $('.searchinterests input').on('ifChecked', function(event) {
        var interestid = event.target.value;
        searchSelectedInterests.push(interestid);
        updateURLParameters();
        performSearch();
    });
    $('.searchinterests input').on('ifUnchecked', function(event) {
        var interestid = event.target.value;
        var arrayPos = $.inArray(interestid, searchSelectedInterests);
        if (arrayPos > -1) {
            searchSelectedInterests.splice(arrayPos, 1);
        }
        performSearch();
    });
    $('.searchsdgs input').on('ifChecked', function(event) {
        var sdgid = event.target.value;
        searchSelectedSdgs.push(sdgid);
        updateURLParameters();
        performSearch();
    });
    $('.searchsdgs input').on('ifUnchecked', function(event) {
        var sdgid = event.target.value;
        var arrayPos = $.inArray(sdgid, searchSelectedSdgs);
        if (arrayPos > -1) {
            searchSelectedSdgs.splice(arrayPos, 1);
        }
        performSearch();
    });
    $('.searchengagements input').on('ifChecked', function(event) {
        var social_engagement_id = event.target.value;
        searchSelectedEngagements.push(social_engagement_id);
        updateURLParameters();
        performSearch();
    });
    $('.searchengagements input').on('ifUnchecked', function(event) {
        var social_engagement_id = event.target.value;
        var arrayPos = $.inArray(social_engagement_id, searchSelectedEngagements);
        if (arrayPos > -1) {
            searchSelectedEngagements.splice(arrayPos, 1);
        }
        performSearch();
    });

    var searchLocationSelect = $('.stb-search-location');
    var radiusSlider = document.getElementById('radius-slider');
    var minMaxSlider = document.getElementById('min-max-slider');
    var priceSlider = document.getElementById('price-slider');
    var daterangepicker = $('#searchdaterange');
    var curr_lang = $('#curr_lang').val();

    switch(curr_lang) {
        case 'nl':
            moment.locale('nl');
            daterangepicker.daterangepicker({
                minDate: moment(),
                startDate:  moment(),
                endDate: moment().add(1, 'years'),
                ranges: {
                    'Volgende week': [moment(), moment().add(1, 'weeks')],
                    'Volgende maand': [moment(), moment().add(1, 'months')],
                    'Volgende 3 maanden': [moment(), moment().add(3, 'months')],
                    'Volgende 6 maanden': [moment(), moment().add(6, 'months')],
                    'Volgend jaar': [moment(), moment().add(1, 'years')]
                },
                alwaysShowCalendars: true,
                locale: {
                    "customRangeLabel": "Vrije keuze",
                    "format": "DD-MM-YYYY"
                }
            });
            break;
        case 'en':
            moment.locale('en');
            daterangepicker.daterangepicker({
                minDate: moment(),
                startDate:  moment(),
                endDate: moment().add(1, 'years'),
                ranges: {
                    'Next week': [moment(), moment().add(1, 'weeks')],
                    'Next month': [moment(), moment().add(1, 'months')],
                    'Next 3 months': [moment(), moment().add(3, 'months')],
                    'Next 6 months': [moment(), moment().add(6, 'months')],
                    'Next year': [moment(), moment().add(1, 'years')]
                },
                alwaysShowCalendars: true,
                locale: {
                    "customRangeLabel": "Free choice",
                    "format": "DD-MM-YYYY"
                }
            });
            break;
        case 'fr':
            moment.locale('fr');
            daterangepicker.daterangepicker({
                minDate: moment(),
                startDate:  moment(),
                endDate: moment().add(1, 'years'),
                ranges: {
                    'Semaine prochaine': [moment(), moment().add(1, 'weeks')],
                    'Mois prochain': [moment(), moment().add(1, 'months')],
                    '3 mois prochains': [moment(), moment().add(3, 'months')],
                    '6 mois prochains': [moment(), moment().add(6, 'months')],
                    'L\'année prochaine': [moment(), moment().add(1, 'years')]
                },
                alwaysShowCalendars: true,
                locale: {
                    "customRangeLabel": "Libre choix",
                    "format": "DD-MM-YYYY"
                }
            });
            break;
    }
    daterangepicker.on('hide.daterangepicker', function (ev, picker) {
        var startdate = picker.startDate.format('YYYY-MM-DD');
        var enddate = picker.endDate.format('YYYY-MM-DD');
        setStartDate(startdate);
        setEndDate(enddate);
        updateURLParameters();
        performSearch();
    });

    if (searchLocationSelect.length) {
        searchLocationSelect.selectize({
            create: false,
            sortField: {
                field: 'text',
                direction: 'asc'
            },
            dropdownParent: 'body',
            plugins: ['remove_button'],
            onChange: function(value) {
                setLocation(value);
                var size = value.length;
                if (size == 1) {
                    enableRadius(radiusSlider);
                } else {
                    disableAndResetRadius(radiusSlider);
                }
                updateURLParameters();
                performSearch();
            }
        });
    }

    noUiSlider.create(radiusSlider, {
        start: [0],
        step: 5,
        range: {
            'min': 0,
            'max': 100
        }
    });
    var radiusNodes = [
        document.getElementById('radius-value')
    ];
    // Display the slider value and how far the handle moved
    // from the left edge of the slider.
    radiusSlider.noUiSlider.on('update', function (values, handle, unencoded, isTap, positions) {
        var value = values[handle];
        radiusNodes[handle].innerHTML = Math.round(value);
    });
    radiusSlider.noUiSlider.on('set', function (value) {
        setRadius(value);
        updateURLParameters();
        performSearch();
    });

    var minmax_slider_options = {
        start: [0,1000],
        behaviour: 'drag',
        connect: true,
        tooltips: [wNumb({
            decimals: 0
        }), wNumb({
            decimals: 0
        })],
        range: {
            'min': 0,
            'max': 1000
        },
        step: 5
    };
    noUiSlider.create(minMaxSlider, minmax_slider_options);
    var minMaxNodes = [
        document.getElementById('minmax-lower-value'),
        document.getElementById('minmax-upper-value')
    ];
    // Display the slider value and how far the handle moved
    // from the left edge of the slider.
    minMaxSlider.noUiSlider.on('update', function (values, handle, unencoded, isTap, positions) {
        var value = values[handle];
        minMaxNodes[handle].innerHTML = Math.round(value);
    });
    minMaxSlider.noUiSlider.on('set', function (values) {
        setMin(values[0]);
        setMax(values[1]);
        updateURLParameters();
        performSearch();
    });

    var price_slider_options = {
        start: [0,50000],
        behaviour: 'drag',
        connect: true,
        tooltips: [wNumb({
            decimals: 0
        }), wNumb({
            decimals: 0
        })],
        range: {
            'min': 0,
            'max': 50000
        },
        step: 250
    };
    noUiSlider.create(priceSlider, price_slider_options);
    var priceNodes = [
        document.getElementById('price-lower-value'), // 1000
        document.getElementById('price-upper-value')  // 3500
    ];
    // Display the slider value and how far the handle moved
    // from the left edge of the slider.
    priceSlider.noUiSlider.on('update', function (values, handle, unencoded, isTap, positions) {
        var value = values[handle];
        priceNodes[handle].innerHTML = '€'+Math.round(value);
    });
    priceSlider.noUiSlider.on('set', function (values) {
        setMinPrice(values[0]);
        setMaxPrice(values[1]);
        updateURLParameters();
        performSearch();
    });

    /** Reset methods **/
    $('#resetLocations').on('click', function(e) {
        e.preventDefault();
        var locationInputField = $('.stb-search-location');
        var control = locationInputField[0].selectize;
        control.clear();
    });

    $('#resetRadius').on('click', function(e) {
        e.preventDefault();
        document.getElementById('radius-slider').noUiSlider.set(0);
    });

    $('#resetMinMax').on('click', function(e) {
        e.preventDefault();
        document.getElementById('min-max-slider').noUiSlider.set([0,1000]);
    });

    $('#resetPrice').on('click', function(e) {
        e.preventDefault();
        document.getElementById('price-slider').noUiSlider.set([0,50000]);
    });

    $('#resetInterests').on('click', function(e) {
        e.preventDefault();
        searchSelectedInterests = [];
        $("input[name='interests[]']").iCheck('uncheck');
    });

    $('#resetSdgs').on('click', function(e) {
        e.preventDefault();
        searchSelectedSdgs = [];
        $("input[name='sdgs[]']").iCheck('uncheck');
    });

    $('#resetDate').on('click', function(e) {
        e.preventDefault();
        $('#searchdaterange').data('daterangepicker').setStartDate(moment());
        $('#searchdaterange').data('daterangepicker').setEndDate(moment().add(1, 'years'));

        var startdate = $('#searchdaterange').data('daterangepicker').startDate.format('YYYY-MM-DD');
        var enddate = $('#searchdaterange').data('daterangepicker').endDate.format('YYYY-MM-DD');
        setStartDate(startdate);
        setEndDate(enddate);
        performSearch();
    });

    $('#resetEngagement').on('click', function(e) {
        e.preventDefault();
        searchSelectedEngagements = [];
        $("input[name='engagement[]']").iCheck('uncheck');
    });

    // Set initial parameters (and pre-fill the filters based on query params) 
    setupConfig(radiusSlider);
});


function getQueryStringValue(){
    var currentURL = new URI();

    var queryParams = currentURL.query(true);
    if ($.isEmptyObject(queryParams) === false) {
        return queryParams;
    } else {
        return undefined;
    }
}

//In here we read the query parameters from the URL and set the filters to the query parameters (+ do initial filtering)
function setupConfig(radiusSlider) {
    var queryParams = getQueryStringValue();

    if (queryParams !== undefined) {
        var locations = queryParams.locations;
        if (locations !== undefined) {
            var locationsArray = locations.split(";");
            fillLocations(locationsArray);
            if (locationsArray.length != 1) {
                disableAndResetRadius(radiusSlider);
            }
        } else {
            disableAndResetRadius(radiusSlider);
        }

        var distance = queryParams.distance;
        if (distance !== undefined) {
            if (locationsArray.length != 1) {
                disableAndResetRadius(radiusSlider);
            } else {
                document.getElementById('radius-slider').noUiSlider.set(distance);
            }
        }

        var minEmployees = queryParams.minemployees;
        var maxEmployees = queryParams.maxemployees;
        if ((minEmployees !== undefined) && (maxEmployees !== undefined)) {
            document.getElementById('min-max-slider').noUiSlider.set([minEmployees,maxEmployees]);
        }

        var minPrice = queryParams.minprice;
        var maxPrice = queryParams.maxprice;
        if ((minPrice !== undefined) && (maxPrice !== undefined)) {
            document.getElementById('price-slider').noUiSlider.set([minPrice,maxPrice]);
        }

        var interests = queryParams.interests;
        if (interests !== undefined) {
            var interestsArray = interests.split(";");
            fillInterests(interestsArray);
        }

        var sdgs = queryParams.sdgs;
        if (sdgs !== undefined) {
            var sdgsArray = sdgs.split(";");
            fillSdgs(sdgsArray);
        }

        var startdate = queryParams.startdate;
        var enddate = queryParams.enddate;
        if ((startdate !== undefined) && (enddate !== undefined)) {
            $('#searchdaterange').data('daterangepicker').setStartDate(moment(startdate));
            $('#searchdaterange').data('daterangepicker').setEndDate(moment(enddate));

            var startdate = $('#searchdaterange').data('daterangepicker').startDate.format('YYYY-MM-DD');
            var enddate = $('#searchdaterange').data('daterangepicker').endDate.format('YYYY-MM-DD');
            setStartDate(startdate);
            setEndDate(enddate);
        }

        var engagements = queryParams.engagements;
        if (engagements !== undefined) {
            var engagementsArray = engagements.split(";");
            fillEngagements(engagementsArray);
        }
    } else {
        disableAndResetRadius(radiusSlider);
        performSearch();
    }
}

function fillLocations(locations) {
    var selectize = $('.stb-search-location');
    selectize[0].selectize.setValue(locations);
}

function fillInterests(interests) {
    for (var i = 0; i < interests.length; i++) {
        var checkboxId = "interest-"+interests[i];
        var checkbox = $('#'+checkboxId);
        checkbox.iCheck('check');
    }
}

function fillSdgs(sdgs) {
    for (var i = 0; i < sdgs.length; i++) {
        var checkboxId = "sdg-"+sdgs[i];
        var checkbox = $('#'+checkboxId);
        checkbox.iCheck('check');
    }
}

function fillEngagements(engagements) {
    for (var i = 0; i < engagements.length; i++) {
        var checkboxId = "eng-"+engagements[i];
        var checkbox = $('#'+checkboxId);
        checkbox.iCheck('check');
    }
}

function getCurrLang() {
    return $('#curr_lang').val();
}

function getCurrLangSegment() {
    return $('#curr_abbr').val();
}

function getLocation() {
    return $('#location').val();
}

function setLocation(value) {
    searchLocation = value;
}

function setRadius(value) {
    searchRadius = value;
}

function disableAndResetRadius(radiusSlider) {
    radiusSlider.noUiSlider.set(0);
    radiusSlider.setAttribute('disabled', true);
}

function enableRadius(radiusSlider) {
    radiusSlider.removeAttribute('disabled');
}

function setMin(value) {
    searchMin = value;
}

function setMax(value) {
    searchMax = value;
}

function setMinPrice(value) {
    searchMinPrice = value;
}

function setMaxPrice(value) {
    searchMaxPrice = value;
}

function setStartDate(value) {
    searchStartDate = value;
}

function setEndDate(value) {
    searchEndDate = value;
}

function performSearch() {
    $('#stb-items-placeholder').html('<div id="loading"><span>'+res.StbSearchPlaceholder+'</span></div>');

    var searchOptions = {
        type: 'POST',
        url: baseUrl + '/dashboard/socialteambuildings/search/getFilteredStbs',
        dataType: 'json'
    };

    var filterdata = {
        "curr_lang" : getCurrLang(),
        "curr_abbr" : getCurrLangSegment(),
        "location" : getLocation(),
        "interests": searchSelectedInterests,
        "sdgs": searchSelectedSdgs
    };

    var options = $.extend({}, searchOptions, {
        data: filterdata
    });

    // ajax done & fail
    $.ajax(options).done(function (data) {
        var mustacheJsonData = data.result;

        var html = Mustache.render( $('#stbItemGen').html(), mustacheJsonData );
        $('#stb-items-placeholder').html( html );
    });
}

function updateURLParameters() {
    if (searchLocation != null) {
        var locationsUrlString = searchLocation.join(";");
    }

    var distanceUrlString = Math.round(searchRadius[0]);
    var minEmployeesUrlString = Math.round(searchMin);
    var maxEmployeesUrlString = Math.round(searchMax);
    var minPriceUrlString = Math.round(searchMinPrice);
    var maxPriceUrlString = Math.round(searchMaxPrice);
    var interestUrlString = searchSelectedInterests.join(";");
    var sdgUrlString = searchSelectedSdgs.join(";");
    var startDateUrlString = searchStartDate;
    var endDateUrlString = searchEndDate;
    var engagementUrlString = searchSelectedEngagements.join(";");

    var params = {locations: locationsUrlString, distance: distanceUrlString, minemployees: minEmployeesUrlString, maxemployees: maxEmployeesUrlString, minprice: minPriceUrlString, maxprice: maxPriceUrlString, interests: interestUrlString, sdgs: sdgUrlString, startdate: startDateUrlString, enddate: endDateUrlString, engagements: engagementUrlString};
    var query = $.param(params);
    addURLParameter(query);
}

//This function removes all the query parameters and adds the completely newly built query param string again
function addURLParameter(queryString){
    var currentUrl = window.location.href;
    var urlNoQueryParams = currentUrl.split("?");
    var baseUrl = urlNoQueryParams[0];
    var result = baseUrl + "?" + queryString;
    window.history.replaceState('', '', result);
}

例如,我尝试在删除选项上使用 e.stopPropagation() 和 e.stopImmediatePropagation() 。这不会阻止事件返回 iCheck 库。


反跳在这里不起作用,因为问题不在于一个事件监听器在短时间内有太多请求,而在于许多独立的事件监听器一个接一个地触发。

可能的解决方案:

  1. 添加一个按钮,例如SEARCH它将实际执行搜索,而不是由单独的更新触发。这是解决许多独立听众问题的一个很好且简单的解决方案。

  2. 如果您不想添加新按钮,请执行以下操作。添加时间间隔setInterval使用 AJAX 执行搜索。并有一个标志是否应该执行搜索。然后,当复选框上的任一侦听器发生更改时,只需将标志设置为true。此外,如果请求已经在进行中,则在当前请求完成之前不要发出另一个 AJAX 请求。

伪代码如下:

var do_search = false, timer = null, doing_ajax = false, TROTTLE = 500;
timer = setTimeout(performSearch, TROTTLE);

function performSearch()
{
    if ( !do_search || doing_ajax )
    {
        timer = setTimeout(performSearch, TROTTLE);
        return;
    }
     doing_ajax = true;
     do_search = false;
     // do the ajax request here
     // ...
     // NOTE: on ajax complete reset the timer, eg timer = setTimeout(performSearch, TROTTLE);
     // and set doing_ajax = false;
}

// then your checkboxes listeners will simply update the do-search flag eg:
    $('.searchsdgs input').on('ifChecked', function(event) {
        var sdgid = event.target.value;
        searchSelectedSdgs.push(sdgid);
        updateURLParameters();
        //performSearch();
        do_search = true;
    });
    $('.searchsdgs input').on('ifUnchecked', function(event) {
        var sdgid = event.target.value;
        var arrayPos = $.inArray(sdgid, searchSelectedSdgs);
        if (arrayPos > -1) {
            searchSelectedSdgs.splice(arrayPos, 1);
        }
        //performSearch();
        do_search = true;
    });
    $('.searchengagements input').on('ifChecked', function(event) {
        var social_engagement_id = event.target.value;
        searchSelectedEngagements.push(social_engagement_id);
        updateURLParameters();
        //performSearch();
        do_search = true;
    });
    $('.searchengagements input').on('ifUnchecked', function(event) {
        var social_engagement_id = event.target.value;
        var arrayPos = $.inArray(social_engagement_id, searchSelectedEngagements);
        if (arrayPos > -1) {
            searchSelectedEngagements.splice(arrayPos, 1);
        }
        //performSearch();
        do_search = true;
    });

NOTE你可以调整TROTTLE用于在更即时的交互性和更少的 AJAX 请求之间取得平衡的间隔。尝试不同的值来感受它对您的应用程序的影响。

NOTE2您可以在此示例的基础上进行构建,使其像多重去抖例如,通过清除超时并在每个单独的侦听器中重置它来实现功能(而不是简单地设置do_search=true你可以设置do_search=true并清除之前的间隔并再次重置)。这将确保仅执行最后一次更新。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何通过减少请求来改进 AJAX 实时搜索 的相关文章

随机推荐

  • SQLite CreateDatabase 不支持错误

    我将 Entity Framework 4 2 CF 与 SQLite 一起使用 但是当我尝试启动该应用程序时 出现 提供商不支持 CreateDatabase 错误 这是我的模型映射 protected override void OnM
  • 覆盖XMLHttpRequest以实现跨域请求

    我想知道是否有一个 JavaScript 库可以覆盖XMLHttpRequest并允许透明地处理所有跨域请求 并通过我的同源服务器端代理无缝转发它们 我想要的是有一个通用的解决方案 可以与any用于发出跨域请求的 JavaScript 库
  • 如何获取 Python 中所有内置函数的列表?

    我正在尝试整理一个关于如何获取 Python 中所有内置函数的列表的规范示例 该文档很好 但我想用可证明的方法来演示它 在这里 我本质上将内置函数定义为默认命名空间的成员 这些成员可用且与旨在在模块中使用的函数的风格特征一致 即 它们提供一
  • SQL Server:将表达式转换为数据类型 bigint 时出现算术溢出错误

    这是我的查询顺序 SELECT CASE WHEN BarCode IS NOT NULL AND ExternelBarCode IS NULL THEN BarCode WHEN BarCode IS NULL AND Externel
  • 创建 Facebook 测试用户时访问令牌出现问题

    我正在尝试为我的 Facebook 应用程序创建测试用户 他们在 11 月份的博客文章 http developers facebook com blog post 429 中宣布了此功能 并在此处记录了该功能 http developer
  • 如何在使用 ajax 和 JQuery 时加密发布数据?

    服务器端我们可以对用户进行身份验证 但我希望 ajax 或 JQuery 发送数据时数据安全 就像在客户端一样 某人只能看到加密格式的任何调用的参数 那么我该怎么做呢 我在这个网站上看到过这个场景 EDIT 当数据来自服务器时 我们可以忽略
  • SSRS - RDLC Tablix 行不会跨页面拆分

    我有一个包含两列数据的 Tablix 部分名称和部分文本 对于某些部分 部分文本变得如此之大 以至于代表该部分的行占据了页面的 2 3 或更多 报告打印得很好 直到这些大行中的其中一个必须在页面末尾拆分并继续在下一页上 在这种情况下 并且仅
  • 尝试获取 Google accessToken

    看起来 无论我做什么 谷歌都在竭尽全力阻止我完成这个研究项目 我的项目让我使用 Google 电子表格作为数据库 并使用所述电子表格中的数据执行程序化的 Google 图片搜索 并向最终用户显示一些结果 设置说明 我开始按照此处的说明进行操
  • 非 hdfs 文件系统上的 hadoop/yarn 和任务并行化

    我已经实例化了 Hadoop 2 4 1 集群 并且发现运行 MapReduce 应用程序的并行化方式会有所不同 具体取决于输入数据所在的文件系统类型 使用 HDFS MapReduce 作业将生成足够的容器 以最大限度地利用所有可用内存
  • 如何使用 jQuery 进行同步请求?

    为什么不返回该函数的responseText function LoadBookmarksAsXml return ajax type GET async false url http www google com bookmarks ou
  • Android Things 5​​.1 - 9 位 UART

    我正在尝试使用 Android Things 支持 9 位 UART 当我尝试将数据大小设置为 9 时 我收到 IO 异常 唯一有效的配置是 7 位和 8 位 我知道可以使用奇偶校验错误中断进行 9 位模拟 但在 Android 上 我没有
  • 从日期变量创建月末日期

    我有一个包含日期变量的大型数据框 它反映了该月的第一天 有没有一种简单的方法来创建代表该月最后一天的新数据框日期变量 以下是一些示例数据 date start month seq as Date 2012 01 01 length 4 by
  • 如何清除 Slatejs v0.50+ 中的编辑器?

    我不知道如何删除 Slate v0 50 中编辑器中的所有内容 我曾经能够做这样的事情 editor moveToRangeOfDocument delete 我现在该怎么做 你需要先开始Location编辑器 然后结束Location 最
  • .NET CORE WEB API 接受整数列表作为 HTTP GET API 中的输入参数

    我正在使用 net core 3 Web api 下面是我的操作的样子 它使用 HTTP GET 我想传递几个字段 其中一个字段是整数列表 HttpGet Route cities public ActionResult
  • 尝试用 C# 创建数学输入面板

    如何在 C 中创建数学输入面板 我尝试将其放入 dll 中并调用它 但它立即关闭 include
  • 我可以从命令行打印 html 文件(带有图像、css)吗?

    我想从脚本中打印带有图像的样式化 html 页面 谁能建议一个开源解决方案 我使用的是 Linux Ubuntu 8 04 但也对其他操作系统的解决方案感兴趣 你可以给html2ps http user it uu se jan html2
  • 使用字符串中的变量名称访问变量值,R

    Intro 一个数据集有大量的age year变量 age 1990 age 1991 etc 我有一个字符串值数组length age years 表示这些变量 使得age years 1 回报 age 1990 etc Need 我想搜
  • 在 macOS 上为 MoviePy 安装 ffmpeg 失败并出现 SSL 错误

    我正在尝试编写一个 Python 程序 在 Mac OS 10 11 16 上使用 MoviePy 将 MP4 文件转换为 GIF 我用 import moviepy editor as mp 我收到一条错误消息 说我需要打电话imagei
  • 如何将 MySQL 查询输出保存到 Excel 或 .txt 文件? [复制]

    这个问题在这里已经有答案了 如何将 MySQL 查询的输出保存到 MS Excel 工作表 即使只能将数据存储在 txt文件 就可以了 From 将 MySQL 查询结果保存到文本或 CSV 文件中 http www tech recipe
  • 如何通过减少请求来改进 AJAX 实时搜索

    我正在构建一个 AJAX 实时搜索页面 到目前为止 一切都按预期运行 但我注意到我正在进行大量的 AJAX 调用 我知道发生这种情况的地点和原因 但我找不到阻止这些 AJAX 调用发生的方法 我将尝试给出快速解释 然后粘贴下面的代码 在页面