繁体   English   中英

单击链接时 Javascript 停止工作

[英]Javascript stops working when a link is clicked

我一直在尝试使用 rails 7 创建一个 facebook 克隆应用程序。我使用 javascript 来呈现一些前端功能。 起初似乎没有任何问题,但是当我单击页面上的链接以重定向到其他视图时,javascript 停止工作。 我相信这可能是由于在 DOM 之前加载了脚本。 似乎可行的是重新加载页面,然后一切都按预期工作。 因此,我尝试在 javascript 中使用 window.location.reload() 命令,该命令有效,但是随着我添加更多链接,任务变得过于乏味,而且如果我希望重定向到另一个页面,该函数会将我重定向到同一页面。 那么有没有一种方法可以有效地实现所有 javascript 功能而无需重新加载页面。

app/javascript/application.js

// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "controllers"

function home(){
    let link = document.querySelector(".title-container")
    if (link!=null){
    link.addEventListener("click", function(){
        var location = window.location.origin 
        window.location.assign(location)
        // console.log(window.location)
        window.localStorage.setItem("activeBtn", "#index")
        // window.location.reload()
    })
}

    // let begin_session = document.querySelector(".actions")
    // console.log(begin_session)
    // if (begin_session != null)
    // {
    //     begin_session.addEventListener("click", function(){
    //         // var location = window.location.origin + "/"
    //         window.location.assign(location)
    //         console.log(location)
    //         window.localStorage.setItem("activeBtn", "#index")
    //         // window.location.reload()
    //     })  
    // }
    // console.log(window.location)    
}

function refresh(){
    let links = document.querySelector("a")
    console.log(links)
    for(let i=0; i<links.length ; i++ )
    {
        links[i].addEventListener("click", function(){
            console.log(this)

            window.location.reload()
        })
    }
}

function PageTransition(){
    const sectBtns = document.querySelectorAll(".page-control")
    // console.log(sectBtns)

    let flag = true
    var activeBtn = localStorage.getItem("activeBtn")

    // console.log(document.querySelector(activeBtn))
    if (document.querySelector(activeBtn) != null){
    document.querySelector(activeBtn).className += " active"
    }

    for (let i=0; i<sectBtns.length; i++){
        if (sectBtns[i].className.includes("active")){
            flag = false
            break
        }
    }

    if (flag)
    {
        if (document.querySelector("#home") != null) 
        document.querySelector("#home").className += " active"

    }
    for (let i = 0; i < sectBtns.length; i++){
        sectBtns[i].addEventListener("click", function(){
            // console.log(this)
            let currentBtn = document.querySelectorAll(".active");
            // currentBtn[0].className = currentBtn[0].className.replace("active", "")
            // this.className += " active"
            var id = "#"+this.id
            localStorage.setItem("activeBtn", id)
            console.log(localStorage.getItem("activeBtn"))
            console.log(window.location)
            var location = window.location.origin + localStorage.getItem("activeBtn").replace("#","/")
            window.location.assign(location)
            // refresh()
        })
    }

}

function profileMenu(){
    const profileBtn = document.querySelector(".profile")
    const posts = document.querySelector(".posts")
    // const navbar = document.querySelector(".navbar")
    const menu = document.querySelector(".profile-menu")

    if (profileBtn!= null){
    profileBtn.addEventListener("click", function(){
        if (menu.style.display === "none"){
            menu.style.display = "block";
        }else{
            menu.style.display = "none"
        }
    })

    if (posts != null){
    posts.addEventListener("click", function(){
        if (menu.style.display === "block")
        menu.style.display = "none"
    })
}
}
}

// function like(){
//     const btn = document.querySelectorAll(".like-btn")
//     for (let i=0; i< btn.length; i++){
//         let current_btn = btn[i]    
//         current_btn.addEventListener("click", function(){
//         if (current_btn.className.includes("liked"))
//             current_btn.className = current_btn.className.replace("liked", "")
//         else
//             current_btn.className += " liked"
//         })
//     }
// }

function new_post(){

    const bar = document.querySelector(".post-creator")
    if (bar != null){
    const poster = document.querySelector(".new-post")
    const homepage = document.querySelector(".homepage")
    const body = document.querySelector("body")
    const close = document.querySelector(".close")
    bar.addEventListener("click", function(){
        if (poster.style.display === "none"){
            poster.style.display = "block"
            console.log(poster.style.display)
            homepage.style.opacity = "0.5"
            poster.style.opacity = "1"
            var btn = document.querySelector('.submit')
            console.log(btn)
            btn.addEventListener("click", function(){
                window.location.reload()    
            })

        }
        else{
            poster.style.display = "none"
            homepage.style.opacity = "1"
        }
    })
    
    // homepage.addEventListener("click", function(){
    //     if (poster.style.display === "block")
    //     poster.style.display = "none"
    // })
    close.addEventListener("click", function(){
        if (poster.style.display === "block"){
            poster.style.display = "none"
            homepage.style.opacity = "1"
            window.location.reload()

        }
    })
    }
}


