一 第三方 JavaScript 库
前言
.vue 文件 中不解析 script 标签引入 JS 文件, 只能用 import 引入
有两种用法:
- import a from '../a'
- import '../a'
区别在于第一个你要用到 export 导出之后 才能用 import 导入.
第二个是直接引入 和 script 标签是一样的. 但是它作用在自己的 JS 文件中.
在使用 vue 做项目的时候, 我们一般不将 CSS 样式写到各自的组件里, 这样不仅会让代码冗余, 而且不美观整洁. 如果你定义了一些外部 CSS 文件, 如何引入到 vue 组件中去呢? 我们这里使用 ES6 的引入方式:
- <template></template>
- <style scoped>
- @import "../assets/common/common.css";
- </style>
那么 JS 文件如何引入呢? 如果需要全局使用, 则可以在 main.JS 中引用并实例化对象:
部分 JS 代码:
- const DEBUG = true;
- let BASE_URL = DEBUG ? 'url' : '';
- const API = {
- // 网关设备管理
- 'edgeManager':{
- 'deviceList':BASE_URL + '/devicemanager/device/list.do',// 网关设备列表
- 'deviceDelete':BASE_URL + '/devicemanager/device/delete.do'// 网关设备删除
- }
- }
- export default API;
在 main.JS 中:
- import API from './assets/api/api.config.js'
- Vue.prototype.$API = API;
这样, 我们在 vue 组件中使用 this.$API 就可以找到这个 JS 文件中的对象了.
如: this.$API.edgeManager.deviceList
如果需要按需引入, 不在 main.JS 中引入, 直接在有需要的 vue 组件中引入:
部分代码:
- <template>
- </template>
- <script>
- import API from '../../assets/api/api.config.js'
- </script>
这样引入的话, 我们在当前组件可以直接使用 API 去找到这个 JS 文件中的对象.
如: API.edgeManager.deviceList
需要注意的是, 第二种方式按需引入的 JS 文件在其他组件中是找不到这个对象的.
在 vue.js 应用中, 可能需要引入 Lodash,Moment,Axios,Async 等非常好用的 JavaScript 库.
当项目变得复杂庞大, 通常会将代码进行模块化拆分. 可能还需要跑在不同的环境下, 比如浏览器, 服务端.
如何在各个模块和组件文件中引入需要的库呢? 找到一种简单靠谱的方式, 可以省去很多的麻烦.
---------------- 错误示范 ----------------
全局变量法
最不靠谱的方式就是将导入的库挂在全部变量 Windows 对象下:
entry.JS
Windows._ = require('lodash');
MyComponent.vue
- export default {
- created() {
- console.log(_.isEmpty() ? 'Lodash everywhere!' : 'Uh oh..');
- }
- }
这种方式的缺点有很多, 我们只说其中一个关键的点: 不支持服务端渲染. 当应用跑在服务端时, Windows 对象不存在, 当然试图去访问 Windows 下的属性会抛出错误.
处处引入法
另外一个不太优雅的方式就是在需要的每个文件中都引入对应的库:
MyComponent.vue
- import _ from 'lodash';
- export default {
- created() {
- console.log(_.isEmpty() ? 'Lodash is available here!' : 'Uh oh..');
- }
- }
虽然这方法是可行的, 但是太不简洁. 你必须在每个文件中都记得引入, 而且如果不需要了, 又得重新删除. 另外, 如果打包策略不够明智的话, 可能会打包出多份重复的代码.
----------- 正确引入方式 -----------
最简单靠谱的方式是用库变成 Vue 的原型对象的属性. 下面, 我来演示如何将 Moment 库引入:
entry.JS
- import moment from 'moment';
- Object.defineProperty(Vue.prototype, '$moment', {
- value: moment
- });
由于所有的组件都会继承 Vue 原型对象上的方法, 因此这些方法在任何组件文件中都能通过 this.$moment 访问到:
MyNewComponent.vue
- export default {
- created() {
- console.log('The time is' . this.$moment().format("HH:mm"));
- }
- }
我们来仔细看一下其中的原理.
Object.defineProperty
通常我们会如下设置对象属性:
Vue.prototype.$moment = moment;
你也可以这么做, 但是 Object.defineProperty 允许我们用属性描述器来定义我们的属性. 我们可以定义该属性是否可写, 可枚举, 可配置.
一般情况下, 我们不需要用那么复杂的方式来赋值属性. 但这里用它有个好处: 用属性描述器定义的属性是默认只读的.
这能防止那些脑子不清醒的开发者犯下一些低级错误:
- this.$http = 'Assign some random thing to the instance method';
- this.$http.get('/'); // TypeError: this.$http.get is not a function
Object.defineProperty 能保护引入的库不被重新赋值, 如果你尝试重写, 程序会抛出 "TypeError: Cannot assign to read only property" 的错误.
$
可能你注意到, 我们用 "$" 开头的属性来存放引入的库. 当然, 你应该记得还有其他的一些属性也是这样的, 比如 $refs, $on, $mount.
这种做法不是强制的, 这个前缀就是为了提醒某些昏昏沉沉的开发者, 这些属性是公有的, 你可以在任何地方使用. 反之, 某些属性只能在 Vue 内部使用.
作为一门以原型为基本的语言, JavaScript 中并没有真正的类, 所以也就没有所谓的公有, 私有变量, 或者静态方法. 上面这种约定, 我觉得是种不错的选择.
this
现在你能用 this.$libraryName 的方式来访问你需要的库了. 但, 你得保证 this 的指向. 如果你在回调函数中使用 this, 通常这个 this 不再指向 Vue 实例.
箭头函数是解决这个问题的好方法.
- this.$http.get('/').then(res => {
- if (res.status !== 200) {
- this.$http.get('/') // etc
- // Only works in a fat arrow callback.
- }
- });
二 如何创建自己的 Vue 插件
如果你在项目的很多地方都用了某个库, 或者你希望全局可用, 你可以构建自己的 Vue 插件.
插件能化繁为简, 能让你像下面这样很简单地引入自己想要的库:
- import MyLibraryPlugin from 'my-library-plugin';
- Vue.use(MyLibraryPlugin);
就像 Vue Route,Vuex 等插件一样, 我们的库仅仅需要两行, 就能在任何地方使用了.
如何写插件
首先, 创建一个文件. 本例中, 我将引入一个 Axios 库的插件. 我们就把这个文件命名为 axios.JS 吧.
最关键的地方在于, 我们需要暴露一个将 Vue 构造器作为第一个参数的 install 方法.
axios.JS
- export default {
- install: function(Vue) {
- // Do stuff
- }
- }
然后我们可以用之前的方式将库添加到 Vue 的原型对象上:
axios.JS
- import axios from 'axios';
- export default {
- install: function(Vue) {
- Object.defineProperty(Vue.prototype, '$http', { value: axios });
- }
- }
接着我们只需要 Vue 实例的 use 方法就能将这个库引入整个项目了. 我们像下面代码一样简单引入:
entry.JS
- import AxiosPlugin from './axios.js';
- Vue.use(AxiosPlugin);
- new Vue({
- created() {
- console.log(this.$http ? 'Axios works!' : 'Uh oh..');
- }
- })
插件参数设置
插件的 install 方法还可以接受其他的可选参数. 有些开发者可能不喜欢 Axios 实例对象的方法名 $http, 因为 Vue resource 插件的方法名也是这个. 然后, 让我们利用第二个参数来修改它.
axios.JS
- import axios from 'axios';
- export default {
- install: function(Vue, name = '$http') {
- Object.defineProperty(Vue.prototype, name, { value: axios });
- }
- }
entry.JS
- import AxiosPlugin from './axios.js';
- Vue.use(AxiosPlugin, '$axios');
- new Vue({
- created() {
- console.log(this.$axios ? 'Axios works!' : 'Uh oh..');
- }
- })
当然上面, 我们可以直接在 Object.defineProperty 的中将 name 属性写死成 $axios. 也可以在 install 方法中引入多个需要的库.
来源: https://www.cnblogs.com/both-eyes/p/10122164.html