【问题标题】:Moving inline javascript function to external file and convert to jQuery将内联 javascript 函数移动到外部文件并转换为 jQuery
【发布时间】:2017-10-13 02:50:03
【问题描述】:

我正在尝试优化我在 phpBB3 上的“剧透”bbcode。

现在,我有一个可行的解决方案,但每次使用“spoiler”bbcode 标签时,phpBB 都会注入内联 javascript。我想调用一个通用函数,而不是每次使用 bbcode 时都内联添加。

这是工作的内联javascript:

<div class="spoiler">
    <div class="spoiler-title">
        <span onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.parentNode.getElementsByTagName('a')[0].innerText = 'hide'; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.parentNode.getElementsByTagName('a')[0].innerText = 'show'; }">
            <strong>{TEXT1}</strong> (<a href="#" class="spoiler-btn" title="Show hidden content">show</a>)
        </span>
    </div>
    <div class="spoiler-text">
        <div style="display: none;">
            {TEXT2}
        </div>
    </div>
</div>

为了阅读方便,这里重复一下内联的onclick函数:

if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') {
    this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = '';
    this.parentNode.getElementsByTagName('a')[0].innerText = 'hide';
} else {
    this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none';
    this.parentNode.getElementsByTagName('a')[0].innerText = 'show';
}

单击“spoiler-btn”类的锚点有一个preventDefaults,以防止单击将您带到页面顶部:

$(document).ready(function(){

    $(".spoiler-btn").click(
      function(e) {
        e.preventDefault();
      }
    );

});

我试图将 span onclick 内联 javascript 替换为将“this”传递给外部 javascript 文件的函数调用。我似乎无法让它工作,所以我尝试使用 jQuery 来捕获“this”以遍历 DOM 以找到包含在“spoiler-text”div 中的“div”并操纵 display:none。页面上可以有多个这样的剧透标签,所以我不能给“剧透文本”div 中的 div 一个 id。

这里我把span的onclick改成了外部函数:

onclick="spoilerToggle(this);"

然后我的外部文件中有以下内容:

var spoilerToggle = function(param) {
    if ($(this).parent('div').parent('div').hasClass('spoiler-text').css('style') == 'none') {
        ($(this).parent('div').parent('div').hasClass('spoiler-text').removeAttr('style'));
        ($(this).parent('div').$('a').text('hide'));
    } else {
        ($(this).parent('div').parent('div').hasClass('spoiler-text').css('display', 'none'));
        ($(this).parent('div').$('a').text('show'));
    }
}

然后控制台给出以下错误: bbcode.js:22 Uncaught TypeError: $(...).parent(...).parent(...).hasClass(...).css is not a function

第 22 行是带有“if”检查的行。

jQuery 已加载到网站上,并且我确保在 body 标记关闭之前调用我的外部 javascript 文件。

我觉得我已经掉进了兔子洞,看不到光了。我确信这比我想象的要容易得多。

非常感谢任何帮助。谢谢!

【问题讨论】:

    标签: javascript jquery html css


    【解决方案1】:

    .hasClass() 返回一个布尔值,因此您不能在它之后链接其他方法。这就是为什么你会得到你引用的错误。

    我会以不同的方式实现它:

    $(document).on("click", ".spoiler-title", function(e) {
      e.preventDefault();
      var container = $(this).closest(".spoiler");
      container.find(".spoiler-btn").text(function(i, currentText) {
        return currentText === "show" ? "hide" : "show"
      });
      container.find(".spoiler-text div").toggle();
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <div class="spoiler">
        <div class="spoiler-title">
            <span>
                <strong>{TEXT1}</strong> (<a href="#" class="spoiler-btn" title="Show hidden content">show</a>)
            </span>
        </div>
        <div class="spoiler-text">
            <div style="display: none;">
                {TEXT2}
            </div>
        </div>
    </div>

    上面使用绑定到文档的单个委托点击处理程序来处理页面上所有扰流板元素的点击(您可以将其绑定到较低级别的容器元素,无论最低级别是包含所有剧透)。

    在处理程序中,this 将引用单击的元素,因此使用 DOM 导航方法,例如 .closest().find(),您可以上到包含 div,然后再下到要操作的元素。 .closest() 比尝试链接 .parent().parent() 更灵活,因为它会自动上升,直到找到与指定选择器匹配的元素,所以如果你以后更改 HTML 结构,JS 可能不需要更改。

    如果 .text() 调用看起来令人困惑,那么 jQuery 会调用我作为参数传递给 .text() 的函数,将元素文本的当前值传递给它,然后返回的任何值都会成为新文本。

    【讨论】:

    • 非常感谢!我必须将 onclick 选择器从剧透标题类调整为 a.spoiler-btn 才能使其正常工作。
    • 没问题。我使用.spoiler-title 作为点击选择器,因为我认为您希望能够点击该 div 中的任何位置(如果您运行我的 sn-p,您可以看到它正在工作),不一定只是在锚点上,因为在您原来的内联中JS 你在跨度而不是锚点上有你的点击处理程序。如果您只想通过单击锚点本身来完成显示/隐藏,那么我显示的代码可以简化一点。您可能还想尝试.slideToggle() 而不是.toggle(),添加一些简单的动画。
    • 哦,这更有意义!然而,这只会使点击标题起作用——点击锚点并没有做任何事情。我还在选择器前面添加了 .postbody ,因为这是 div phpBB3 用于帖子的容器 div,根据您上面的建议。
    • “单击锚点没有做任何事情” - 这很奇怪,因为在我的演示 sn-p 中单击锚点可以正常工作。也许在您的实际项目中还有其他一些不同之处。关于容器 div,我的意思是 $(".postbody").on("click", ".spoiler-title", function() {...}),即,将容器 div 的选择器放在我有 document 的位置(只要它引用 JS 运行时存在的静态元素,而不是稍后通过 Ajax 加载的元素)。
    • 我将选择器更改为 .postbody .spoiler-title 并单击标题上的任意位置,锚点现在效果很好。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-30
    • 1970-01-01
    • 1970-01-01
    • 2012-11-16
    • 2020-11-25
    • 2022-12-05
    相关资源
    最近更新 更多