[英]How to write JavaScript for Ruby On Rails?
假設我有一個包含以下頁面的網站: Home
About
Friends
。
我想做的是創建一個簡單的 JavaScript 文件(稱為test.js
),所以當用戶按下按鈕時,我可以做一些簡單的事情,例如:
function myFunction(name) {
console.log("Name = " + name);
}
現在到了我有問題的部分。 我注意到 ruby 使用project_name/app/views/layout/application.html.erb
並為所有三個頁面( Home
, About
和Friends
)提供相同的<head>
。
但是,這不是我想在這里做的! 我只希望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
的地方,如果是,在哪個文件夾中?
所以總結一下:
test.js
文件保存在哪個文件夾中?test.js
以便它只對Friends
頁面可見? 您有 2 個選擇來放置 js、資產管道或 webpack。 資產管道可能更容易理解,在app/assets/javascripts/application.js
中,您可以簡單地將測試 function 放在所有 require 語句之后(或將其提取到獨立文件並要求它)。 確保您的 application.html.erb 有一個<%= javascript_include_tag 'application'%>
您不需要在 friends.html.erb 中添加腳本標簽,將其刪除,讓布局和資產管道/webpacker 為您處理
第二種選擇是使用 webpacker。 有很多關於如何在 Rails 中使用它的資源,最終熟悉它可能會更好,我只是認為對於初學者來說,舊的資產管道可能更容易一些; webpack 過程非常相似,因此一旦您了解其中一個,您就可以輕松轉移到另一個。
在哪里引用 test.js 以便它只對好友頁面可見?
您可以為朋友 controller 創建一個新布局。
class FriendsController < ApplicationController
layout "friends"
end
所以在你的布局目錄中創建一個friends.html.erb。 在friends.html.erb 中使用<%= javascript_include_tag 'friends' %>
。 接下來為朋友創建一個清單(或包)文件: app/assets/javascripts/friends.js
並在其中需要您需要的任何內容。 這將意味着朋友 controller 將獲得自己的布局和自己獨立的 javascript。
我想這就是你要找的。
您提到您在app/javascript
中有目錄pack
,似乎您正在使用 web 打包器用於 js 和 css。
所以這里是你的解決方案。
在pack
目錄中創建一個test.js
並將以下內容寫入您在問題中提到的project_name/app/views/home/friends.html.erb
。
<%= javascript_pack_tag 'test' %>
並在test.js
文件中編寫所有 js 代碼。 這將被加載到僅提到的頁面中。
如果您想與其他區域(例如home
和about
)進行相同的操作。 為此創建 js 文件並將<%= javascript_pack_tag 'js file name' %>
包含到相應的 html.erb 文件中。
這將幫助您為每個模塊的視圖擁有相同的布局,但仍然擁有它自己的 uniq js,只需要特定的視圖。
您可能需要重新啟動 rails 服務器。
希望我的回答有幫助。
在 Rails 中,你真的想忘記“我只想在這個頁面上加載這個 JS 文件”的概念——我認為它是一種反模式,會讓你望而卻步。
Rails 使用資產管道/ webpacker來簡化您的 JS 交付,在舊版本中使用渦輪鏈接“ajaxify”常規頁面加載,Rails UJS 做了很多 ajax 詭計。 這意味着您很可能會處理 ajax 和持久的瀏覽器會話,這使得這個想法成為一個真正的問題,因為您的 JS 泄漏到您最初沒有想到的上下文中,或者除非您重新加載整個頁面否則根本無法工作.
而是考慮基於事件的編程和可以用來增強 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
class。
如果你真的想做“每頁” Z action_name
我用它來將controller_name
名稱和動作名稱附加到正文元素的一種方法:
<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);
});
然后我們觸發自定義事件,您可以附加事件偵聽器以使 JS 觸發特定的控制器/操作。
此代碼屬於您的資產管道/包中,其有效地連接和交付。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.