Vue.js 学习笔记
第一站
初使用
js 中
// let(定义变量) / const(定义常量) 创建变量的方式
const app = new Vue({
el:'#app', // 用来挂载要管理的元素
data:{ // 定义数据
message: '你好呀!',
name: 'hello 你好呀'
},
// 方法区,在HTML中可以调用此区域中的方法
methods: {
// 定义一个click方法
click: function() {
alert("你好")
}
},
// 计算属性
computed: {
upChar(message) {
message.up
}
}
// 在网页被创建前执行此区域方法
beforeCreate: function (){
console.log("beforeCreate");
},
// 在网页完成创建后执行此区域方法
created: function() {
console.log("created");
},
//
mounted: function() {
console.log("mounted");
},
})
HTML 中
<!-- app为模块名称与 vue 中使用的 el 挂载名一致 -->
<div id="app">
<!-- moustache语法:
使用: {}来引入data中的数据
moustache中可以使用简单的计算: + - * /
-->
<h2>{{message}}</h2>
<h1>{{name}}</h1>
</div>
<!-- 导入 vue 模块 -->
<script src="../js/vue.js"></script>
初级语法
v-on:
用来绑定事件- 语法糖写法: " @ "
- 例子:
- v-on:click=“click”
- @click=“click”
v-for="item in movies"
遍历数组moves中每一个数据, item 为每一个数据v-html="url"
以html方式展示v-text="message"
已文本方式展示v-pre
将标签中的内容原封不动地展示出来v-cloak
当vue代码执行后才会显示标签内容v-once
修改后内容不会改变,只会显示第一次得值v-bind
动态绑定- 语法糖写法: " : "
- 例子:
- v-bind:style=“color:blue”;
- :style=“color:blue”;
组件
-
创建组件(同样组件中也有自己的数据域,和vue实例一样该有的属性一样可以使用,但在组件中data属性必须为函数)
const cpn1 = Vue.extend({ template: ` <div> <h1>组件1</h1> </div> `, data() { return { message: "hello" } } })
-
注册组件
-
全局注册组件
// 组件名 组件实例 Vue.component('my-cpn', cpn1)
-
语法糖写法
Vue.component('my-cpn', { template: ` <div> <h1>组件1</h1> </div> ` })
-
局部注册组件
Vue({ el: "#app", components: { //组件名 组件实例 my-cpn: cpn1 }, data: { message: "你好" } })
-
-
使用组件(创建的组件必须在Vue管理的实例内)
<div id="app"> <!--可以多次使用--> <my-cpn></my-cpn> </div>
-
在组件中创建子组件
Vue.extend({ template: ` <div> <div>父组件</div> <cpn1></cpn1> </div> `, components: { cpn1: cpn1 } })
-
将模板从js中抽取出来放到html标签中
-
方法一:
<!--将模板写到script标签中,script类型必须是:text/x-template--> <script type="text/x-template" id="cpn"> <div>我是组件</div> </script>
-
方式二:
<template id="cpn"> <div>我是组件</div> </template>
-
-
注册组件
Vue.component("cpn", { template: "#cpn" })
第二站
父子组件间通信
-
向子组件中传递信息
<body> <div id="app"> <div>{{message}}</div> <!--子组件中接受信息的名称为hello, hello2,父组件中传递的数据信息名称为message,message2--> <!--如果没有使用v-bind(:)将会将字符串message和message2传给子组件,而非·父组件中的信息--> <cpn :hello="message" :hello2="message2" :child-message-info="info"/> </div> </body> <template id="cpn"> <!--vue2中模板里面必须包含一个根标签--> <div> <div>我是子组件</div> <div>父组件中的信息:</div> <div>{{hello}}</div> <div>{{hello2}}</div> <div>{{childMessageInfo}}</div> </div> </template> <script> cpn = { template: "#cpn", // 用来存放父组件中传递的信息 // 方式一: props: ['hello', 'hello2'] // 方式二:(此时限制了传到子组件中的信息类型,这里为string类型) props: { hello: string, hello2: string } // 方式三:(此时不仅限制了类型,还会有默认值,当父组件没有传来信息时,将会使用默认值) props: { hello: { type: string, default: "我是默认值", // 表示必须要传递信息 required: true }, hello2: { type: Array, // 当默认值为:[]时将会报错 // default: [] // 类型是对象或者数组时,默认值必须是一个函数 default() { return [] } } // 当子信息接收变量为驼峰标识变量时,须在别的使用地方添加“-”来表示 childMessageInfo: { type: Object, default() { return {} } } } } new Vue({ el: "#app", components: { cpn }, data: { message: "你好,我是父组件", message2: "你好我是第二条信息", info: { name: "张三", age: 18 } } }) </script>
-
向父组件中传递信息
<body> <div id="app"> <!--将子组件发射事件的名称绑定监听函数,此处绑定的为childClick事件--> <!--vue2中不能解析驼峰式写法,但在vue脚手架中可以解析--> <cpn @item-click="childClick"></cpn> </div> </body> <template id="cpn"> <div> <h1>我是子组件</h1> <!--当按钮被点击时,触发函数进行发送事件--> <button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button> </div> </template> <script> const cpn = { template: "#cpn", data() { return { categories: [ {id: '01', name: '手机数码'}, {id: '02', name: '家用电器'}, {id: '03', name: '服装装饰'}, {id: '04', name: '实用小件'} ] } }, methods: { btnClick(item) { // 发射事件(自定义事件),发射事件的名称为第一个参数,第二个参数为发送的内容 this.$emit('item-click', item) } } } new Vue({ el: "#app", components: { cpn }, date: { message: "父子组件通信之子传父" }, methods: { // 该处默认接收的变量为子组件发送来的变量 childClick(item) { console.log("已接收", item) } } }) </script>
watch
-
watch 用来监听属性的改变
<body> <div id="app"> <div>{{message}}</div> </div> </body> <script src="vue/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { message: "hello world" }, watch: { // 此处watch函数名必须为 data 中的数据名,其中newVal和oldVal分别为新值和旧值 message(newVal, oldVal) { console.log(newVla, oldVal) } } }) </script>
父子组件的访问方式
父组件访问子组件:
c h i l d r e n : t h i s . children:this. children:this.children是一个数组类型,它包含所有子组件对象
$refs
子组件访问父组件:
$parent
-
父组件调用子组件中的方法
<body> <div id="app"> <!--通过ref属性来在组件中使用该子组件--> <cpn ref="cpn1"></cpn> <cpn ref="cpn2"></cpn> <button @click="btnClick">调用自组件方法</button> </div> </body> <template id="cpn"> <div>子组件</div> </template> <script> const cpn = Vue.component("cpn", { template: "#cpn", data() { return { message: "我是子组件中的信息" } }, methods: { showMSG() { alert("调用成功!") } } }) new Vue({ el: "#app", components: { cpn }, data: { message: "hello world" }, methods: { btnClick() { // 一般不使用$children属性,使用$refs来替代 this.$children[0].showMSG() alert(this.$children[0].message) // 推荐使用此方法 this.$refs.cpn1.showMSG() console.log(this.$refs.cpn2.message) } } }) </script>
-
子组件调用父组件中方法
<body> <div id="app"> <cpn></cpn> </div> <template id="cpn"> <div> <div>我是子组件</div> <button @click="btnClick">调用父组件中方法</button> </div> </template> </body> <script> const cpn = Vue.component("cpn", { template: "#cpn", methods: { btnClick() { // 使用$parent属性进行访问父组件,但此方法不建议使用(由于耦合度较高,父组件可能有多个) this.$parent.showMSG() console.log(this.$parent.message); // 访问根组件使用$root,在此示例中$parent和$root一样 console.log(this.$root.message) } } }) new Vue({ el: "#app", components: { cpn }, data: { message: "你好,我是父组件" }, methods: { showMSG() { alert("访问成功!") } } }) </script>
插槽
在结构相似的功能组件中使用插槽能带来很大的便利
-
定义插槽
<body> <div id="app"> <cpn><button>通过插槽引入button按钮</button></cpn> <cpn><a>通过插槽来添加a标签</a></cpn> <cpn></cpn> </div> <template id="cpn"> <div> <div>子组件</div> <!--当组件中含有多个插槽时,在使用时都为以名子使用,则组件中插槽都将会被替换为组件中的内容--> <slot></slot> <!--此插槽含有默认值,当引入此插槽时,未在组件中添加任何元素,则使用默认添加到元素,如果有元素,则默认元素将会被替换为指定元素--> <slot><button></button></slot> </div> </template> </body> <script> const cpn = { template: "#cpn" } new Vue({ el: "#app", components: { cpn } }) </script>
-
具名插槽
<body> <div id="app"> <!--在替换时使用slot属性来替换具体名字的插槽,其插槽的作用域只在某个模板下起作用,此处input将不会显示,由于isShow在vue实例中为false故不会显示--> <cpn><input v-show="isShow" slot="center"/></cpn> </div> <template id="cpn"> <div> <!--在使用有名字的插槽时,必须选定要替换插槽的名字--> <slot name="left"><span>左边</span></slot> <slot name="center"><span>中间</span></slot> <slot name="right"><span>右边</span></slot> </div> </template> </body> <script> const cpn = { template: "#cpn", data() { return: { isShow: true } } } new Vue({ el: "#app", components: { cpn }, data: { isShow: false } }) </script>
-
在父组件中引用子组件中的数据
<body> <div id="app"> <cpn></cpn> <cpn> <!-- 在2.5.x以前必须使用template模板,在2.5.x以后取消了这种约束,在模板中引用数据 --> <template slot-scope="slot"> <span v-for="item in slot.data">{{item}} --- </span> </template> </cpn> <cpn> <!-- 其中slot-scope为固定写法,后面的值为引用的子组件 --> <div slot-scope="sl"> <!-- 从子组件中的data域取值 --> <a href="#" v-for="item in sl.data"> --{{item}}-- </a> </div> </cpn> <cpn2></cpn2> <cpn2> <div slot-scope="s"> <!--join函数将数组中间使用 - 来进行分割--> <!-- 由于子组件中使用了message来存放变量故,在引用时也必须使用message --> <i>{{s.message.join(' - ')}}</i> </div> </cpn2> </div> <template id="cpn"> <div> <div>我是子组件</div> <!--data可以为自己取的名字,可以将data改为别的变量名称,在引用时也必须用别的变量名--> <slot :data="arr"> <ul> <li v-for="item in arr">{{item}}</li> </ul> </slot> </div> </template> <template id="cpn2"> <div> <div>我是子组件2</div> <slot :message="arr"> <ul> <li v-for="item in arr">{{item}}</li> </ul> </slot> </div> </template> </body> <script> new Vue({ el: "#app", components: { cpn: { template: "#cpn", data() { return { arr: ['java', 'c', 'c++', 'php'] } } }, cpn2: { template: "#cpn2", data() { return { arr: ['西红柿', '番茄', '南瓜', '冬瓜'] } } } } }) </script>
在 vue-cli3 及以上版本需使用以下方法进行插槽的使用
<!-- 这里使用 v-slot: 的形式来指定具名插槽 -->
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
生命周期
模块化开发
-
commonjs语法
-
a.js
let name = "小明" let age = 18 let sayHello = function () { console.log("hello:" + name) } modlue.export = { name, age, sayHello }
-
b.js
let name = "小红" let age = 19 let sayHello = () => { console.log("hello:" + name) } modlue.exports = { name, age, sayHello }
-
main.js
let {name, age, sayHello} = require("./a.js")
-
在主页面中使用
<!--在引入时加入type属性将不会发生命名冲突的问题--> <script src="main.js" type="module"></script> <script src="a.js" type="module"></script> <script src="b.js" type="module"></script>
-
-
ES6语法
-
a.js
let name = "小明" let age = 18 let sayHello = (msg) => { console.log("hello, " + msg) } // 导出方式一: export { name, age, sayHello } // 导出方式二:(定义变量时,直接导出) export let num = 1 // 导出函数 export function sum(num1, num2) { return num1 + num2 } // 导出类 // ES5语法 export function Person() { let name let age } // ES6语法 export class Person{ let name let age } // (以上这些导出方式导出时为什么的名字,在别的文件中导入也只能用导出时的名字) // 通过export default 在导出时可以不命名,在一个文件中只能有一个export default。在导入时,可以重命名 export default Perosn
-
b.js
import {name, age, sayHello} from './a.js' // 此时导入了导出文件的默认导出数据,可以在导入时重命名 import presonA from './a.js' // 此时导入为存放到一个obj的对象中,访问时可以使用”obj.“的形式 import * as obj from './a,js' console.log(obj.name) (() => { console.log(name + "同学的年龄为:" + age) })() sayHello(name + "、小名:")
-
webpack进行打包
初使用
在打包时使用指令
webpack ./src/main.js -o ./dist/
webpack 在4.0以上要使用 -o 选项来进行指定输出地址,在之前版本不需要 -o 选项。并且不需要指定输出文件的名字,如果指定则会以文件夹的形式显示,会默认生成一个 main.js 的文件
在打包时,只需指定入口文件即可,别的 js 文件则不需进行打包
webpack配置
webpack的配置文件名称固定为 webpack.config.js
在配置的时候需要引入node的相关包来动态获取路径需要在终端执行 npm init
指令,生成一个 package.json 文件
-
webpack.config.js
// 通过引入node的模块获取绝对路径 const path = require('path') module.exports = { // 导入的入口 entry: './src/main.js', // 导出的出口 output: { // 要求path必须为绝对路径,path的resolve函数可以动态获取路径 // __dirname为node的全局变量,join函数可以用来拼接两个路径,此处为该文件所处的绝对路径和 'dist' 路径进行拼接 // 在webpack4.0以前使用resolve函数进行拼接路径 path: path.join(__dirname, 'dist'), filename: "bundle.js" } }
-
package.json
在json文件中不允许有注释代码片段
{ "name": "meet", "version": "1.0.0", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", // 在此处构建了一个映射,此时只需执行build指令即可执行打包(在终端执行 npm run build) // 此处定义了一个指令(build)该指令执行时,将会优先在本地进行查找本地不存在则会取去全局找 // 在命令窗口敲的指令都会去全局找 "build": "webpack" }, "author": "", "license": "ISC", "description": "" }
- 此时只需在终端敲
webpack
或npm run build
命令,即可实现自动打包
- 此时只需在终端敲
-
开发时依赖:
npm install webpack@3.6.0 --save-dev
-
运行时依赖:
npm install vue --save
-
自动生成的 package.json 文件
-
package.json
{ "name": "meet", "version": "1.0.0", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "build": "webpack --mode development", // 配置webpack服务启动指令,参数:--open设置自启动 "server": "webpack-dev-serve --open" }, "author": "", "license": "ISC", "description": "", // 开发时依赖,通过--save-dev指令下载的包将会保存于此 "devDependencies": { "webpack": "^3.6.0" }, // 运行时依赖 "dependencies": { } }
-
webpack loader
-
使用 npm install 包名 --save-dev 来下载对应的loader,然后再webpack.config.js中添加相应配置
-
再main.js中依赖相关的 css 文件或别的 js 文件即可,只需要打包完成后引入打包后的js文件即可,而不需要在index.html中引入css或别的js文件
-
webpack.config.js
// 通过引入node的模块获取绝对路径 const path = require('path') module.exports = { // 导入的入口 entry: './src/main.js', // 导出的出口 output: { // 要求path必须为绝对路径,path的resolve函数可以动态获取路径 // __dirname为node的全局变量,resolve函数可以用来拼接两个路径,此处为该文件所处的绝对路径和 'dist' 路径进行拼接 path: path.join(__dirname, 'dist'), filename: "bundle.js" }, module: { rules: [{ // 使用正则表达式进行匹配,匹配到符合条件的将会使用下列两个loader test: /\.css$/, // css-loader 只负责加载 // style-loader 负责将样式添加到 DOM 中 // 使用多个 loader 时,从右向左加载 use: ['style-loader', 'css-loader'] }, { test: /\.less$/i, use: [ // compiles Less to CSS "style-loader", "css-loader", "less-loader", ], }] } }
webpack.config.js 详细配置
由于直接引入vue的时候可能会报错:提示你正在使用的时 runtime-only 此模板不能编译template,您应该使用 compiler-included。解决此问题,需在webpack.config.js中配置vue信息
// 通过引入node的模块获取绝对路径
const path = require('path')
// 导入webpack的包,后续可以引入webpack的插件
const webpack = require("webpack")
// 导入自动生成index.html插件
const HtmlWebPackPlugin = require('html-webpack-plugin')
// 导入自动丑化js代码插件
const uglifyJsPlugin = require("uglifyjs-webpack-plugin")
module.exports = {
// 导入的入口
entry: './src/main.js',
// 导出的出口
output: {
// 要求path必须为绝对路径,path的resolve函数可以动态获取路径
// __dirname为node的全局变量,resolve函数可以用来拼接两个路径,此处为该文件所处的绝对路径和 'dist' 路径进行拼接
path: path.join(__dirname, 'dist'),
filename: "bundle.js",
// 当文件打包后通过css或别的文件引入的文件将会存在路径错误,此时需要配置一个公共地址,在别的文件加载时,会自动拼接公共地址
publicPath: "dist/"
},
module: {
rules: [{
// 使用正则表达式进行匹配,匹配到符合条件的将会使用下列两个loader
test: /\.css$/,
// css-loader 只负责加载
// style-loader 负责将样式添加到 DOM 中
// 使用多个 loader 时,从右向左加载
use: ['style-loader', 'css-loader']
}, {
test: /\.less$/i,
use: [
// compiles Less to CSS
"style-loader",
"css-loader",
"less-loader",
],
}, {
test: /\.(png|jpg|gif|jpeg|webp)$/i,
use: [{
loader: 'url-loader',
// 限制由url引入的文件的大小,此处单位为字节,此处大小为8kb
options: {
// 当加载的图片小于limit时,会将图片编译成base64字符串形式
limit: 1000,
// 该处为打包后的文件设置文件命名方式 "[]" 表示变量的意思,此处为打包后的文件存放到img文件夹下,名字为原来文件的名称.8为hash值.扩展名
name: 'img/[name].[hash:8].[ext]'
}
}],
}, {
test: /\.(png|jpe?g|gif|webp)$/i,
use: [{
loader: 'file-loader'
}],
}, {
// 此loader为将es6转化为es5的loader
test: /\.m?js$/,
// exclude排除,以下文件将不会被使用此loader
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},{
test: /\.vue$/,
use: ['vue-loader']
}]
},
resolve: {
// 使用此配置能省去文件的扩展名
extensions: ['.js', '.vue', '.css'],
// alias:别名,此时引入vue的时候将会在指定的文件夹下寻找vue,添加此配置时,将会解决template不能被加载的问题
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
plugins: [
// 此插件能在每个打包后文件中添加版权说明
new webpack.BannerPlugin("最终版权归小明所有"),
// 此插件将会在打包后自动生成index.html文件,此时将不需要再配置publicPath路径
new HtmlWebPackPlugin({
// 根据index.html模板生成index.html文件
template: "index.html"
}),
// 使用丑化插件,在打包后将自动丑化js代码,以进行压缩js文件
new uglifyJsPlugin()
],
// 该配置只在开发时需要,发布时可以删除
devServer: {
// 指定服务的文件夹
contentBase: "./dist",
// 指定是否要实时监听
inline: true,
// 指定服务器端口,默认为8080端口
port: 8080
}
}
-
当vue实例中既有el属性又有template属性时,template将会替换掉el所挂载的所有东西
-
App.vue
<template> <h1>{{message}}</h1> </template> <script> export default { name: "App", data() { return { message: "hello world" } } } </script> <style scoped> body { background-color: green; } </style>
-
main.js
// 引入vue模块 import Vue from 'vue' // 导入组件 import App from './vue/App' new Vue({ el: "#app", // 此时template模板将会替换el所挂载的内容 template: "<App/>", components: { // 组件挂载 App } })
-
webpack.config.js文件的分离
-
base.config.js基本配置
// 通过引入node的模块获取绝对路径 const path = require('path') // 导入webpack的包,后续可以引入webpack的插件 const webpack = require("webpack") // 导入自动生成index.html插件 const HtmlWebPackPlugin = require('html-webpack-plugin') module.exports = { // 导入的入口 entry: './src/main.js', // 导出的出口 output: { // 要求path必须为绝对路径,path的resolve函数可以动态获取路径 // __dirname为node的全局变量,resolve函数可以用来拼接两个路径,此处为该文件所处的绝对路径和 'dist' 路径进行拼接 // 当webpack配置文件分离后需要修改打包路径在第二个参数前添加 ../ // path: path.join(__dirname, 'dist'), path: path.join(__dirname, '../dist'), filename: "bundle.js", // 当文件打包后通过css或别的文件引入的文件将会存在路径错误,此时需要配置一个公共地址,在别的文件加载时,会自动拼接公共地址 publicPath: "dist/" }, module: { rules: [{ // 使用正则表达式进行匹配,匹配到符合条件的将会使用下列两个loader test: /\.css$/, // css-loader 只负责加载 // style-loader 负责将样式添加到 DOM 中 // 使用多个 loader 时,从右向左加载 use: ['style-loader', 'css-loader'] }, { test: /\.less$/i, use: [ // compiles Less to CSS "style-loader", "css-loader", "less-loader", ], }, { test: /\.(png|jpg|gif|jpeg|webp)$/i, use: [{ loader: 'url-loader', // 限制由url引入的文件的大小,此处单位为字节,此处大小为8kb options: { // 当加载的图片小于limit时,会将图片编译成base64字符串形式 limit: 1000, // 该处为打包后的文件设置文件命名方式 "[]" 表示变量的意思,此处为打包后的文件存放到img文件夹下,名字为原来文件的名称.8为hash值.扩展名 name: 'img/[name].[hash:8].[ext]' } }], }, { test: /\.(png|jpe?g|gif|webp)$/i, use: [{ loader: 'file-loader' }], }, { // 此loader为将es6转化为es5的loader test: /\.m?js$/, // exclude排除,以下文件将不会被使用此loader exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } },{ test: /\.vue$/, use: ['vue-loader'] }] }, resolve: { // 使用此配置能省去文件的扩展名 extensions: ['.js', '.vue', '.css'], // alias:别名 alias: { 'vue$': 'vue/dist/vue.esm.js' } }, plugins: [ // 此插件能在每个文件中添加版权说明 new webpack.BannerPlugin("最终版权归小明所有"), // 此插件将会在打包后自动生成index.html文件 new HtmlWebPackPlugin({ // 根据index.html模板生成index.html文件 template: "index.html" }) ] }
-
dev.config.js开发时依赖配置
const webpackMerge = require("webpack-merge") const baseConfig = require("./base.config") module.exports = new webpackMerge(baseConfig, { devServer: { // 指定服务的文件夹 contentBase: "./dist", // 指定是否要实时监听 inline: true, // 指定服务器端口,默认为8080端口 port: 8080 } })
-
pro.config.js项目发布时依赖
const webpackMerge = require("webpack-merge") // 导入自动丑化js代码插件 const uglifyJsPlugin = require("uglifyjs-webpack-plugin") const baseConfig = require("./base.config") module.exports = (baseConfig, { plugins: [ // 使用丑化插件,在打包后将自动丑化js代码,以进行压缩js文件 new uglifyJsPlugin() ] })
-
此时需要在package.json文件中添加webpack.config.js文件的路径,否则报错找不到webpack的配置文件
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", // --config 指定路径 "build": "webpack --mode development --config ./build/pro.config.js", "dev": "webpack-dev-serve --config ./build/dev.config.js" }
-
第三站
vue-cli
如果使用 vue - cli 2 的版本时,使用命令:vue init webpack 项目名
创建
vue - cli 高版本创建命令:vue create 项目名
创建
render函数
vue执行原理:
runtime - complier 执行原理:
tempalte --> ast(abstract tree) --> render --> virtual dom --> UI
runtime - only 执行原理:
render --> virtual dom --> UI
// 使用render函数创建对象
render: function (createELement) {
retun createELement('div',
{class: 'box'},
['我是由render函数渲染出来的标签', createELement('button', {id: 'btn'}, ['按钮'])])
}
// 使用render函数传入组件对象
const cpn = {
template: '<div>{{message}}</div>',
data() {
return {
message: "我是组件"
}
}
}
render: function (createELement) {
retun createELement(cpn)
}
在vue3中,配置文件默认隐藏了,如果想要引入自己的配置,则需要创建:vue.config.js
文件,该文件名固定
vue.config.js
module.export = {
...
}
Vue - Router
前奏:
通过一些方式改变 url 但页面不发生刷新
使用 location.hash = ‘a’; 可以将地址栏后面加 a 即原始为 www.baidu.com 则可以转变为:www.baidu.com/a
使用 history.pushState({}, ‘’, ‘a’) 能达到和 hash 一样的效果,通过此方法是将新加的连接放入到堆栈中,之后在使用 history.back() 函数,则会一层一层返回
- 参数:
- data
- title
- url
history.replaceState({}, ‘’, ‘b’) 通过此方式则原来的url将会被覆盖不能通过 back() 函数返回到上一个页面
history.back() 回到上一个页面
history.go()
- history.go(-1) 和 history.back() 等价
- history.go(-2) 将会使栈中弹出两个地址,即返回两次
- history.forword() 等价于 history.go(1)
- history.go(2) 将会压进栈中两个,即前进两次地址
vue-router 配置
在 src 目录下创建 router 文件夹,在该文件夹中创建 index.js 文件,在该文件中配置路由相关信息
router – > index.js(vue3及以下使用方式)
// 导入vue在后续中用于注册组件
import Vue from 'vue'
// 导入路由,用于配置路由相关信息
import VueRouter from 'vue-router'
// 安装插件
Vue.use(VueRouter)
// 导入组件
import App from '../App.vue'
import About from '../components/About'
import Profile from '../components/Profile.vue'
// 配置路径相关变量
const routes = [
{
path: '',
// 使用重定向,使页面刚开始时即定位到 /home 路径
redirect: '/home'
},{
path: '/about',
component: About
},{
// 通过 /:userId 来动态拼接 url 路径,在 Profile 组件中可以使用:this.$route.params.userId 获取传入的 userId 信息
path: '/profile/:userId',
component: Profile
}]
// 创建路由对象
const router = new VueRouter({
routes,
// 改变路径的默认模式,默认模式为hash(该模式会使路径中含有 # ),此处改边为 history 模式
mode: 'history',
// 更改为点击后的 router-link 渲染之后的标签的 class 名字
linkActiveClass: 'active'
})
// 导出router
export default router
router – > index.js(vue3以上使用方式)
// 导入路由相关对象
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
import Home from '../views/Home.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
在 App.vue 中需指引到该页面的方式
<template>
<div id="app">
<!-- router-link 和 router-view 标签为router自动注册的组件,直接使用即可 -->
<!-- 使用 router-link 标签,该标签在渲染后将会默认变为 a 标签 -->
<router-link to="/about">关于</router-link>
<!-- 使用 tag 属性将渲染之后的结果变为 button 标签,replace 属性使改变路径时使用的是替换而不是压栈,即不能返回 -->
<!-- 当点击某个router-link渲染之后的标签后,vue 会自动给改变前添加两个 class 类(router-link-active 和 router-link-exact-active),可以通过该类名用于设置点击之后的样式,使用 active-class属性可以更改该标签被点击后的 class 属性,此处更改为 active ,可以在 router 配置文件中统一进行更改-->
<router-link to="/profile" tag="button" replace active-class="active">我的</router-link>
<!-- 通过方法进行更改页面的 url 进行页面跳转 -->
<button @click="aboutClick">关于</button>
<button @click="profileClick">我的</button>
<!-- 动态拼接路径,在将要跳转后面加上动态的路径拼接信息 -->
<router-link to="/profile/xiaoming">我的</router-link>
<!-- 动态拼接路径,在将要跳转后面加上动态的路径拼接信息。此处为在 data 中寻找userId变量 -->
<router-link :to="'/profile/' + userId">我的</router-link>
<!-- router-view 组件将会使 router-link 标签中的指向渲染到此处,即替换router-view标签 -->
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
userId: 'xiaoming'
}
}
methods: {
// 监听事件的点击
aboutClick() {
// router 为每个组件都注入了一个 $router 属性,该属性可以进行页面的跳转
this.$router.push('/about')
},
profileClick() {
// 通过replace方式进行页面跳转,该方法跳转页面将不能进行返回
this.$router.replace('/profile')
},
}
}
</script>
在子组件中获取用户拼接的 url 路径可以通过过 this.$route.params.userId(userId为设置在路由中的动态变量)来获取 此时 $route 表示处于活跃的路由对象
通过路由的懒加载机制进行划分 js 文件,这样用户在初次访问时,将不会出现短暂的空白无响应状态,一个懒加载将会对应打包后的一个 js 文件
路由的懒加载三种方式
- 方法一(结合 vue 的异步组件和 webpack的代码分析)不推荐:
const routes = [
{
path: '/',
component: Home = resolve => {require.ensure(['../components/Home.vue'], () => {resolve(require('../components/'))} )}
}
]
- 方法二(AMD 写法):
const routes = [
{
path: '/',
component: Home = resolve => require(['../components/Home.vue'], resolve}
}
]
- 方式三(ES6)推荐:
const routes = [
{
path: '/',
component: Home = () => import ('../components/Home.vue')
}
]
// 更优做法
const Home = () => import ('../components/Home.vue')
const routes = [
{
path: '/',
component: Home
}
]
- 组件进行进一步细分,进行配置子路由
const Home = () => import('../components/Home.vue')
const News = () => import('../components/News.vue')
const Fun = () => import('../components/Fun.vue')
const routes = [
{
path: '/',
component: Home,
// 通过 children 属性来决定组件中子组件路由相关信息,子路由不需要加 ‘ / ’
children: [
{
path: 'news',
component: News
},{
path: 'fun',
component: Fun
}
]
}
]
- 在父组件中,和配置普通路由一样进行添加 router-link 和 router-view 标签设置子组件的显示位置及何时显示
<template>
<div id="app">
<!-- 在此处要添加父组件的路径 -->
<router-link :to="'/home/news">新闻</router-link>
<router-view/>
</div>
</template>
- 通过另一种方式进行界面的跳转以及参数的传递
<template>
<div id="app">
<router-link :to="{path: '/profile', query: {name: 'xiaoming', age: 18}}">新闻</router-link>
<router-view/>
<!-- 通过 query 来获取当前传的参数对象 -->
<div>{{$router.query}}</div>
</template>
- 通过普通标签进行设置跳转及参数传递
<template>
<div id="app">
<button @click="aboutClick">关于</button>
<button @click="profileClick">我的11</button>
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
userId: 'xiaoming'
}
}
methods: {
// 监听事件的点击
aboutClick() {
// router 为每个组件都注入了一个 $router 属性,该属性可以进行页面的跳转
this.$router.push('/about')
},
profileClick() {
// 通过replace方式进行页面跳转,该方法跳转页面将不能进行返回
this.$router.push({
path: '/profile',
query: {
name: 'xiaoming',
age: 18
}
})
},
}
}
</script>
router 和 route不为同一个,route 代表当前活跃的那个路由对象,而 router 代表整个路由对象
扩展:
-
为一个对象添加一个属性:
const obj = { name: 'xiaoming' } // 通过 Object.defineProperty() 方法为对象进行添加属性(该方法为响应式) // 参数一为要添加属性的对象,参数二为添加的属性名,参数三为属性值 Object.defineProperty(obj, 'age', 18)
-
在页面跳转时,该表网页的 title 名
// 在组建被创建后将会调用此方法,然而此方式须在每个组件中都是用,故不推荐 created() { // 通过此方法能改变每个网页的 title 名 document.title = "用户" } // 更优做法,在路由配置文件中添加以下代码 const routes = [ { path: '/', component: Home = () => import ('../components/Home.vue'), // 为每一个路由对象添加元素据,用于跳转页面时更换 title 名 meta: { title: '首页' } } ] // 这些方法也可在每一个映射关系中直接写入 // 前置守卫 router.beforeEach((to, from ,next) => { // from 和 to,即从 from 跳转到 to // 当有路由嵌套时,父路由将会找不到title属性,此时通过 matched 属性中的 meta 的 title 来设置 document.titile = to.matched[0].meta.title // next 为下一步的意思,必须调用这个函数,当不调用此函数时,将会不发生页面的调转 // next 函数中可以传递参数,当参数为 false 时,中断当前导航,或传入一个路径,即为跳转到该路径 next() }) // 后置钩子 router.afterEach((to, from) => { // 后置钩子中没有 next 参数,即当跳转完页面之后才会调用此方法 })
使用 keep-alive 标签嵌套 router-view 标签,能做到,不频繁创建和销毁(由于组件之间进行切换时,会频繁创建和销毁操作),而是缓存下来,这样将会大大提高响应时间
-
keep-alive 的两个属性
<!-- include 字符串或正则表达式,只有匹配的组件会被缓存 --> <!-- exclude 字符串或正则表达式,任何被匹配的组件都不会被缓存 --> <!-- 此处未不缓存 Home 和 Profile 组件,其中 exclude 属性的值未每个组件中的 name 属性值,多个组件使用 , 进行分割,之间不能加空格 --> <keep-alive exclude="Home,Profile"> <route-view/> </keep-alive> <!-- 此处未只缓存 Home 和 Profile 组件,其中 include 属性的值未每个组件中的 name 属性值,多个组件使用 , 进行分割,之间不能加空格 --> <keep-alive include="Home,Profile"> <route-view/> </keep-alive>
-
当页面进行跳转时,设置返回原来页面时,于未跳转之前显示一样
export default { name: 'home', data() { return { // 使用 path 变量用来记录上一次处于活跃状态的路径,用以以后跳转回来时使用 path: '/home/news' } }, // 当页面发生跳转,即路由发生转换前进行调用此函数 beforeRouteLeave(to, from , next) { this.path = this.$route.path next() }, // 当页面处于活跃状态时,进行调用此函数 activated() { this.$router.push(this.path) } }
-
activated 和 deactivated 生命周期函数
export default { name: 'home', // 只有当组件处于 keep-alive 即被保持了状态后才会有效,否则将不会自动调用这两个函数 // 当页面处于活跃状态时,进行调用此函数 activated() { console.log('activated') }, deactivated() { console.log('deactivated') } }
在文件中配置路径映射关系
- 在vue2版本时,找到 webpack.base.config.js 文件(即 webpack 配置文件)在里面修改 resolve 添加相应路径映射关系
resolve: {
alias: {
'@': resolve('src')
'assets': resolve('src/ssets'),
'components': resolve('src/components'),
'views': resolve('src/views')
}
}
- 由于在vue3隐藏了相关的配置文件,故需要在根目录下创建一个 vue.config.js 文件(每次修改配置文件都需要重启以下项目),在该文件中写入以下信息,进行配置相关路径映射关系
module.exports = {
configureWebpack: {
resolve: {
alias: {
'assets': '@/assets',
'components': '@/components',
'views': '@/views'
}
}
}
}
在非 import 方式导入时(例如:导入资源文件图片等)需要在前面加上” ~ “例:~assets/img/1.jpg
Promise 的使用
- 由于异步请求网络数据,可能会导致回调地狱,使用 Promise 能简化编程,使代码看起来更加清晰,代码只需写在 then 函数中即可
new Promise((resolve, reject) => {
// 使用 setTimeout 来模拟异步操作
setTimeout(() => {
//调用 resolve 函数
resolve()
}, 1000)
}).then(() => {
// 在这里进行代码逻辑结构的处理
console.log("hello xiaoming")
// 返回一个 Promise 对象,在以后的调用
return new Promise((resolve, reject) => {
setTimeout(() => {
// 在 resolve 函数中可以进行传递参数,在 then 中可以接受该参数
resolve("hello xiaohong")
}, 1000)
})
// then 中的参数为调用 resolve 函数时,传来的参数
}).then((data) => {
console.log(data)
return new Promise((resolve, reject) => {
setTimeout(() => {
// 成功的时候调用 resolve,失败的时候调用 reject 函数
reject("err ^ ... ^")
} ,1000)
})
// 只有调用 resolve 函数时,才会执行 then 函数,当调用 reject 函数时,将会执行 catch 函数
}).then(() => {
console.log("hello xiaogang") // 次语句将不会被执行
}).catch((err) => {
console.log(err)
}) // 该程序执行结果为,每隔一秒输出一句打印语句
- Promise 的另一种使用形式
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("hello xiaogang")
// reject("err ^ ... ^")
}, 1000)
// 在 then 函数中,可以传递两个参数,一个是数据返回结果,一个是错误信息,即在 then 函数中可以同时完成数据信息返回和错误信息打印
}).then(data => {
console.log(data)
}, err => {
console.log(err)
})
- Promise 的多层级调用,单层级异步简写
new Promise((resolve, reject) => {
// 使用 setTimeout 来模拟异步操作,在网络请求只有该阶段使用
setTimeout(() => {
resolve("hello xiaoming")
}, 1000)
}).then((data) => {
// 在这里进行代码逻辑结构的处理
console.log(data)
// 返回调用 resolve 函数后的结果,此处无异步处理,可直接调用 resolve函数,在每次调用时都修改数据的值,在以下调用中进行输出打印
return Promise.reject(data + "1") // 该处调用了 reject 函数,即以下的 then 将不会执行
// 还可以直接使用 throw 来抛出异常
// throw 'error'
}).then((data) => { // 此函数将不会执行
console.log(data)
return Promise.resolve(data + "2")
}).then(data => { // 此函数将不会执行
console.log(data)
}, err => { // 此函数将会执行
console.log(err)
}) // 打印结果为 xioaming \n xiaoming1
- Promise 进一步的简写
new Promise((resolve, reject) => {
// 使用 setTimeout 来模拟异步操作,在网络请求只有该阶段使用
setTimeout(() => {
resolve("hello xiaoming")
}, 1000)
}).then((data) => {
// 在这里进行代码逻辑结构的处理
console.log(data)
// 返回数据处理后的结果,无需再调用 Promise.resolve() 函数
return data + "1"
}).then((data) => {
console.log(data)
return data + "2"
}).then(data => {
console.log(data)
}, err => {
console.log(err)
})
- Promise.all() 方法
// Promise.all 方法需传入一个数组,每个数组用于封装不同的网络请求
Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("小明")
}, 2000)
}),
new Promise((resolve, reject) => {
setTimeout(() => {
resolve("小红")
}, 1000)
})
// 该 data 对象为一个数组,该数组用于存放两个异步处理操作结果
]).then(data => {
console.log(data[0])
console.log(data[1])
}) // 结果为 小明 \n 小红
第四站
Vuex 状态管理器
当多个组件想使用同一个状态(变量)时,可以使用 vuex 来把这个状态存储到状态管理器中,这样,多个组件使用时可以直接从状态管理器中拿(相当于一个全局变量的存储容器)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WKp5GoUB-1626776658179)(D:\Dahui\DesktopApp\学习资料\学习笔记\前端\JavaScript遗忘知识点\Vue.js\Vue.js学习笔记\img\flow.png)]
Vuex的相关配置
在 src 文件夹下创建一个问价夹名为:store(仓库的意思,用于存储各种状态),在该问价夹中创建 index.js 文件
index.js(vue2.x)
// 导入 Vue 在后续中注册组件
import Vue from 'vue'
// 导入 Vuex 在后续中创建该对象
import Vuex from 'vuex'
// 注册该插件
Vue.use(Vuex)
// 创建 Vuex 对象
const store = new Vuex.Store({
// state 对象用于保存状态(变量),在别的地方只需使用this.$store.state.变量名,即可访问该变量
state: {
},
// vuex 的 store 状态更新的唯一方式通过 mutation
mutations: {
},
actions: {
},
// 类似于组件中的计算属性,在每次使用状态时如果希望在更改后在使用,则需在此处进行实现
getters: {
},
// 用于划分模块
modules: {
}
})
// 导出创建后的 store 对象
export default store
在 main.js 中注册该对象
main.js
import Vue from 'vue'
import App from './App'
import store from './store/index.js'
new Vue({
el: '#app',
store,
render: h => h(App)
})
在 vue3.x 中使用以下方法
- index.js(vue3.x)
import { createStore } from 'vuex'
export default createStore({
// 在 state 中用于存放用于共享的状态
state: {
count: 100
},
mutations: {
// 通过此方法进行对 count 变量进行修改,改方法会自动传入一个参数 state 用于访问 state 中的变量
decreasement(state) {
state.count --
},
increasement(state) {
state.count --
}
},
actions: {
},
modules: {
}
})
在 main.js 中注册该对象
- main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
createApp(App).use(store).use(router).mount('#app')
修改状态管理器中的状态
在修改状态管理器中的状态时如果使用
this.$store.state.变量名 = 值
时,在后期调试无法得知时哪个组件对该状态进行了修改,为了方便后期的维护应使用官方给出的方式去更改
- 该图中显示了更改状态管理器中的方式
- Devtools 为浏览器中进行调试 vue 的插件,Mutions 只能处理同步的操作,对于异步请求等操作不能染过 Action环节,否则 Devtools 无法跟踪到
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hRdMiLDQ-1626776658183)(D:\Dahui\DesktopApp\学习资料\学习笔记\前端\JavaScript遗忘知识点\Vue.js\Vue.js学习笔记\img\vuex.png)]
通过以下方法进行状态的修改
- App.vue
<template>
<div id="app">
<div>{{$store.state.count}}</div>
<div>{{$store.getters.powerCounter}}</div>
<div>{{$store.getters.length}}</div>
<!-- 在此处传入参数进行修改含有参数的状态 -->
<div>{{$store.getters.mergeS('a')}}</div>
<button @click="additionCount(5)">+5</button>
<button @click="addition">+</button>
<button @click="substract">-</button>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
addition() {
// 通过提交的方式进行调用状态管理器中的函数,参数为要调用的函数
this.$store.commit('increment')
},
substract() {
this.$store.commit('decrement')
},
additionCount(count) {
// 通过传入第二个参数的形式可以在调用 mutations 方法中传递参数
this.$store.commit("increasementCount", count)
// 特殊的提交方式,当使用这种方式传递参数时,传递过去的实则为一个对象,访问时需使用 参数.count
this.$store.commit({
type: 'increasementCount',
count
})
}
}
}
</script>
- index.js(store文件夹中的 vuex 配置文件)
import { createStore } from 'vuex'
export default createStore({
state: {
count: 100,
obj: {
age: 18
}
},
// 通过此对象中的函数进行对状态进行修改
mutations: {
// 在改方法中被调用时会自动出入 state 对象,该对象为用户所定义的状态
increment(state) {
state.count ++
},
decrement(state) {
state.count --
},
increasementCount(state, count) {
state.count += count
},
update(state) {
// 在 2.x 版本中此属性将不会加入响应式系统中,而在高版本中此功能已修复,可以进行响应式修改
state.obj['name'] = "xiaoming"
// 在 vue 中可以使用 Vue.set() 方法为对象添加属性,该属性能加入响应式系统中,参数一为要修改的对象,参数二为添加到属性,参数三为属性值
Vue.set(state.obj, 'name', 'xiaoming')
// 使用 delete 关键字能删除对象中的某个属性,但该方法做不到响应式
delete state.obj.age
// 而使用 Vue.delete() 方法能响应式删除对象中某个属性,参数一为要修改的对象,参数二为删除的属性(Vue.2x)
Vue.delete(state.obj, age)
}
},
getters: {
// 此处可以在使用时直接使用修改过后的数据,在使用时可以直接使用 $store.getters.powerCount 来访问
powerCounter(state) {
return state.count * state.count
},
// 此方法会默认传入一个 getters 该 getters 为此处定义的 getters
length(state, getters) {
return getters.powerCounter >= 10000 ? 10 : getters.powerCounter
},
mergeS(state) {
// 调用该方法时返回一个函数,在该函数中可以传入函数,该函数可以通过传入的参数返回修改后的状态
return function(num) {
return state.count + num
},
// 更为简洁的写法,但不推荐,因为不好看懂
mergeS(state) {
return num => state.count + num
}
}
},
actions: {
// 定义一个方法,该方法中会默认传递一个参数,该参数为创建的该 store 对象,参数二为传入的参数
aUpdate(context, payload) {
// 在修改store对象中的状态时,只能通过 mutations 修改 store 对象中的参数
// 在异步操作执行时,通过 actions 来执行 mutations 中的方法,使用此方式 devtools 才能动态跟踪到 store 对象中的状态的变化,在执行 actions 中的方法时,使用 this.$store.dispatch("aUpate")
setTimeout(() => {
context.commit("increment")
}, 1000)
},
// 一种提醒外面,该处已经修改成功的方法,参数二为外提交时传递的一个函数: this.$store.dispatch("aUpate", () => {console.log("里面已经修改完成")})
aUpdate(context, payload) {
setTimeout(() => {
context.commit("increment")
// 调用该函数
payload()
}, 1000)
},
// 另一种方式,在该方式中传递参数时使用如下:this.$store.dispatch("aUpate", {message: '我是信息', success: () => {console.log("里面已经修改完成")}})
aUpdate(context, payload) {
setTimeout(() => {
context.commit("increment")
// 调用该函数
payload.success()
}, 1000)
},
// 另一种更加优雅方式
aUpdate(context, payload) {
retrun new Promise((resolve, reject) => {
setTimeout(() => {
context.commit("increment")
console.log(payload)
resolve("传递过去的信息")
}, 1000)
})
}
// 在别处调用该方法时代码如下
this
.$store.dispath("aUpdate", "携带过去的信息")
.then(res => {
console.log(res)
})
},
moduleA = {
state: {
name: "xiaoming"
},
mutations: {
updateName(state, payload) {
state.name = payload
}
},
actions: {
// 此处的 context 为该模块对象
updateName(context) {
// 在此处使用 commit 时,提交的为该模块中的 mutations 中的方法
context.commit("updateName", 'xiaogang')
}
},
getters: {
update(state) {
return state.name + "1"
},
// 此处 getters 就为该 getters
update2(state, getters) {
return getters.update + "1"
},
// 此处 getters 就为该 getters,rootState 为根 store 对象
update3(state, getters, rootState) {
// 可以通过 rootState 访问根 store 对象的状态
return getters.update + rootState.count
}
},
modules: {}
}
moduleB = {
state: {},
mutations: {},
actions: {},
getters: {},
modules: {}
}
// 在该对象中可以定义模块,模块中又可以定义 state 及别的属性,可以无限套娃,在使用时:this.$store.moduleA.name,在调用 mutations 中的方法时:this.$store("updateName", "xiaohong"),所以各个模块中的 mutations 不要重复
// 在使用 getters 中的方法时也是直接使用:this.$store.getters.update,故getters中定义的方法也不能重复
modules: {
moduleA: moduleA
moduleB: moduleB
}
})
官方推荐,将除 state 和 modules 外的属性抽取到外部文件,在 index 中只需要导入即可,modules 中的相应模块抽取到新建的 modules 文件夹中
- 扩展
在调用 mutations 中的一些函数时,可能调用的函数名会写错,可以通过定义常量的方式避免
在 store 文件夹中创建文件 mutations-type.js 文件
mutations-type.js
export const INCREMENT = 'increment'
export const DECREMENT = 'increment'
在 store 文件夹中的方法名称也可以按这样来定义
import { createStore } from 'vuex'
import {INCREMENT, DECREMENT} from './mutations-type.js'
export default createStore({
state: {
},
// 此方式能减少错误
mutations: {
[INCREMENT](state) {
state.count ++
},
[DECREMENT](state) {
state.count --
},
},
getters: {
},
actions: {
},
modules: {
}
})
在别的地方引用时只需要写以下代码即可
import {INCREMENT, DECREMENT} from './store/mutations-type.js'
// . . .
this.$store.commit(INCREMENT)
// . . .
this.$store.commit(DECREMENT)
// . . .
使用 Axios 进行网络请求
index.js
// 导入相关模块
import axios from 'axios'
axios({
// 该地址可以用来网络测试
url: 'http://httpbin.org'
// 默认情况下为 get 请求,可以通过设置 method 的值来修改请求方式
method: 'get'
// 通过 params 属性来指定传入的 参数
params: {
name: xiaoming,
age: 18
}
// 由于 axios 支持 Promise 故可以使用 Promise 的方式来接收数据
}).then(res => {
console.log(res)
})
axios 发送并发请求
import axios from 'axios'
// 该方法返回所有请求到的结果,并将结果放入数组中,在 then 中拿到 results 该对象为一个数组
axios.all([axios({
// 设置基地址
baseURL: 'http://httpbin.org'
url: '/home'
}), axios({
url: 'http://httpbin.org'
})]).then(results => {
console.log(results)
})
axios.all([axios({
url: 'http://httpbin.org'
}), axios({
url: 'http://httpbin.org'
})]).then(axios.spread((res1, res2) => { // 通过 axios.spread 方法可以将拿到的结果进行分割
console.log(res1)
console.log(res2)
}))
axios 的全局配置
import axios from 'axios'
axios.default.baseURL = "http://httpbin.org"
// 设置超时时间,单位为毫秒
axios.timeOut = 50000
axios 实例
import axios from 'axios'
const instance1 = axios.create({
baseURL: 'http://httpbin.org',
timeout: 5000
})
const instance2 = axios.create({
baseURL: 'http://baidu.com',
timeout: 3000,
headers: {
}
})
instance1({
url: '/home',
params: {
name: xiaoming
}
}).then(res => {
console.log(res)
})
instance2({
url: '/category',
params: {
name: xiaoming,
age: 18
}
}).then(res => {
console.log(res)
})
模块化网络请求
在设计网络请求模块时,最好将网络请求单独写到一个文件中,这样当该网络请求框架不在维护时,可以很容易更换别的框架
单独创建一个文件夹:network,在该文件夹中创建 request.js 文件
request.js
import axios from 'axios'
// 方式一:
export function request(config, success, failure) {
const instance = axios.create({
baseURL: 'http://baidu.com',
timeout: 5000
})
instance(config).then(res => {
success(res)
}).catch(err => {
failure(err)
})
}
// 方式二:
export function request(config) {
const instance = axios.create({
baseURL: 'http://baidu.com',
timeout: 5000
})
instance(config.baseConfig).then(res => {
config.success(res)
}).catch(err => {
config.failure(err)
})
}
// 方式三:
export function request(config) {
return new Promise((resolve, reject) => {
const instance = axios.create({
baseURL: 'http://baidu.com',
timeout: 5000
})
instance(config).then(res => {
resolve(res)
}).catch(err => {
reject(err)
})
})
}
// 方式四:
export function request(config) {
const instance = axios.create({
baseURL: 'http://baidu.com',
timeout: 5000
})
return instance(config)
}
在使用该模块时:
import { request } from './network/request.js'
// 对应方式一
request({
url: '/home'
}, res=> {
console.log(res)
}, err => {
console.log(err)
})
// 对应方式二
request({
baseConfig: {
url: '/home'
},
success: function(res) {
console.log(res)
},
failure: function(err) {
console.log(err)
}
})
// 对应方式三和四
request({
url: '/home'
}).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
axios 的拦截器
import axios from 'axios'
export function request(config) {
return new Promise((resolve, reject) => {
const instance = axios.create({
baseURL: 'http://baidu.com',
timeout: 5000
})
// 请求拦截器
instance.interceptors.request.use(config => {
// 当需要对配置信息进行修改时可以使用拦截器进行修改,在用户请求网络数据时,可以添加响应动画,用户登录时,没有携带 token 时可以进行页面跳转
// 该函数返回配置信息
console.log(config)
// 当缺少返回配置信息时,将不会请求该地址成功,即信息被拦截了。但没有继续向下执行
return config
}, err => {
// 该函数返回错误信息
console.log(err)
})
// 响应拦截器
instance.interceptors.response.use(res => {
// 该方法传入的参数为请求后返回的结果
console.log(res)
// 修改过后响应信息需要将数据进行返回,否则在别的地方接收不到该信息
return res.data
}, err => {
// 请求失败时会调用该函数
console.log(err)
})
return instance(config)
})
}
nce(config).then(res => {
success(res)
}).catch(err => {
failure(err)
})
}
// 方式二:
export function request(config) {
const instance = axios.create({
baseURL: ‘http://baidu.com’,
timeout: 5000
})
instance(config.baseConfig).then(res => {
config.success(res)
}).catch(err => {
config.failure(err)
})
}
// 方式三:
export function request(config) {
return new Promise((resolve, reject) => {
const instance = axios.create({
baseURL: ‘http://baidu.com’,
timeout: 5000
})
instance(config).then(res => {
resolve(res)
}).catch(err => {
reject(err)
})
})
}
// 方式四:
export function request(config) {
const instance = axios.create({
baseURL: ‘http://baidu.com’,
timeout: 5000
})
return instance(config)
}
在使用该模块时:
```js
import { request } from './network/request.js'
// 对应方式一
request({
url: '/home'
}, res=> {
console.log(res)
}, err => {
console.log(err)
})
// 对应方式二
request({
baseConfig: {
url: '/home'
},
success: function(res) {
console.log(res)
},
failure: function(err) {
console.log(err)
}
})
// 对应方式三和四
request({
url: '/home'
}).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
axios 的拦截器
import axios from 'axios'
export function request(config) {
return new Promise((resolve, reject) => {
const instance = axios.create({
baseURL: 'http://baidu.com',
timeout: 5000
})
// 请求拦截器
instance.interceptors.request.use(config => {
// 当需要对配置信息进行修改时可以使用拦截器进行修改,在用户请求网络数据时,可以添加响应动画,用户登录时,没有携带 token 时可以进行页面跳转
// 该函数返回配置信息
console.log(config)
// 当缺少返回配置信息时,将不会请求该地址成功,即信息被拦截了。但没有继续向下执行
return config
}, err => {
// 该函数返回错误信息
console.log(err)
})
// 响应拦截器
instance.interceptors.response.use(res => {
// 该方法传入的参数为请求后返回的结果
console.log(res)
// 修改过后响应信息需要将数据进行返回,否则在别的地方接收不到该信息
return res.data
}, err => {
// 请求失败时会调用该函数
console.log(err)
})
return instance(config)
})
}