问题描述
假设我有一个包含以下页面的网站:Home
About
Friends
。
我想要做的是创建一个简单的 JavaScript 文件(称为 test.js
),因此当用户按下按钮时,我可以做一些简单的事情,例如:
function myFunction(name) {
console.log("Name = " + name);
}
现在是我提出问题的部分。我注意到 ruby 使用 project_name/app/views/layout/application.html.erb
并为所有三个页面(<head>
、Home
和 About
)提供相同的 Friends
。
然而,这不是我想在这里做的!我只希望 test.js
为 Friends
页面工作!
我是否在我的 project_name/app/views/home/friends.html.erb
中引用了它,如下所示:
<!-- At the bottom of friends.html.erb -->
<script type="text/javascript" src="directory-to-javascript-file"></script>
我也注意到在这个目录 project_name/app/javascript
下有一个 JavaScript 文件夹,里面有两个文件夹; channels
和 packs
。
这是我要添加我的 test.js
的位置吗?如果是,在哪个文件夹中?
总结:
解决方法
您有 2 种选择来放置 js,资产管道或 webpack。
资产管道可能更容易理解,
在 app/assets/javascripts/application.js
中,您可以简单地将您的测试函数放在所有 require 语句之后(或将其解压缩到一个独立文件并要求它)。确保您的 application.html.erb 有一个 <%= javascript_include_tag 'application'%>
你不需要在friends.html.erb中放置脚本标签,删除它,让布局和资产管道/webpacker为你处理
第二个选项是使用 webpacker。有很多关于如何在 Rails 中使用它的资源,最终熟悉它可能会更好,我只是想对于初学者来说,旧的资产管道可能会更容易一些; webpack 过程非常相似,所以一旦你理解了一个,你就可以轻松地转移到另一个。
在哪里引用 test.js 以便它只能被好友页面看到?
您可以为朋友控制器创建新布局。
class FriendsController < ApplicationController
layout "friends"
end
所以在你的布局目录中创建一个friends.html.erb。在friends.html.erb 中使用<%= javascript_include_tag 'friends' %>
。接下来为朋友创建一个清单(或包)文件:
app/assets/javascripts/friends.js
并要求您在那里需要的任何东西。这意味着朋友控制器将使用自己单独的 javascript 获得自己的布局。
我认为这就是您要找的。p>
您提到您在 pack
中有目录 app/javascript
,看来您正在使用 web packer 来处理 js 和 css。
所以这是适合您的解决方案。
在 test.js
目录中创建一个 pack
。
并在您在问题中提到的 project_name/app/views/home/friends.html.erb
中写下以下内容。
<%= javascript_pack_tag 'test' %>
并将所有 js 代码写入 test.js
文件。并且只会加载到提到的页面中。
如果您想与 home
和 about
等其他区域相同。为此创建 js 文件并将 <%= javascript_pack_tag 'js file name' %>
包含到适当的 html.erb 文件中。
这将帮助您对每个模块的视图具有相同的布局,但仍然有自己的 uniq js,仅需要特定视图。
您可能需要重新启动 rails 服务器。
希望我的回答有帮助。
,在 Rails 中,你真的想忘记“我只想在这个页面上加载这个 JS 文件”的概念——我认为这是一种反模式,会阻碍你。
Rails 使用 an assets pipeline / webpacker 来简化您的 JS 交付,使用 turbolinks 来“ajaxify”旧版本中的常规页面加载,Rails UJS 做了很多 ajax 技巧。这意味着您很可能会处理 ajax 和持久的浏览器会话,这会使这个想法成为一个真正的问题,因为您的 JS 会泄漏到您最初没有想到的上下文中,或者除非您重新加载整个页面,否则将无法正常工作.
而是从 event based programming 和行为的角度考虑,您可以用它们来增强 UI 元素。想想“我希望这种按钮做 X”而不是“我希望这个页面上的这个特定的东西做 X”。使用事件处理程序和 css 类来实现该目标:
document.addEventListener("click",(event) => {
if (!event.target.matches('.magic-button')) return;
console.log('You clicked a magical button!');
});
这使您的 JS 与页面本身分离并可重用,实际上使您的初始问题没有实际意义。如果您不想在其他页面上进行操作,请不要添加 magic-button
类。
如果您真的想执行“每页”javascript,我已使用一种方法将 controller_name
和 action_name
附加到 body 元素:
<body data-controller="<%= controller_name" %>" data-action="<%= action_name %>">
这让您只需读取数据属性即可知道您在应用程序中的位置:
// given controller = foos and action = bar the events are:
// * MyApp:loaded
// * MyApp:foos#bar
// * MyApp:foos
// * MyApp:#bar
const firePageEvents = (event) => {
// read the data attributes off the body element
const body = document.querySelector('body');
const details = {
action: body.dataset.action,controller: body.dataset.controller
};
const eventNames = [
"MyApp:loaded",`MyApp:${controller}#${action}`,`MyApp:${controller}`,`MyApp:#${action}`
];
// fire the events
eventNames.forEach((name) => {
let event = new CustomEvent(name,{ detail: details });
document.dispatch(event);
});
}
// fires the events either when turbolinks replaces the page
// or when the DOM is ready
if (window.Turbolinks && Turbolinks.supported) {
document.addEventListener("turbolinks:load",(event) => {
firePageEvents(event);
});
} else {
document.addEventListener("DOMContentLoaded",(event) => {
firePageEvents(event);
});
}
// this will be trigged when any page is loaded
document.addEventListener("MyApp:loaded",(event) => {
switch(event.details.action) {
case 'about':
console.log('about page loaded');
break;
case 'friends':
console.log('friends page loaded');
break;
}
});
// this will be trigged when the an action named "about" is rendered:
document.addEventListener("MyApp:#about",(event) => {
console.log('About page loaded',event.details);
});
// this will be triggered on the users load page
document.addEventListener("MyApp:users#index",(event) => {
console.log('User#index page loaded',event.details);
});
然后我们fire custom events您可以附加事件侦听器以使 JS 为特定控制器/动作触发。
此代码属于您的资产管道/包,并在其中有效地连接和交付。