Vue中引用第三方JS文件

使用Vue时会经常使用jQuery、bootstrap这类第三方工具库,而boostrap的渲染不仅依赖于jQuery js文件的加载,也依赖于HTML中DOM树内容的加载。但Vue中DOM树是有Vue的app.js动态生成,因此js文件的引用顺序关系boostrap是否能够渲染成功。

以下没有贴所有的代码,可能有信息缺失引起歧义,可以发送邮件到hugh@inner-peace.cn 咨询和探讨。

遇到这个场景,最开始会使用的错误方法会在index.html中如下编写代码。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimal-ui">
  <title>Wrong Example</title>
  <link rel="shortcut icon" href="/static/images/favicon.ico">
  <link rel="stylesheet" type="text/css" href="/static/css/bootstrap.min.css">
</head>
<body>
  <div id="app"></div>
  <script src="assets/js/jquery.min.js"></script>
  <script src="assets/js/bootstrap.bundle.min.js"></script>
  <script src="assets/js/jquery.slimscroll.js"></script>
</body>
</html>

以上的代码是希望使用jQuery和boostrap完成一个scroll的控件功能,但实际上是不能实现的,主要因为VUE构建项目会更新index.html,并在自动在之前增加一行代码

<body>
  <div id="app"></div>
  <script src="assets/js/jquery.min.js"></script>
  <script src="assets/js/bootstrap.bundle.min.js"></script>
  <script src="assets/js/jquery.slimscroll.js"></script>
  <!-- App js VUE自动增加在body标签最后 -->
  <script src="assets/js/app.js"></script>
</body>

app.js动态构建DOM树,这导致提前加载的jquery.slimscroll.js和bootstrap.bundle.min.js是无法找到对应的DOM elements进行渲染。

解决这个问题,需要使用以下方式。

增加utils.js,export一个自己编写的LoadJS函数

export function LoadJS (p, callback) {
  const oScript = document.createElement('script');
  oScript.type = 'text/javascript';
  oScript.src = p;
  if (oScript.onreadystatechange) {
    oScript.onreadystatechange = function () {
      if (this.readyState === 'complete' || this.readyState === 'loaded') {
        oScript.onreadystatechange = null;
        if (callback != null) {
          callback();
        }
      }
    };
  } else {
    oScript.onload = function () {
      if (callback != null) {
        callback();
      }
    };
  }
  document.body.appendChild(oScript);
}

之后在components中的VUE文件中使用

<template>
  <div>...</div>
</template>

<script>
  import {LoadJS} from '../assets/js/utils.js';
   LoadJS('/static/js/jquery.min.js', function () {
   	LoadJS('/static/js/bootstrap.bundle.min.js', null);
    LoadJS('/static/js/jquery.slimscroll.js', null);
  });
  export default {
    name: 'Example',
    components: {Example}
  };
</script>

<style scoped>

</style>

为什么针对jquery.min.js需要使用callback,是因为LoadJS调用后是异步load js文件,可能导致先load完bootstrap.bundle.min.js,之后在load完jquery.min.js,这样会导致boostrap找不到jQuery而报错,因此需要基于callback实现同步等待的机制。