require.context()
require.context()
是一个webpack的api,主要作用是批量导入指定模块,解决了手动导入模块的繁琐。
用法:
通过执行require.context()
函数获取一个特定的上下文(特定文件夹)。然后获取当前的文件,实现导入。
语法:require.context(String:directory,Boolean:useSubdirectories,regExp:regexp)
参数:
directory:String,读取文件的路径
useSubdirectories:Boolean,是否遍历文件子目录。
regexp:Regexp,匹配文件的正则表达
分析:
什么时候需要使用require.context()
如果有以下情况,可以使用。
盗图:
当导入模块时:
模块文件:
基于Vue-cli的一个自定义UI插件的小demo
文件结构:
我的packages文件夹中有两个组件Button
和Icon
,我需要将他们导入到index.js
文件中然后注册给一个暴露了install方法的对象,之后就可以在 main.js
中使用Vue.use()
方法注册插件全局使用。
使用vue-cli3自定义插件并发布到npm参考我的文章:vue-cli3自定义插件并发布到npm
如果不使用require.context()
方法时,是这样做的。
index.js
import Button from './Button.vue'; //导入Button组件
import Icon from './Icon.vue';//导入Icon组件
let MsComponent = {};
MsComponent.install = function(Vue,options){
Vue.component('ms-button',Button); //全局注册Button组件
Vue.component('ms-icon',Icon); //全局注册Icon组件
}
export default MsComponent
可以看到手动import
每个需要的组件,然后分别调用Vue.component()
去进行全局注册。
这样如果我的组件很多的情况下,逐个导入与注册就会让代码变得非常长。一点都不优雅。
使用require,context()
let MsComponent = {};
MsComponent.install = function(Vue,options){
let components = require.context('./',true,/\.vue$/);//当前文件夹下以.vue结尾的所有文件
console.log(components); // components
components.keys().forEach((item)=>{
let componentConfig = components(item)
console.log(componentConfig) //componentConfig
Vue.component(componentConfig.default.name,componentConfig.default)
})
}
export default MsComponent
-
注释里面的输出 components 是一个方法
-
注释里面的输出 components.keys() 方法返回的是所有的组件路径list.
-
注释里面的输出 componentConfig 是一个对象里面包含了组件的信息。
比如default属性里面包含了组件的生命周期,name,render方法等。
源码 大概长这个样子:
var map = {
"./Button.vue": "./src/packages/Button.vue",
"./Icon.vue": "./src/packages/Icon.vue"
};
function webpackContext(req) {
var id = webpackContextResolve(req);
return __webpack_require__(id);
}
function webpackContextResolve(req) {
if(!__webpack_require__.o(map, req)) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
return map[req];
}
webpackContext.keys = function webpackContextKeys() {
return Object.keys(map);
};
webpackContext.resolve = webpackContextResolve;
module.exports = webpackContext;
webpackContext.id = "./src/packages sync recursive \\.vue$";
参考文章:使用require.context实现前端工程自动化
babel工作原理
Babel本质就是操作AST来完成代码转译;
三个阶段:
- Parse(解析):将源代码转换成更加抽象的表示方法(AST抽象语法树)
- Transform(转换):对AST(抽象语法树)做一些特殊处理,使其更符合编译器的期望
- Generate(代码生成):将第二步经过转换的AST(抽象语法树)生成新的代码
Babel 是一个被广泛使用的代码转码器,可以将 ES6 代码转为 ES5 代码,这意味着你可以现在就用 ES6 编写程序,而不用担心现有环境是否支持 ES6。Babel 的工作原理就是先将 ES6 源码转换为 AST,然后再将 ES6 语法的 AST 转换为 ES5 语法的 AST,最后利用 ES5 的 AST 生成 JavaScript 源代码。
网络请求Axios
Axios是一个支持node端和浏览器端,支持Promise,拥有丰富的配置项的网络请求工具。
安装:npm install axios
执行GET
请求
axios.get("/user?ID=123")
.then((response)=>{
//捕获请求成功
})
.catch((error)=>{
//捕获请求失败
})
GET
请求参数可以直接拼接在路径后面,也可以直接在第二个参数中传入一个对象,将参数放置在对象的params属性上
axios.get("/user",{
params:{
ID:123
}
})
.then((response)=>{
//捕获请求成功
})
.catch((error)=>{
//捕获请求失败
})
执行POST
请求
axios.post("/user",{
name:"mstian",
age:18
})
.then((response)=>{
//捕获请求成功
})
.catch((error)=>{
//捕获请求失败
})
POST
请求参数为第二个参数是一个对象。
执行多个并发请求:
function getUserAccount(){
return axios.get("/user")
}
function getUserPermission(){
return axios.get("/user/permission")
}
axios.all([getUserAccount(),getUserPermission()])
.then(axios.spread((acct,perms)=>{
//两个请求都成功
}))
Axios API
可以通过向axios
传递相关配置来创建请求
axios({
method:"post",
url:"/user',
data:{
name:"mstian",
age:18
}
});
axios默认为get请求
axios("/user")
//默认发送get请求
为了方便所有请求方法都有别名
axios.request(config)
axios.get(url[,config])
axios.post(url[,config])
axios.put(url[,config])
创建实例
可以使用自定义配置新建一个axios实例
axios.create([config]);
var instance = axios.create({
baseURL:"http://www.tianleilei.cn",
timeout:1000
})
请求拦截
instance.interceptors.request.use((config)=>{
//config请求体
//可以在这里做一些请求前的配置,比如动态增加header
config.headers.Authorization = "token"
return config
},(err)=>{
return Promise.reject(err)
})
响应拦截
instance.interceptors.response.use((response)=>{
//对响应数据加工处理
if(response.status>=200 && response.status<300 || response.status === 304){
return Promise.resolve(response.data)
}else{
return Promise.reject(response)
}
},(error)=>{
console.log(error)
})
响应结构
{
// `data` 由服务器提供的响应
data: {},
// `status` 来自服务器响应的 HTTP 状态码
status: 200,
// `statusText` 来自服务器响应的 HTTP 状态信息
statusText: 'OK',
// `headers` 服务器响应的头
headers: {},
// `config` 是为请求提供的配置信息
config: {}
}
全局axios默认值
axios.defaults.baseURL = "https://www.api.example.com"
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
网络请求封装参考
import axios from 'axios'
import Qs from 'qs'
import store from '@/store'
import router from '@/router'
import Vue from 'vue'
import { Loading, Message } from 'element-ui' // 引用element-ui的加载和消息提示组件
const $axios = axios.create({
// 设置超时时间
timeout: 30000,
// 基础url,会在请求url中自动添加前置链接
baseURL: process.env.VUE_APP_BASE_API
})
Vue.prototype.$http = axios // 并发请求
// 在全局请求和响应拦截器中添加请求状态
let loading = null
// 请求拦截器
$axios.interceptors.request.use(
config => {
loading = Loading.service({ text: '拼命加载中' })
const token = store.getters.token
if (token) {
config.headers.Authorization = token // 请求头部添加token
}
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截器
$axios.interceptors.response.use(
response => {
if (loading) {
loading.close()
}
const code = response.status
if ((code >= 200 && code < 300) || code === 304) {
return Promise.resolve(response.data)
} else {
return Promise.reject(response)
}
},
error => {
if (loading) {
loading.close()
}
console.log(error)
if (error.response) {
switch (error.response.status) {
case 401:
// 返回401 清除token信息并跳转到登陆页面
store.commit('DEL_TOKEN')
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath
}
})
break
case 404:
Message.error('网络请求不存在')
break
default:
Message.error(error.response.data.message)
}
} else {
// 请求超时或者网络有问题
if (error.message.includes('timeout')) {
Message.error('请求超时!请检查网络是否正常')
} else {
Message.error('请求失败,请检查网络是否已连接')
}
}
return Promise.reject(error)
}
)
// get,post请求方法
export default {
post(url, data) {
return $axios({
method: 'post',
url,
data: Qs.stringify(data),
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
}
})
},
get(url, params) {
return $axios({
method: 'get',
url,
params
})
}
}
node-glob模块
node-glob模块可以用来使用*等符号获取匹配对应规则的文件。
语法:glob(pattern,cb)
pattern表示匹配文件的规则
安装:npm i glob
使用:
const glob = require('glob');
glob("**/*.js",function(err,files){
console.log(files);
})
其中**/*
,表示当前目录下所有文件夹中的js文件,src/*.js
表示当前目录下src
目录下的所有js文件,file/a[0-3].js
表示当前目录下file目录下文件名为a0,a1,a2,a3的js文件。
files
是一个数组,表示所获取到的文件名。比如[ 'file/a0.js', 'file/a1.js', 'file/a3.js' ]
这种文件操作都是异步操作,glob提供同步方法:glob.sync(pattern)
let files = glob.sync("file/*.js")
console.log(files);
// [
'file/a0.js',
'file/a1.js',
'file/a3.js',
'file/a5.js',
'file/img.js',
'file/text.js'
]
实际应用,如果需要获取文件名进行操作,比如webpack多页面打包需要手动增加htmlWebpackPlugin插件配置时就可以使用glob模块优雅高效的处理。https://www.jianshu.com/p/cc8eee4a430c
未完待续。。。
写在最后:文中内容大多为自己平时从各种途径学习总结,文中参考文章大多收录在我的个人博客里,欢迎阅览http://www.tianleilei.cn