“ 文章是翻译的, 原文链接在最下面,
很多javascript老手也会常用window.function_name, 但这位1994年就开始从事web编程的Michael Chaney向我们演示什么是正确的姿势.
”
使用webpacker的时候, 你要抛弃"你以为"的JavaScript的使用方式.
这里不再有 scoping issue (作用域问题)
当您将代码放入web pack文件里面时,它是自包含的,您可以使用import/export在文件之间共享代码.
默认情况下没有什么是全局的.
这是比较让人沮丧的, 你可能也和我一样, 在javascript文件里面声明一个function, 然后在你的html文件里面去调用, 或者直接在html文件的末尾加上一些javascript, 我从1994(你没看错)年就开始web编程, 因此我见证了很多次的演化. JavaScript已经发展了, 你必须学会新的方式.
如果你想给form或者其它加个action, 你可以在app/javascript下创建一个文件在里面写要做的内容. 那怎么获取数据? 你可以使用data attributes\ hidden fields 等, 如果这个filed不存在,那代码不会运行.
01
—
例1
这里有个你可能用的上的例子.
如果form里面有Google reCAPTCHA, 而你在提交这个form的时候没有选中这个box, 那就显示一个弹窗.
// 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; } } }); });});
注意, 它是自包含的,它不依赖任何其他的模块,也不被其它的依赖,你可以在你的pack文件里面直接require它, 那它就会watch所有的form提交.
02
—
例2
下面还有一个例子: 页面加载后,通过geojson overlay加载google map.
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); });});
页面加载完毕后, 我会查找class为'shuttle-route-version-map' 的div, 找到div里面保存这路线id(route id)的data attribute 'shuttleRouteVersionId' (data-shuttle-route-version-id)的值. 我把geojson保存在hidden field里面, 通过id也很容易被查询到, 然后我初始化地图.增加geojson, 然后根据数据设置map center和 bounds.
同样,除了Google Maps,它是自包含的.
03
—
例3
你也需要学会使用import/export去共享代码, 这确实强大.
下面的例子展示了如何使用import/export. 这里一段代码是设置了一个'watcher' 来监测你的位置.
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; }}
它exports了2个functions: "watch_position" 和"stop_watching_position", 你可以在其它文件中import他们.
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; }); }});
当这个页面加载后,我们会查找id为 "driver_location_check_latitude" 和 "driver_location_check_longitude" 的2个fields, 如果它们存在,我们设置一个回调的watcher, 这个callback(回调)的function的功能是给上面2个fields的赋值. 这就是在模块之间共享代码.
写在最后
—————
所以,再说一次,这是一种非常不同的方式。如果模块化和组织得当,您的代码会更干净、更可预测.
这是未来. 所以要与之抗争(window.function_name 正在与之抗争)将一事无成。
来自 stackoverflow.com