有关从旧资产管道迁移到新的 webpacker 处理方式的说明,您可以在此处查看:
https://www.calleerlandsson.com/replacing-sprockets-with-webpacker-for-javascript-in-rails-5-2/
这是在 Rails 5.2 中从资产管道迁移到 webpacker 的操作指南,它让您了解 Rails 6 中的不同之处,因为 webpacker 是 javascript 的默认设置。特别是:
现在是时候将所有应用程序 JavaScript 代码从
app/assets/javascripts/ 到 app/javascript/。
要将它们包含在 JavaScript 包中,请确保在
应用程序/javascript/pack/application.js:
require('your_js_file')
所以,在app/javascript/hello.js 中创建一个文件,如下所示:
console.log("Hello from hello.js");
然后,在app/javascript/packs/application.js 中添加这一行:
require("hello")
(注意不需要扩展)
现在,您可以在浏览器控制台打开的情况下加载一个页面并看到“Hello!”控制台中的消息。只需在 app/javascript 目录中添加您需要的任何内容,或者最好创建子目录以保持您的代码井井有条。
更多信息:
这个问题被诅咒了。以前接受的答案不仅是错误的,而且是非常错误的,而最受支持的答案仍然是一个国家英里的目标。
上面的 anode84 仍在尝试以旧方式做事,如果您尝试这样做,webpacker 会妨碍您。当你迁移到 webpacker 时,你必须彻底改变你做 javascript 的方式并考虑 javascript。没有“范围问题”。当您将代码放入 web pack 时,它是独立的,您可以使用导入/导出在文件之间共享代码。默认情况下,没有什么是全局的。
我明白为什么这令人沮丧。你可能和我一样,习惯于在 javascript 文件中声明一个函数,然后在你的 HTML 文件中调用它。或者只是在 HTML 文件的末尾添加一些 javascript。自 1994 年以来,我一直在进行 Web 编程(不是拼写错误),所以我看到一切都发展了多次。 Javascript已经发展。你必须学习新的做事方式。
如果您想向表单或其他任何内容添加操作,您可以在 app/javascript 中创建一个文件来执行您想要的操作。要获取数据,可以使用数据属性、隐藏字段等。如果该字段不存在,则代码不会运行。
这是一个您可能会发现有用的示例。如果表单有 Google reCAPTCHA 并且用户在提交表单时没有选中该框,我会使用它来显示弹出窗口:
// For any form, on submit find out if there's a recaptcha
// field on the form, and if so, make sure the recaptcha
// was completed before submission.
document.addEventListener("turbolinks:load", function() {
document.querySelectorAll('form').forEach(function(form) {
form.addEventListener('submit', function(event) {
const response_field = document.getElementById('g-recaptcha-response');
// This ensures that the response field is part of the form
if (response_field && form.compareDocumentPosition(response_field) & 16) {
if (response_field.value == '') {
alert("Please verify that you are not a robot.");
event.preventDefault();
event.stopPropagation();
return false;
}
}
});
});
});
请注意,这是独立的。它不依赖于任何其他模块,也没有其他依赖于它。您只需在包中需要它,它就会监视所有表单提交。
这是在页面加载时加载带有 geojson 覆盖的谷歌地图的另一个示例:
document.addEventListener("turbolinks:load", function() {
document.querySelectorAll('.shuttle-route-version-map').forEach(function(map_div) {
let shuttle_route_version_id = map_div.dataset.shuttleRouteVersionId;
let geojson_field = document.querySelector(`input[type=hidden][name="geojson[${shuttle_route_version_id}]"]`);
var map = null;
let center = {lat: 36.1638726, lng: -86.7742864};
map = new google.maps.Map(map_div, {
zoom: 15.18,
center: center
});
map.data.addGeoJson(JSON.parse(geojson_field.value));
var bounds = new google.maps.LatLngBounds();
map.data.forEach(function(data_feature) {
let geom = data_feature.getGeometry();
geom.forEachLatLng(function(latlng) {
bounds.extend(latlng);
});
});
map.setCenter(bounds.getCenter());
map.fitBounds(bounds);
});
});
当页面加载时,我会寻找具有“shuttle-route-version-map”类的 div。对于我找到的每一个,数据属性“shuttleRouteVersionId”(data-shuttle-route-version-id)都包含路线的 ID。我已将 geojson 存储在一个隐藏字段中,可以根据该 ID 轻松查询该字段,然后我初始化地图,添加 geojson,然后根据该数据设置地图中心和边界。同样,除了 Google 地图功能外,它是独立的。
您还可以学习如何使用导入/导出来共享代码,这真的很强大。
所以,还有一个展示如何使用导入/导出。下面是一段简单的代码,用于设置“观察者”来观察您的位置:
var driver_position_watch_id = null;
export const watch_position = function(logging_callback) {
var last_timestamp = null;
function success(pos) {
if (pos.timestamp != last_timestamp) {
logging_callback(pos);
}
last_timestamp = pos.timestamp;
}
function error(err) {
console.log('Error: ' + err.code + ': ' + err.message);
if (err.code == 3) {
// timeout, let's try again in a second
setTimeout(start_watching, 1000);
}
}
let options = {
enableHighAccuracy: true,
timeout: 15000,
maximumAge: 14500
};
function start_watching() {
if (driver_position_watch_id) stop_watching_position();
driver_position_watch_id = navigator.geolocation.watchPosition(success, error, options);
console.log("Start watching location updates: " + driver_position_watch_id);
}
start_watching();
}
export const stop_watching_position = function() {
if (driver_position_watch_id) {
console.log("Stopped watching location updates: " + driver_position_watch_id);
navigator.geolocation.clearWatch(driver_position_watch_id);
driver_position_watch_id = null;
}
}
导出两个函数:“watch_position”和“stop_watching_position”。要使用它,您需要在另一个文件中导入这些函数。
import { watch_position, stop_watching_position } from 'watch_location';
document.addEventListener("turbolinks:load", function() {
let lat_input = document.getElementById('driver_location_check_latitude');
let long_input = document.getElementById('driver_location_check_longitude');
if (lat_input && long_input) {
watch_position(function(pos) {
lat_input.value = pos.coords.latitude;
long_input.value = pos.coords.longitude;
});
}
});
页面加载时,我们会查找名为“driver_location_check_latitude”和“driver_location_check_longitude”的字段。如果它们存在,我们设置一个带有回调的观察者,当它们发生变化时,回调会用纬度和经度填充这些字段。这就是如何在模块之间共享代码。
所以,这又是一种非常不同的做事方式。如果模块化和组织得当,您的代码会更清晰、更可预测。
这是未来,所以与它抗争(设置“window.function_name”就是在抗争)会让你一事无成。