switch (document.readyState){
case "interactive":
    PageTransition()
    profileMenu()
    // like()
    new_post()
    home()
    // refresh()
    console.log("hi")
    break;
}

您可以简单地将defer属性添加到您的script标签

<script src="script.js" defer></script>

不确定上下文,但可能是加载 JS 的方式。 这些函数不应该在 app/javascript/application.js 中,它是整个应用程序 JS 的入口点。 此外,没有理由为窗口对象设置任何属性。 页面特定的 JS 应该只加载在您需要它的页面上 + 有助于分离关注点。

该视频包含导入地图的关键概念https://youtu.be/PtxZvFnL2i0

刺激在这种情况下会很好地工作,它可以为你处理状态。 即使您不想使用它的所有功能,设置起来并不复杂 + 看起来您已经安装了它,因此它可能是一个快速的解决方案,同时也匹配您应用的当前层次结构。

在项目目录的根目录中运行

$ rails g stimulus controller_that_renders_the_view/controller_action

例如,我在app/controllers/ posts_controller.rb 下有一个 PostsController,我希望 JS 用于app/views/posts/index.html.erb中的索引操作(PostsController#index)

$ rails g stimulus posts/index

这将创建文件app/javascript/controllers/posts/index_controller.js

console.log('app/javascript/controllers/posts/index_controller.js connected')添加到新文件中的连接函数中,如下所示:

// app/javascript/controllers/posts/index_controller.js

import { Controller } from "@hotwired/stimulus"

// Connects to data-controller="posts--index"
export default class extends Controller {
  connect() {
    console.log('app/javascript/controllers/posts/index_controller.js connected')
  }
}

打开config/importmap.rb文件,您应该会看到该行

pin_all_from "app/javascript/controllers", under: "controllers"

除非它已被删除。 我的新 Rails 应用程序如下所示:

# config/importmap.rb

# Pin npm packages by running ./bin/importmap

pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers" 
# ^^^ Because all from app/javascript/controllers is pinned you will be able to use all files under app/javascript/controllers throughout the app without additional setup

importmap.rb在配置目录中,由于您的 JS 被固定通过它,您需要重新启动服务器以使用新文件

您可能还需要预编译资产以确保所有资产都已编译并可用于您的应用程序。

$ rails assets:precompile && rails s

将您的 HTML 包装在一个元素中,其中包含您希望刺激控制器能够访问的数据属性data-controller="posts--index"

<!-- app/views/posts/index.html.erb -->

<span data-controller="posts--index">
  <!-- app/javascript/controllers/posts/index_controller.js will have access to everything wrapped in this span -->

  <p style="color: green"><%= notice %></p>
  <h1>Posts</h1>

  <div id="posts">
    <% @posts.each do |post| %>
      <%= render post %>
      <p>
        <%= link_to "Show this post", post %>
      </p>
    <% end %>
  </div>
  <%= link_to "New post", new_post_path %>

</span>

打开浏览器控制台并访问 posts#index 页面,您应该会在控制台中看到 app/javascript/controllers/posts/index_controller.js 已连接。

您还可以将 initialize() 和 disconnect() 函数添加到您的 posts/index_controller 以掌握它的窍门,如下所示:

// app/javascript/controllers/posts/index_controller.js

import { Controller } from "@hotwired/stimulus"

const postControllerIndexFilePath = "app/javascript/controllers/posts/index_controller.js"

// Connects to data-controller="posts--index"
export default class extends Controller {

  // Optional function for when controller is initialized, can remove
  initialize(){
    console.log(`${postControllerIndexFilePath} initialized`)
  }

  // Optional function for when controller is connected, can remove
  connect(){
    console.log(`${postControllerIndexFilePath} connected`)
    this.exFunction()
    // Other functions you want to execute when controller is connected
  }

  // Optional function for when controller is disconnected, can remove
  disconnect() {
    console.log(`${postControllerIndexFilePath} disconnected`)
  }


  exFunction(){
    console.log("\nsuper cool exFunction function")
  }
}

Stimulus 允许您通过数据属性与目标进行交互,因此您不必使用查询选择器来选择它们。 您可以在此处了解更多信息。 没有涵盖将您的 JS 文件与 content_for 块分开,以便您可以将特定于文件的 JS 生成到其相关页面,但 DHH 在第一个链接中对此进行了介绍。

另外,请随时查看这个import_map 演示 repo ,它是几个月前为了熟悉 import_maps 而制作的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM