有关如何从旧的 asset pipeline 迁移到新的 webpacker 的指南,请参见此处:
https://www.calleerlandsson.com/replacing-sprockets-with-webpacker-for-javascript-in-rails-5-2/
这是一个如何从 Rails 5.2 中的 asset pipeline 迁移到 webpacker 的指南,并且它会让你了解到在 Rails 6 中,由于 webpacker 是 javascript 的默认值,事情发生了什么变化。 特别地:
现在是时候将所有应用程序 JavaScript 代码从 app/assets/javascripts/ 移动到 app/javascript/。
要在 JavaScript pack 中包含它们,请确保在 app/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会妨碍您。当您将JavaScript移动到webpacker时,必须完全改变JavaScript的使用方式和思考方式。默认情况下,没有任何内容是全局的。
我理解这很令人沮丧。您可能和我一样习惯于在JavaScript文件中声明函数,然后在HTML文件中调用它。或者只需在HTML文件末尾添加一些JavaScript。我从1994年开始做Web编程(不是错别字),因此我已经看过多次演变。JavaScript已经发展了。您必须学习新的做事方式。
如果要向表单或其他内容添加操作,则可以创建一个在app/javascript中执行所需操作的文件。要将数据传递给它,可以使用数据属性、隐藏字段等。如果字段不存在,则代码不运行。
这是一个您可能发现有用的示例。如果表单具有Google reCAPTCHA并且用户在提交表单时没有勾选框,则我使用此功能显示弹出窗口:
document.addEventListener("turbolinks:load", function() {
document.querySelectorAll('form').forEach(function(form) {
form.addEventListener('submit', function(event) {
const response_field = document.getElementById('g-recaptcha-response');
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 叠加层的 Google 地图的另一个示例:
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。对于每个我找到的div,数据属性“shuttleRouteVersionId”(data-shuttle-route-version-id)包含路线的ID。我已经将geojson存储在一个隐藏的字段中,可以根据该ID轻松查询,然后初始化地图,添加geojson,然后根据该数据设置地图中心和边界。再次说明,它是自包含的,除了谷歌地图功能之外。
你还可以学习如何使用导入/导出来共享代码,这真的很强大。
所以,再来展示如何使用导入/导出。以下是一段简单的代码,用于设置“观察者”以监视您的位置:
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) {
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”就是抵制它)是无济于事的。