常见的 模块化的规范
CommonJS AMD CMD 也有 ES6的 Modules
需要底层支撑
commonJS的导出:
module.exports = {
flag:true,
test(a,b){
return a+b
},
demo(a,b){
return a*b
}
}
commonJS的导入:
let {test,demo,flag} = require('moduleA');
//等同于
let _mA = require('moduleA');
let test = _mA.test;
let demo = _mA.demo;
let flag = _mA.flag;
export指令用于导出变量,比如下面的代码:
首先需要在页面引入 js 文件的时候 给一个 type
属性,值为 module
,本身script标签具备跨域请求,不受同源策略影响,但由于添加了type =module
请求方式改为了 file:// 文件请求,受到同源策略的影响
1.导出方式一:
// info.js
export let name = 'why'
export let age = 18
export let height = 1.88
上面的代码还有另一种写法:
2.导出方式二:
// info.js
let name = 'why'
let age = 18
let height = 1.88
export {name, age, height}
3.可以导出函数、类:
export function mul(num1,num2){
return num1 + num2
}
4.export default 注意!!! 只能一个导出为这个,否则import导入时候会产生错乱
var count = 88
export default count
import alger from "./main"
console.log(alger);
导入的三种方式:
// 导入 //对象 括号不能去
import {name, age, height} from '文件地址'
// 当导出为 export default
import 自己起的名字 from '文件地址'
// 以这种方式导入的时候 起的名字是alger ,因此这个模块中要想使用导入的数据需要添加 alger前缀
import * as alger from './main.js'
// 只有这个特殊一些,其他的直接可以拿到原来的变量,default 则是把导出的变量用自己起的名字代替了
// 这里导入的是'./main.js' 导出的所有变量 包括 default, 都包含着自己命名的这个对象中
从本质上来将,webpack是现代的javascript应用的静态模块打包工具
从 模块 打包来解释
webpack模块化打包工具,为了可以正常运行,必须依赖node环境,node环境为了可以正常的执行很多代码,必须其中包括各种依赖的包,npm工具(node packges manager)
安装webpack 首先需要安装Node.js,Node.js自带了软件包管理工具npm
查看自己的node 版本: node -v
全局安装webpack (这里我先指定版本3.6.0,因为vue cli2依赖该版本)
npm install webpack@3.6.0 -g
局部安装 webpack(后续才需要)
在通过vs code 运行webpack进行打包时,报错webpack : 无法加载文件 D:\nodejs\node_global\webpack.ps1,因为在此系统上禁止运行脚本。
解决方案:
以管理员身份运行vs code
执行:get-ExecutionPolicy,显示Restricted,表示状态是禁止的
执行:set-ExecutionPolicy RemoteSigned
这时再执行get-ExecutionPolicy,就显示RemoteSigned
此时发现再进行打包就没有问题了
webpack ./src/main.js ./dist/bundel.js
由于每次打包都要执行这样的代码 ,太过于麻烦,因此我们需要对webpack 进行一些配置
可以在项目根目录创建一个webpack.config.js文件,对webpack进行一些配置
const path = require('path')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundel.js'
},
}
1.官方推荐 output出口需要传个对象,对象中的属性 path,filename. 其中 path需要传一个绝对路径。
2.而我们并不希望这个路径被写死。 此需要用到 node中的 path模块, 当用到node模块时 可以先执行 npm init 初始化下,得到 package.json 文件。
3.然后导入node 的path模块
const path = require('path')
4.调用 path.resolve() 函数,该函数传递两个参数,会将两个参数进行拼接。 第一个参数传递 __dirname, 注意两个下划线,第二个参数传递当前文件目录 下的目标文件
5.然后直接执行 webpack 即可 按照 webpack.config.js 配置文件中的配置项 进行配置
1.原本我们已经通过 webpack.config.js 配置, 只需要运行webpack 就会自动进行 src 下的 main.js打包到 dist文件下的 bundel.js
2.package.js文件中"scripts"
对象下存储的都是 运行 npm run … 的快捷方式 。 我们如果在这个对象下 定义 "build": "webpack"
则运行npm run build
会自动运行 webpack, 也就是进行打包
注意!!!! package.json中的script的脚本在执行时,会按照一定的顺序寻找命令对应的位置
npm run build
也就是说在cmd中直接使用webpack命令 则一定会使用全局配置的webpack,然而使用脚本命令,则会优先使用局部配置的webpack,这也是配置脚本运行的一个原因
1.由于每个项目都有自己依赖的webpack版本,所以不是所有项目都可以运行全局的webpack进行打包,因此我们需要在本地也安装相应版本的webpack.
2.安装本地webpack 执行命令npm install [email protected] --save-dev
此时 package.js文件下的devDependencies
中就有了安装的webpack信息了。 【devDependencies 中 develop的缩写,翻译:开发,dependencies 翻译:依赖】
0.在引入css样式的入口文件中需要导入,css不需要变量接收,因此直接使用commenJS中的语法 ,require('./src/css/normal.css')
1.本身webpack没有办法对css类型的文件进行解析打包。
2.需要依赖其他的loader 来配置,官网上看了后发现需要用到 css-loader 因此需要 通过 npm来安装
3.执行命令 npm install --save-dev css-loader
安装完毕后再 package.json 文件中的开发依赖可以看到这个loader,
4.安装结束后,需要在webpack 配置文件中进行配置,打开webpack.config.js 之前我们配置了 入口,出口,现在需要配置module,如下:
module:{
rules:[{
test: /\.csss$/,
use: ['style-loader', 'css-loader']
}]
}
5.不难发现rules 是定义一些模块规则的, test是匹配这些文件,模块的,当匹配到的时候,则会依据use,执行里面相应的包。
6.注意此处的css-loader是用来解析css 文件的,你并不能将该css文件绑定到相应的DOM上,所以此时又需要使用 style-loader
7.因此我们需要安装 npm install --save-dev style-loader , 安装后依然是在use中配置,style-loader 应该是css文件解析结束后再调用,因此需要现在css-loader前面,因为 use中执行顺序是 从右到左
方法与配置css基本一致
安装: npm install --save-dev less-loader less
配置: 在 webpack.config.js 中进行配置
{
test: /\.less$/,
use: [{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "less-loader" // compiles Less to CSS
}]
}
一:配置 url-loader
安装依赖 npm install --save-dev url-loader
配置 webpack.config.js 环境
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [{
loader: 'url-loader',
options: {
limit: 8192
}
}]
}
一般 limit 限制大小 为 8k ,小于8k webpack会将其打包为 base64的图片,但是大于 8k的话 就不能这样处理了,进行打包的话会报错,提醒找不到 file-loader 整个模块,因此我们需要安装,file-loader
二:配置 file-loader
1.安装依赖 npm install --save-dev file-loader
2.不需要单独对file-loader 进行配置 ,配置的进行直接在url-loader中
3.此时再打包,默认大于 limit 的文件会直接调用 file-loader
4.默认情况下 是使用原来的扩展名,使用hash值作为文件名,直接打包在打包文件下。
5.此时我们需要在webpack.config.js的出口 配置上 publicPath:'dist/'
将输出解析文件的目录改为 dist ,url 相对于 HTML 页面
我们发现webpack自动帮助我们生成了一个非常长的名字
img/name.hash:8.ext
所以我们可以在options中添加上如下选项:
但是,我们发现图片并没有显示出来,这是因为图片使用的路径不正确
因此 最终我们只需要在 url-loader 配置的 limit下配置一个 name: 'img/[name].[hash:8].[ext]'
中括号说明是变量,hash:8说明截取hash前八位, .ext说明使用默认的扩展名
webpack打包的js文件,写的ES6语法并没有转化为ES5,那么就意味着可能一些ES6还不支持的浏览器没有办法很好的运行我们的代码
此时我们需要使用babel
webpack中,我们直接使用babel对应的loader就可以了
npm install --save-dev babel-loader@7 babel-core babel-preset-es2015
配置webpack.config.js文件
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
重新打包,查看bundle.js 文件,发现es6语法 改为了es5
1.安装 Vue 因为Vue不仅仅是开发时候我们需要使用,运行的时候也需要使用,因此npm安装的时候 不再是-dev
而是 npm install --save vue
2.在 main.js 中通过import Vue from 'vue'
进行导入 ,因为vue内部导出的方式是 export default vue , 因此可以这样导入,注意大小写
3.打包发现报错You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
4.出现的原因,Vue构建最终发布版本的时候,构建了两类版本
5.不难看出错误信息,简单翻译:你是用的是 runtime-only 进行构建Vue,template 不可以使用。
6.解决方式,进行webpack的配置
resolve:{
alias:{
// 此处是使用了 vue的 esm的一个版本,这个版本有template 语法
'vue$': 'vue/dist/vue.esm.js'
}
}
当同时 有 el属性和 template属性时候,则会将el位置的模板用 template模板进行替换
但是一个组件以js对象的形式进行组织和使用的时候是非常不方便的
现在我们以一种全新的方式来组织一个vue组件
但是这个时候这个文件被正确加载吗?
安装 vue-loader以及vue-template-compiler
**注意 ** vue版本,13版本以上还需要多加载其他loader,因此这里我们使用 vue-loader 的 13.0.0版本即可
修改webpack.config.js的配置文件:
{
test: /\.vue$/,
use: ['vue-loader']
}
如果想要省略导入时候的后缀名的话,需要在 配置文件webpack.config.js中的 resolve 中添加 extensions: ['.js','.css','.vue']
这样导入的时候就可以不加 扩展名了。 【extensions: 拓展,扩展】,但是注意同名文件产生意想不到的错误
loader 和 plugin 的区别
plugin的使用过程
步骤一: 通过npm安装需要使用的plugin(某些webpack已经内置的插件不需要安装)
步骤二: 在webpack.config.js 中的plugin中配置插件
本身是webpack自带的插件,因此只需要在 webpack.config.js中配置就可以了
module.exports = {
...
plugins:[
new webpack.BannerPlugin('最终版权归coderWyj所有')
]
}
由于此处new了 webpack ,因此这个页面需要导入webpack ,因此这个文件头部需要 const webpack = require('webpack')
目前我们的index.html文件是存放在项目的根目录下的
HtmlWebpackPlugin 插件可以为我们做什么事情
安装HtmlWebpackPlugin 插件
npm install html-webpack-plugin --save-dev
使用插件,修改webpack.config.js文件中 plugins部分 的内容如下:
1.安装插件
2.配置插件 const HtmlWebpackPlugin = require('html-webpack-plugin')
和 new HtmlWebpackPlugin()
3.**另外,我们需要删除之前在 output中添加的publicPath属性 ** 否则插入的script标签中的src可能会有问题
这时我们还有一个问题需要解决 因为index.html文件body下 需要一个
因此我们在webpack.config.js 中配置这个参数时候可以传入一个 template参数
new HtmlWebpackPlugin({
template: 'index.html'
})
此时 ,打包的时候,就会自动查找 这个index.html ,以这个文件模板进行编译至 dist文件夹
在项目发布之前,我们必然需要对js等文件进行压缩处理
这里我们就对打包的js文件进行压缩
我们使用一个第三方的插件uglifyjs-webpack-plugin,并且版本号指定1.1.1,和 CLI2 保持一致
npm install [email protected] --save-dev
修改webpack.config.js文件进行配置,使用插件:
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
new uglifyJsPlugin()
查看打包后的 bundel.js 文件,是已经被压缩过了的
webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js搭建,内部使用express框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果
npm install --save-dev webpack-dev-server@2.9.1
**注意:**此处由于webpack使用的是 3.6.0版本 ,对应了 CLI2 因此这里的webpack-dev-server 也需要对应版本,所以使用了 2.9.1
webpack.config.js 文件配置修改如下:
devServer: {
contentBase:'./dist'
inline: true
}
"dev": "webpack-dev-server --open"
因为有些配置文件是开发阶段需要使用的,还有一些时开发结束,最终打包时候需要使用的,因此需要对配置文件 webpack.config.js 进行抽离
1.创建 build目录存放 这些webpack的配置文件,
2.需要安装 npm install --save-dev webpack-merge
安装之后就可以在这三个配置文件中进行使用了,先进行抽离
// develop.config.js 开发时候需要的配置
const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')
module.exports = webpackMerge(baseConfig, {
devServer: {
contentBase: '/dist',
port: 3000,
inline: true
}
})
// product.config.js 生产发布时候需要的配置
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
const webpackMerge = require('webpack-merge')
const baseConfig = require('./base.config')
module.exports = webpackMerge(baseConfig, {
plugins: [
new UglifyjsWebpackPlugin()
]
})
注意,此处两个文件因为需要拼接base.config.js 因此都需要加载 webpackMerge的包,其次,由于都需要用到 base.config.js 因此需要先导入这个文件, 然后通过 webpackMerge(基础文件,需要拼接的内容)
3.由于webpack.config.js文件抽离了,原本package.json中的 scripts 配置需要更改,定义的 npm run 快捷中 build的快捷需要 指定 --config ./build/product.config.js
, dev 的快捷也需要添加 ` --config ./build/develop.config.js
4.base.config.js
中输出出口 为path: path.resolve(__dirname, './dist')
,此时会在当前文件夹下建dist文件存储输出的文件,我们需要更改下 path: path.resolve(__dirname, '../dist')
什么是Vue CLI
CLI是什么意思
npm insatll -g cnpm --registry=http://registry.npm.taobao.org
1.安装Vue 脚手架
2.注意:上面安装的是Vue CLI3的版本,如果想按照VueCLI2的方式初始化项目是不可以的
vueCLI3 和旧版使用了相同的vue命令,所以vue CLI2(vue-cli
)被覆盖了,如果你仍然想使用旧版本,可以全局安装一个桥接工具
npm install -g @vue/cli-init
// vue init 的影响效果将会跟 'vue-cli2'相同
3.初始化方式
CLI2 : 命令: vue init webpack my-project
CLI3 : 命令 : vue create my-project
4.初始化后进行的一些配置
npm install
for you after the project hasbeen created? (使用的哪种包管理工具)runtime-compiler( v1 ) 整个解析渲染过程:
runtime-only ( v2 ) 整个解析渲染过程:
因此可以看出 runtime-only 性能更高,代码量更少,了解区别后,开发尽量使用 runtime-only
其实 后一个版本是在前一个版本的基础上加上了 compiler ,然而在 vue2.0版本后 最终的渲染都是通过 render函数的,如果写template 属性的话,则会对template进行编译,这样其实是对性能的一种损耗。因此我们尽量去使用runtime-only
那么runtime-only 怎么使用,注意点是什么呢?
const APP = require('./src/components/App.vue')
new Vue ({
el:'#app',
render: h => h(App)
})
//此处的参数 h 其实就是 createElement 这个函数 ,这个函数有两种用法
//1. 传递三个参数 元素名字 属性名字(可选) 内容,其中数组内容中可以继续去嵌套createElement函数
new Vue ({
el:'#app',
render: createElement => createElement('h2',
{class: 'box'},
['Hello MOTO', createElement('button',['按钮'])])
})
//2.开发中常用 就是直接传一个vue 组件
new Vue ({
el:'#app',
render: h => h(App)
})
因此我们在实例中就不要再使用 template 定义模板了 ,直接使用render 函数去渲染
此时你可能会有疑惑,我们定义组件的时候 也就是 App.vue 文件中还是有 template 便签啊, 其实在我们将App导入进来的时候,导入的这个App对象 中是没有 template属性的,为什么没有呢???? 是因为我们之前是用来一个loader, 就是 vue-template-compiler
,它已经将我们的 .vue文件解析过了 ,因此其实已经没有template 了。
vue-cli3 与 2 版本区别
创建CLI3 : 命令 : vue create my-project
修改webpack一些配置的方式
内容概述:
location.hash = 'foo' //路由后面会添加上 /foo ,执行后未对服务端发送请求
history.back() // 后退一个路由/栈 等价于下面:
history.go(-1)
history.forward() //向前,前进一个路由/栈 等价于:
history.go(1)
两种方法都是往栈结构里压url,但是pushState 可以通过上面几种方法前进后退,浏览器有记录,replaceState 方法 不可以通过上面几种方法前进后退,,浏览器没有记录
因为我们已经学习了webpack,后续开发中我们主要是通过工程化的方式进行开发的
// 配置路由相关的信息
//1.导入路由
import Vue from 'vue'
import VueRouter from 'vue-router'
// 2.通过Vue.use()安装插件
Vue.use(VueRouter)
// 3.创建VueRouter对象
const routes = []
const router = new VueRouter({
// 配置路由和组件之间的路由关系
routes
})
// 4.将router对象传入到Vue实例中
export default router
使用vue-router的步骤
和
简单使用:
1.创建路由组件 home.vue about.vue
2.配置路由映射:组件和路径映射关系
router文件夹下index.js中配置
const routes = [{
path: '/home',
component: Home
},
{
path: '/about',
component: About
}
]
几个路由对应几个对象,几个关系
3.使用路由:通过
和
渲染
首页
这个作用是当点击首页,url改变
这个标签是个占位符,到时候对应的路由组件就会在这个占位里渲染我们这里还有一个不太好的实现:
渲染首页的内容如何可以让路径默认跳到首页,并且
渲染首页组件呢
const routes = [
{
path: '/',
redirect: '/home'
}
]
配置解析
const router = new VueRouter({
// 配置路由和组件之间的路由关系
routes,
mode: 'history',
})
在前面的 router-link
中,我们只是使用了一个属性:to, 用于指定跳转的路径
在 router-link
中还有一些其他属性:
router-link
之后渲染成什么组件,比如上面的代码被渲染称一个li元素,而不是arouter-link
对应的路由匹配成功时,会自动给当前元素设置一个 router-link-active 的 class ,设置active-class 可以修改默认的名称
前面我们使用的是router-link这个标签的 to来更改路由,如果不使用这个标签我们该怎么做呢?
问题,此处连续点同一个按钮,会报一个promise的错误,原因不明???????????
首先是普通的路由配置,创建路由对应的组件,将组件导入路由,进行映射,在出口用router-link,通过to属性去使用。
当使用动态路由则:
$router 拿到的是路由 router这个实例对象 ; $route 拿到的是 活跃状态组件的路由,也就是new VueRouter({routes}),中处于活跃状态的那个, $route下有一个属性 params ,对应的就是活跃状态路由的参数,里面有{ “userId”: “kenan” } 对象,这样就可以拿到
官方给出的解释
官方在说什么呢?
路由懒加载做了什么?
import Home from '../components/home'
import About from '../components/about'
import User from '../components/user'
const routes = [{
path: '/',
redirect: '/home'
}, {
path: '/home',
component: Home
},
{
path: '/about',
component: About
}, {
path: '/user/:userId',
component: User
}
]
const router = new VueRouter({
// 配置路由和组件之间的路由关系
routes,
mode: 'history',
linkActiveClass: 'active'
})
打包出来后,这三个组件的js代码都是在一起的
const routes = [{
path: '/',
redirect: '/home'
}, {
path: '/home',
component: () => import('../components/home')
},
{
path: '/about',
component: () => import('../components/about')
}, {
path: '/user/:userId',
component: () => import('../components/user')
}
]
const router = new VueRouter({
// 配置路由和组件之间的路由关系
routes,
mode: 'history',
linkActiveClass: 'active'
})
总结 : 就是将路由routes属性中的 component 通过 () => import('../components/home')
函数的方式绑定上,此时打包的时候就会按照组件个数分别打包成js代码块 。 当然 () => import('../components/home')
可以抽离出去。
嵌套路由是一个很常见的功能
实现嵌套路由有两个步骤:
标签1.创建自组件
2.配置映射,因为是路由的嵌套,因此先找到嵌套在哪个路由中
3.在相应的路由中添加属性 children 并传一个数组,数组内传多个 路由对象,其中路由对象的 path 属性直接 给一个不带 / 的 相对路径即可,vue内部会自动拼接
4.通过
在嵌套的组件中 通过to属性 绑定这个路径,在通过
将组件页面挂在上去
传递参数主要有两种类型;params 和 query
params的类型:
query 的类型:
1.以普通的方式创建路由,以及组件,在router-link to属性传值的时候,传递一个对象
2.对象中含有path属性,给与与路由映射相应的path, 然后传递第二个属性 query属性
3.该query属性是一个对象,对象中传递的键值对最后会被以 ?key=value&key1=value1的形式拼接到path属性后面
4.组件想要拿到数据可以通过,$route.query 拿到?后拼接的数据
每次路由变化,标题的title也进行相应的变化
keep-alive 是Vue内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染
router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配的视图组件都会被缓存
业务需求:我们想要首页每次跳转到关于,用户等界面后回到首页,能够记录当时首页选择的是新闻还是信息
1.首先要想每次切换回首页能够不重新创建首页组件进行渲染,那么首先需要将router-view 包裹在keep-alive
中,这样就能够每次切换路由,回来后不是重新创建,再渲染
2.此时这个router-view
中会渲染的组件都不会重新创建再渲染了,当我们选择信息后切换到关于界面,再返回,此时点击首页则会触发路由 /home, 由于路由中又有重定向,因此又会重定向回/home/news
。 这不是我们想要的。
3.那么我们去掉重定向呢??? 那么每次点击 首页 就会去请求/home
这个路由
4.我们一开始进入首页以及后续点击首页(多次点击) 就会反复请求/home
这个路由,当反复请求这个路由,我们还是需要让他指向 /home/news
的,因此不建议更改重定向
5.那么我们就需要在 home
组件中定义一个path去保存路径,每次离开home
这个组件的时候,要去拿到当时 this.$route.path
这个值 ,也就需要用到组件内路由守卫beforeRouteLeave
6.当我们从关于界面重新跳转到首页,那么就会触发activated()
这个函数,由于跳转回来首先是重定向到/home/news
,那么此时我们进行一个判断,如果保存的这个path
不等于 重定向的这个path
,那么我们就调用 this.$router.push(this.path)
更改路由
export default {
name: 'Home',
data() {
return {
path: '/home/news'
}
},
activated() {
if (this.$route.path !== this.path) {
this.$router.replace(this.path)
}
},
beforeRouteLeave(to, from, next) {
this.path = this.$route.path
next()
}
}
(视频老师思路)
1.如果在下方有一个单独的TabBar组件,你如何封装?
2.TabBar 中显示的内容由外界决定
3.自定义TabBarItem,可以传入 图片和文字
4.传入高亮图片
5.TabBarItem绑定路由数据
6.点击item跳转到对应的路由,并且动态决定 isActive
7.动态计算active样式
(个人思路)
分析这个tabbar界面,tabbar应该抽成一个组件,然后该组件注册为App.vue 的子组件,并且挂到这个组件上
由此开始,先封装tabbar组件
添加到页面中,此时我们又发现 TabBarItem中的icomoon和文本又写死了const routes = [{path:'/home',component:() => import('../views/home/Home)}]
mode:'history'
即可 ,然后只需要在需要挂在路由的App.vue页面 加入标签 router-view即可, 但是因为没有 router-link标签,因此没有办法监听路由变化,所以我们需要给每个TabBarItem,绑定点击事件,并且传入方法 使用 this. r o u t e r . p a s h ( ) 或 者 t h i s . router.pash( ) 或者 this. router.pash()或者this.router.replace( )方法进行路由跳转,传入的参数不应写死,应该通过父传子的方式拿到数据,因此通过props 定义 link, 在父组件页面每个 TabBarItem组件上绑定 link 属性,并且传递参数为该组件的路由,然后 点击事件传递一个方法,方法通过 props拿到的字符串 ,然后执行 this. r o u t e r . p a s h ( t h i s . l i n k ) 或 者 t h i s . router.pash( this.link) 或者 this. router.pash(this.link)或者this.router.replace( this.link) 注意:此处也许你会疑问 props拿到的到底是App.vue中的哪一个link呢,其实我们在App.vue使用了4次TabBarItem组件,因此每一次都有拿到,只是点击了哪一个就会执行相应的那个组件的方法,传入相应组件的linkisActive?{color:this.activeColor}:{}
CLI2中找到 build中 webpack.base.comfig.js
找到起别名resolve 中 的alias
, 然后只要是通过import导入的 都可以使用这个别名的绝对路径,如果是html中 src等属性使用的话 就需要在路径前面加上~
符号 表示 也是用这个别名
ES6中一个非常重要和好用的特性及时Promise
Promise到底是做什么的呢?
那什么时候我们会来处理异步事件呢?
但是非常复杂的时候,就会出现回调地狱
一般情况下是有异步操作时,使用Promise对这个异步操作进行封装
new => 构造函数(1.保存了一些状态信息 2. 执行传入的函数)
在执行传入的回调函数时,会传入两个参数,resolve,reject,本身又是函数
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('helloworld')
// reject('error Javascript')
}, 1000)
}).then((date) => {
console.log(date);
console.log(date);
console.log(date);
}).catch((error) => {
console.log(error);
console.log(error);
console.log(error);
})
// 另一种写法 then方法中传递成功和失败 两个回调
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('helloworld')
// reject('error Javascript')
}, 1000)
}).then(date => {
console.log(date);
console.log(date);
console.log(date);
},error => {
console.log(error);
console.log(error);
console.log(error);
})
首先,当我们开发中有异步操作时,就可以给异步操作包装一个Promise
我们一起来看看这三种状态
就是每次成功的回调后面返回一个新的 Promise实例对象,对新的异步操作进行处理,然后接着上一个then( )函数后面继续 .then( )函数处理新的成功或者失败操作,如果有很多个,一直循环往复即可
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hello111')
}, 1000)
}).then(data => {
console.log(data);
console.log(data);
console.log(data);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hello222')
}, 1000)
})
}).then(data => {
console.log(data);
console.log(data);
console.log(data);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('hello333')
}, 1000)
})
}).then(data => {
console.log(data);
console.log(data);
console.log(data);
})
当第一次异步操作拿到数据后,后续继续想通过promise对数据进行一些操作的话可以省略返回的 new Promise的写法,直接返回一个 Promise.resolve(),在括号内对数据进行一些操作, 当然也可以直接返回 括号内对数据的操作 继续省略 Promise.resolve()。 本身promise内部还是会对返回的 数据进行一层promise的封装
当然这种方式也可用在reject错误回调上, Promise.resolve()改为 Promise.reject() 即可,当然除了通过 reject()回调拿到错误,还可以通过 throw 抛出异常的方式,catch依然会拿到错误对象
// 第一种
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
}).then(data => {
console.log(data);
return new Promise((resolve, reject) => {
resolve(data + 'ooo')
})
}).then(data => {
console.log(data);
return new Promise((resolve, reject) => {
resolve(data + 'aaa')
})
}).then(data => {
console.log(data);
})
// 第二种
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
}).then(data => {
console.log(data);
return Promise.resolve(data + 'www')
}).then(data => {
console.log(data);
return Promise.resolve(data + 'kkk')
}).then(data => {
console.log(data);
})
// 第三种
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
}).then(data => {
console.log(data);
return data + 'www'
}).then(data => {
console.log(data);
return data + 'kkk'
}).then(data => {
console.log(data);
})
Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
name: '皮卡丘',
attribute: '电'
})
}, 2000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
name: '小火龙',
attribute: '火'
})
}, 1000)
})
]).then(result => {
console.log(result);
})
Promise.all( ) 方法可以对多个异步操作直接结束通过result拿到多次的异步resolve结果,结果以数组的形式保存在result中, 本身Promise.all( ) 传递一个数组,数组中传递Promise实例对象
同样的它传入的也是promise对象列表 不过他们执行顺序是按照谁快 谁先输出
const pro1 = new Promise((resolve,reject) => {
setTimeout(resolve,100,'1');
});
const pro2 = new Promise((resolve,reject) => {
setTimeout(resolve,200,'2');
});
const pro3 = new Promise((resolve,reject) => {
setTimeout(resolve,300,'3');
});
const pro4 = new Promise((resolve,reject) => {
setTimeout(resolve,10,'4');
});
Promise.race([pro4,pro1,pro2,pro3]).then(data => {
console.log(data); // 1 输出最快的那个
}).catch(err => {
console.log(err);
})