微信小店内联框架中的日期时间选择
评论
收藏

微信小店内联框架中的日期时间选择

经验分享
憨
憨憨12
2026-08-18 09:43·浏览量:258
憨
憨憨12
影刀中级开发者
发布于 2026-08-18 09:43258浏览

问题说明

微信小店商品数据页采用 micro-app + ShadowRoot + iframe 结构,日期控件位于 iframe 内,导致影刀普通捕获出现内联框架、元素偏移,智能日期指令无法稳定使用。

解决方案

改用【执行JS脚本】直接操作 DOM。通过 micro-app → shadowRoot → iframe.contentDocument 进入日期页面,先点击“时间范围”打开日期面板,再根据传入的开始、结束日期自动选择年份、月份和日期。

参数格式:
2026-08-01|2026-08-18

流程:
打开时间范围 → 选择开始日期 → 选择结束日期 → 完成

JS代码

打开日期框代码:
function (element, input) {

    var micro = document.querySelector(
        'micro-app[name="statistics"]'
    );

    if (!micro) {
        return "失败:找不到 micro-app";
    }

    var iframe = micro.shadowRoot.querySelector(
        ".iframe-container iframe"
    );

    if (!iframe) {
        return "失败:找不到 iframe";
    }

    var doc =
        iframe.contentDocument ||
        iframe.contentWindow.document;


    function getText(el) {
        return String(
            el.innerText ||
            el.textContent ||
            ""
        ).replace(/\s+/g, "");
    }


    function isVisible(el) {

        if (!el) {
            return false;
        }

        var rect =
            el.getBoundingClientRect();

        return (
            rect.width > 0 &&
            rect.height > 0
        );
    }


    /*
     * 优先找截图里这种 target 容器
     */
    var targets =
        doc.querySelectorAll(
            ".target"
        );


    for (var i = 0; i < targets.length; i++) {

        var text =
            getText(targets[i]);


        if (
            text.indexOf("时间范围") >= 0 &&
            isVisible(targets[i])
        ) {

            targets[i].click();

            return (
                "成功点击时间范围:" +
                text
            );
        }
    }


    /*
     * 如果 class 变化,则按文本兜底
     */
    var all =
        doc.querySelectorAll(
            "button,div,span"
        );


    var best = null;


    for (var j = 0; j < all.length; j++) {

        if (!isVisible(all[j])) {
            continue;
        }


        var t =
            getText(all[j]);


        if (
            t.indexOf("时间范围") === 0 &&
            t.length < 80
        ) {

            /*
             * 选择最小的那个元素,
             * 防止找到整个筛选栏父容器
             */

            if (
                !best ||
                getText(best).length >
                t.length
            ) {

                best =
                    all[j];
            }
        }
    }


    if (!best) {
        return "失败:找不到时间范围选择框";
    }


    /*
     * 看看父级有没有 target
     */

    var node = best;

    for (var k = 0; k < 4 && node; k++) {

        if (
            String(
                node.className || ""
            ).indexOf("target") >= 0
        ) {

            node.click();

            return (
                "成功点击时间范围:" +
                getText(node)
            );
        }

        node =
            node.parentElement;
    }


    /*
     * 找不到特殊父级就直接点击文字元素
     */

    best.click();

    return (
        "成功点击时间范围:" +
        getText(best)
    );
}
选择日期范围代码:
function (element, input) {

    /* =========================================================
       参数格式:
       2026-01-05|2026-01-20
       ========================================================= */

    var text = String(input || "").trim();

    var parts = text.split("|");

    if (parts.length !== 2) {
        return "失败:参数格式应为 开始日期|结束日期,例如 2026-01-05|2026-01-20";
    }


    function parseDate(text) {

        var m = String(text).trim().match(
            /(\d{4})\D+(\d{1,2})\D+(\d{1,2})/
        );

        if (!m) {
            return null;
        }

        return {
            year: parseInt(m[1], 10),
            month: parseInt(m[2], 10),
            day: parseInt(m[3], 10)
        };
    }


    var startDate = parseDate(parts[0]);
    var endDate = parseDate(parts[1]);


    if (!startDate || !endDate) {
        return "失败:开始日期或结束日期格式错误";
    }


    /* =========================================================
       日期合法性
       ========================================================= */

    function toDate(d) {

        return new Date(
            d.year,
            d.month - 1,
            d.day
        );
    }


    var startObj = toDate(startDate);
    var endObj = toDate(endDate);


    if (startObj > endObj) {
        return "失败:开始日期不能晚于结束日期";
    }


    var diffDays =
        Math.floor(
            (endObj - startObj) /
            86400000
        ) + 1;


    if (diffDays > 31) {
        return "失败:时间范围超过31天,当前微信小店最多支持连续31天";
    }


    /* =========================================================
       获取 iframe
       ========================================================= */

    var micro = document.querySelector(
        'micro-app[name="statistics"]'
    );

    if (!micro) {
        return "失败:找不到 micro-app";
    }


    var shadow = micro.shadowRoot;

    if (!shadow) {
        return "失败:拿不到 shadowRoot";
    }


    var iframe = shadow.querySelector(
        ".iframe-container iframe"
    );

    if (!iframe) {
        return "失败:找不到 iframe";
    }


    var doc;

    try {

        doc =
            iframe.contentDocument ||
            iframe.contentWindow.document;

    } catch (e) {

        return "失败:iframe无法访问:" + e.message;
    }


    if (!doc) {
        return "失败:iframe document为空";
    }


    /* =========================================================
       通用工具
       ========================================================= */

    function getText(el) {

        if (!el) {
            return "";
        }

        return String(
            el.innerText ||
            el.textContent ||
            ""
        ).trim();
    }


    function isVisible(el) {

        if (!el) {
            return false;
        }

        var style =
            doc.defaultView.getComputedStyle(el);

        if (
            style.display === "none" ||
            style.visibility === "hidden"
        ) {
            return false;
        }

        var rect =
            el.getBoundingClientRect();

        return (
            rect.width > 0 &&
            rect.height > 0
        );
    }


    function realClick(el) {

        if (!el) {
            return;
        }

        try {

            el.dispatchEvent(
                new MouseEvent(
                    "mousedown",
                    {
                        bubbles: true,
                        cancelable: true,
                        view: doc.defaultView
                    }
                )
            );

            el.dispatchEvent(
                new MouseEvent(
                    "mouseup",
                    {
                        bubbles: true,
                        cancelable: true,
                        view: doc.defaultView
                    }
                )
            );

        } catch (e) {}

        el.click();
    }


    function waitFor(finder, timeout) {

        timeout = timeout || 4000;

        return new Promise(
            function (resolve, reject) {

                var start = Date.now();

                function check() {

                    var result = null;

                    try {
                        result = finder();
                    } catch (e) {}


                    if (result) {

                        resolve(result);
                        return;
                    }


                    if (
                        Date.now() - start >
                        timeout
                    ) {

                        reject(
                            new Error(
                                "等待页面变化超时"
                            )
                        );

                        return;
                    }


                    setTimeout(
                        check,
                        80
                    );
                }

                check();
            }
        );
    }


    /* =========================================================
       找指定年月对应的日历面板
       ========================================================= */

    function findMonthPanel(target) {

        var panels =
            doc.querySelectorAll(
                ".weui-desktop-picker__panel"
            );


        for (
            var i = 0;
            i < panels.length;
            i++
        ) {

            if (!isVisible(panels[i])) {
                continue;
            }


            var labels =
                panels[i].querySelectorAll(
                    ".weui-desktop-picker__panel__label"
                );


            var year = null;
            var month = null;


            for (
                var j = 0;
                j < labels.length;
                j++
            ) {

                var t =
                    getText(labels[j]);


                var ym =
                    t.match(/^(\d{4})年$/);


                if (ym) {

                    year =
                        parseInt(
                            ym[1],
                            10
                        );
                }


                var mm =
                    t.match(/^(\d{1,2})月$/);


                if (mm) {

                    month =
                        parseInt(
                            mm[1],
                            10
                        );
                }

            }


            if (
                year === target.year &&
                month === target.month
            ) {

                return panels[i];
            }
        }


        return null;
    }


    /* =========================================================
       找当前日期模式中的年份按钮
       ========================================================= */

    function findYearLabel() {

        var labels =
            doc.querySelectorAll(
                ".weui-desktop-picker__panel__label"
            );


        for (
            var i = 0;
            i < labels.length;
            i++
        ) {

            if (
                /^\d{4}年$/.test(
                    getText(labels[i])
                )
                &&
                isVisible(labels[i])
            ) {

                return labels[i];
            }
        }


        return null;
    }


    /* =========================================================
       年份选择界面找年份
       ========================================================= */

    function findYearOption(year) {

        var elements =
            doc.querySelectorAll(
                "a,td,button"
            );


        for (
            var i = 0;
            i < elements.length;
            i++
        ) {

            if (
                getText(elements[i]) ===
                    String(year)
                &&
                isVisible(elements[i])
            ) {

                /*
                 * 优先点击 a
                 */

                if (
                    elements[i].tagName
                        .toLowerCase() ===
                    "a"
                ) {

                    return elements[i];
                }


                var a =
                    elements[i]
                        .querySelector &&
                    elements[i]
                        .querySelector("a");


                if (a) {
                    return a;
                }


                return elements[i];
            }
        }


        return null;
    }


    /* =========================================================
       月份选择界面找月份
       ========================================================= */

    function findMonthOption(month) {

        var monthText =
            month + "月";


        var elements =
            doc.querySelectorAll(
                "a,td,button"
            );


        for (
            var i = 0;
            i < elements.length;
            i++
        ) {

            if (
                getText(elements[i]) ===
                    monthText
                &&
                isVisible(elements[i])
            ) {

                if (
                    elements[i].tagName
                        .toLowerCase() ===
                    "a"
                ) {

                    return elements[i];
                }


                var a =
                    elements[i]
                        .querySelector &&
                    elements[i]
                        .querySelector("a");


                if (a) {
                    return a;
                }


                return elements[i];
            }
        }


        return null;
    }


    /* =========================================================
       切换到指定年月

       如果当前左右两个月已经有目标月份,则不切。
       ========================================================= */

    function gotoMonth(target) {

        var current =
            findMonthPanel(target);


        if (current) {

            return Promise.resolve(
                current
            );
        }


        var yearLabel =
            findYearLabel();


        if (!yearLabel) {

            return Promise.reject(
                new Error(
                    "找不到年份按钮"
                )
            );
        }


        /*
         * 点击年份标题
         */

        realClick(yearLabel);


        /*
         * 等待目标年份出现
         */

        return waitFor(
            function () {

                return findYearOption(
                    target.year
                );

            },
            4000
        )

        .then(
            function (
                yearOption
            ) {

                /*
                 * 点击年份后,
                 * 微信小店自动进入月份选择
                 */

                realClick(
                    yearOption
                );


                return waitFor(
                    function () {

                        return findMonthOption(
                            target.month
                        );

                    },
                    4000
                );
            }
        )

        .then(
            function (
                monthOption
            ) {

                /*
                 * 点击月份后,
                 * 自动回日期模式
                 */

                realClick(
                    monthOption
                );


                return waitFor(
                    function () {

                        return findMonthPanel(
                            target
                        );

                    },
                    4000
                );
            }
        );
    }


    /* =========================================================
       在指定年月里面寻找日期
       ========================================================= */

    function findDay(target) {

        var panel =
            findMonthPanel(target);


        if (!panel) {
            return null;
        }


        /*
         * 先找 a。
         * 微信小店日期一般位于 td/a。
         */

        var links =
            panel.querySelectorAll(
                "a"
            );


        for (
            var i = 0;
            i < links.length;
            i++
        ) {

            if (
                getText(links[i]) !==
                    String(target.day)
            ) {

                continue;
            }


            if (!isVisible(links[i])) {
                continue;
            }


            var node =
                links[i];

            var disabled =
                false;


            /*
             * 检查自身和父级,
             * 排除禁用日期。
             */

            for (
                var p = 0;
                p < 4 && node;
                p++
            ) {

                var cls =
                    String(
                        node.className || ""
                    ).toLowerCase();


                if (
                    cls.indexOf(
                        "disabled"
                    ) >= 0
                    ||
                    cls.indexOf(
                        "disable"
                    ) >= 0
                ) {

                    disabled =
                        true;

                    break;
                }


                node =
                    node.parentElement;
            }


            if (!disabled) {

                return links[i];
            }
        }


        /*
         * 兜底
         */

        var items =
            panel.querySelectorAll(
                "td,button,span,div"
            );


        for (
            var j = 0;
            j < items.length;
            j++
        ) {

            if (
                getText(items[j]) ===
                    String(target.day)
                &&
                items[j].children.length === 0
                &&
                isVisible(items[j])
            ) {

                return items[j];
            }
        }


        return null;
    }


    /* =========================================================
       选择一个日期
       ========================================================= */

    function selectOne(target) {

        return gotoMonth(
            target
        )

        .then(
            function () {

                return waitFor(
                    function () {

                        return findDay(
                            target
                        );

                    },
                    4000
                );
            }
        )

        .then(
            function (
                dayElement
            ) {

                realClick(
                    dayElement
                );


                /*
                 * 给微信小店一点时间,
                 * 更新范围选择状态。
                 */

                return new Promise(
                    function (
                        resolve
                    ) {

                        setTimeout(
                            function () {

                                resolve(
                                    true
                                );

                            },
                            300
                        );
                    }
                );
            }
        );
    }


    /* =========================================================
       正式流程:
       开始日期 → 结束日期
       ========================================================= */

    return new Promise(
        function (resolve) {

            selectOne(
                startDate
            )

            .then(
                function () {

                    /*
                     * 第一天下去以后,
                     * 微信小店进入结束日期选择状态
                     */

                    return selectOne(
                        endDate
                    );
                }
            )

            .then(
                function () {

                    function pad2(n) {

                        return String(n)
                            .padStart(
                                2,
                                "0"
                            );
                    }


                    var startText =
                        startDate.year +
                        "-" +
                        pad2(
                            startDate.month
                        ) +
                        "-" +
                        pad2(
                            startDate.day
                        );


                    var endText =
                        endDate.year +
                        "-" +
                        pad2(
                            endDate.month
                        ) +
                        "-" +
                        pad2(
                            endDate.day
                        );


                    resolve(
                        "成功选择时间范围:" +
                        startText +
                        " ~ " +
                        endText
                    );
                }
            )

            .catch(
                function (e) {

                    resolve(
                        "失败:" +
                        e.message
                    );
                }
            );

        }
    );
}

收藏2
全部评论(1)
最新
发布评论
评论