SEJ*_*EJU 4 javascript ruby-on-rails webpack webpacker ruby-on-rails-6
我正在尝试将Rails 3应用程序更新为Rails 6,并且由于无法访问我的Javascript函数,我现在的默认webpacker出现了问题。
我得到:ReferenceError: Can't find variable: functionName对于所有js函数触发器。
我所做的是:
console.log('Hello World from Webpacker');到index.jsimport "app_directory";到/app/javascript/packs/application.js添加到/config/initializers/content_security_policy.rb:
Rails.application.config.content_security_policy do |policy|
policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development?
end
Run Code Online (Sandbox Code Playgroud)我将“ Webpacker的Hello World”登录到控制台,但是当尝试通过<div id="x" onclick="functionX()"></div>浏览器访问简单的JS函数时,出现参考错误。
我了解到资产管道已被webpacker取代,这对于包含模块来说应该是很好的选择,但是我应该如何包括简单的JS函数?我想念什么?
提前致谢?
Mic*_*ney 20
有关从旧的资产管道迁移到新的 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 包中,请确保在 app/javascript/pack/application.js 中要求它们:
Run Code Online (Sandbox Code Playgroud)require('your_js_file')
所以,app/javascript/hello.js像这样创建一个文件:
console.log("Hello from hello.js");
Run Code Online (Sandbox Code Playgroud)
然后,在 中app/javascript/packs/application.js,添加以下行:
require("hello")
Run Code Online (Sandbox Code Playgroud)
(请注意,不需要扩展名)
现在,您可以在浏览器控制台打开的情况下加载页面并看到“Hello!” 控制台中的消息。只需在app/javascript目录中添加您需要的任何内容,或者更好地创建子目录以使您的代码井井有条。
更多信息:
这个问题被诅咒了。以前被接受的答案不仅是错误的,而且是极其错误的,而且最受好评的答案仍然是一英里之内。
上面的阳极84仍在尝试以旧方式做事,如果您尝试这样做,webpacker会妨碍您。当你转向 webpacker 时,你必须彻底改变你做 javascript 的方式并考虑 javascript。没有“范围问题”。当您将代码放入网络包时,它是独立的,您可以使用导入/导出在文件之间共享代码。默认情况下没有什么是全局的。
我明白为什么这令人沮丧。您可能和我一样,习惯于在 javascript 文件中声明一个函数,然后在 HTML 文件中调用它。或者只是在 HTML 文件的末尾添加一些 javascript。我从 1994 年开始从事网络编程(不是打字错误),所以我看到一切都在多次演变。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;
}
}
});
});
});
Run Code Online (Sandbox Code Playgroud)
请注意,这是自包含的。它不依赖于任何其他模块,也没有其他任何东西依赖它。您只需将它放在您的包中,它就会监视所有表单提交。
这是在加载页面时加载带有 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);
});
});
Run Code Online (Sandbox Code Playgroud)
当页面加载时,我查找类为“shuttle-route-version-map”的 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) {
// 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;
}
}
Run Code Online (Sandbox Code Playgroud)
导出两个函数:“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;
});
}
});
Run Code Online (Sandbox Code Playgroud)
当页面加载时,我们查找名为“driver_location_check_latitude”和“driver_location_check_longitude”的字段。如果它们存在,我们会设置一个带有回调的观察器,当它们发生变化时,回调会用纬度和经度填充这些字段。这就是如何在模块之间共享代码。
所以,再一次,这是一种非常不同的做事方式。如果模块化和组织得当,您的代码会更清晰、更可预测。
这是未来,因此与之抗争(并设置“window.function_name”就是与之抗争)将一事无成。
小智 6
查看webpacker如何“打包” js文件和功能:
/***/ "./app/javascript/dashboard/project.js":
/*! no static exports found */
/***/ (function(module, exports) {
function myFunction() {...}
Run Code Online (Sandbox Code Playgroud)
因此,webpacker将这些功能存储在另一个功能中,从而使其无法访问。不知道为什么会这样,或者不确定如何正确解决。
不过,有一种解决方法。您可以:
1)从以下位置更改功能签名:
function myFunction() { ... }
Run Code Online (Sandbox Code Playgroud)
至:
window.myFunction = function() { ... }
Run Code Online (Sandbox Code Playgroud)
2)保持功能的签名,是的,但你仍然需要添加到他们的参考如图所示在这里:
window.myFunction = myFunction
这将使您的功能可从“窗口”对象全局访问。
| 归档时间: |
|
| 查看次数: |
2406 次 |
| 最近记录: |