app html与laravel,Laravel 6 – laravel/ui 中的 vue 与 jquery

Laravel 应该是在5.几之后吧,其laravel/ui项目的前端框架默认使用Bootstrap与Vue。

1. 无法打印vue实例

对于vue官方文档中的例子,我们都可以在浏览器console窗口通过app变量打印出vue实例。

7edafc86444fb12c7cb9815e30726d91.png

但是在laravel/ui的页面中,我们打印app变量时候,输出的却是id="app"的那个dom元素,并不是在/resources/js/app.js中定义的vue实例。

ca98a1ca74137319f90c26740d4a871b.pngconst app = new Vue({

el: '#app',

});

原因是laravel mix在编译打包js文件的时候,会将每个js源文件作为一个独立的作用域,这样可以使不同js文件中的变量互不干扰。而这个app变量(打包时候还会将const变成var。。。=。=# js真是迷)的作用域就只在该/resources/js/app.js文件中。在其他地方是无法读取该变量的。

我们可以看一下laravel mix打包后生成的/pulbic/js/app.js文件,整个/resources/js/app.js源文件的代码(包括app变量)都被function(module, exports, __webpack_require__) 这个匿名函数包裹起来,所以app变量只作为该匿名函数的一个局部变量。/*!*****************************!*\

!*** ./resources/js/app.js ***!

\*****************************/

/***/ (function(module, exports, __webpack_require__) {

/**

* ...

*/

var app = new Vue({

el: '#app'

});

/***/ }),

一个题外话,关于webpack打包的基本原理。(laravel-mix就是基于webpack的封装)

webpack在打包项目中的js源文件,最终生成一个app.js的时候。我们来看一下最终的app.js的简化结构:(function(modules) { // 这是一个立即执行函数(IIFE)的形式

对于modules实参数组中的每个module:

执行module源代码 // 一个module就代表一个被打包的js源文件

})({"module_filename_1": (function() { module_1 源码 }),

"module_filename_2": (function() { module_2 源码 })

// 这就是modules的实参数组,每个js源文件的代码都被包裹在闭包中

});

这样子,每个js源文件就是一个module,用闭包将它们的作用域隔离开。然后通过IIFE的形式立即执行所有module闭包,即执行每个js源文件。

如果非要在全局范围使用该app变量,可以在/resources/js/app.js源文件中将该变量定义为window全局对象的一个属性:window.app = new Vue({

el: '#app',

});

这样在浏览器的console窗口打印app时候,就能打印出该vue实例了。

2. 无法立即使用jquery

我们来看一下laravel/ui是如何引入jquery的,在/resources/js/app.js中,通过require('./bootstrap'); 引入同目录下的bootstrap.js文件:try {

window.Popper = require('popper.js').default; // bootstrap的tooltips与popovers组件需要popper.js

window.$ = window.jQuery = require('jquery'); // 导入并注册jquery全局变量

require('bootstrap'); // 导入bootstrap

} catch (e) {}

所以我们可以看到,它已经将jQuery以及$符号注册到window全局对象中。理论上我们就可以直接在前端页面的代码中直接使用$符号了:

console.log($('.container'));

但是实际上它却报错了:Uncaught ReferenceError: $ is not defined。$未定义?它不是已经在/resources/js/bootstrap.js中注册了$符号了嘛。而如果我们将前端页面的这个代码修改一下:

window.onload = function() {

console.log($('.container'));

}

// console.log($('.container'));

在window.onload事件函数中使用这个$符号却是可行的。

这其实是由于laravel/ui前端模版页面app.blade.php在引入app.js文件的 。defer的意思是告诉浏览器将该脚本文件异步下载并延迟执行。

关于原生的 window.onload  、DOMContentLoaded 与 jquery的 $(document).ready 之间的区别,参考:https://api.jquery.com/ready/。(实际上去看jquery的源码会发现,jQuery.ready就是由DOMContentLoaded触发的)

总结一下js代码在浏览器中的执行顺序:

bea13789de9262f01ae328874da4a841.png

由于defer属性,使得当浏览器解析并执行console.log($('.container')); 这一句的时候,app.js文件还没被执行,jquery还没被引入。所以这时候“$ is not defined”。如果把这一句放在 window.onload 事件函数中,window.onload事件是在所有资源(包括图片、css、script)都加载完后才触发的,此时app.js已经下载并执行了。那么这时候再调用$符号就是OK的。

2.1 如何补救

a. 取消defer加载,并将

既然如上面所诉,那么我们把laravel/ui前端模版页面中

[Vue warn]: Cannot find element: #app

可以在浏览器的控制台窗口看到它报错了!jquery可以用了,却引发了vue的错误。

原因是在laravel/ui的前端模版app.blade.php中,这个

所以,在去掉defer属性的同时,我们还需要将这个

...

@yield('js')

// 后续继承这个app.blade的模版页都可以在这个section('js')中引入JavaScript

// 在这个section('js')中就能直接使用jquery了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值