a
Vue 学习笔记
基础部分
var let const
var
ES5 没有块级作用域概念
let
ES6新增,增加块级作用域概念
const
ES6新增,定义时必须赋值,且值不可改变,用来修饰常量
const a = 10;
a = 20; // a 不能修改
const
常量的含义是指向的对象不能被改变,但可以改变对象的值
<script>
const obj = {
name:'aaa',
age:18
}
console.log(obj);
obj.name='bbb';
obj.age=30;
console.log(obj);
</script>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4BzPCb1c-1610960137092)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20201231144502359.png)]
Vue生命周期
beforeCreat() 创建前
created()() 创建后
beforeMount() 挂载前
mounted() 挂载后
beforeUpdate() 更新前
updated() 更新后
beforeDestry() 销毁前
destryed() 销毁后
第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子
created 与 mounted的区别
created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。
mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。
ES6 与 ES5 对比
属性增强写法
<script>
/* ES5 */
const obj = {
name:'小龙人',
age:18
}
console.log(obj);
/* ES6 */
const name = '小龙人';
const age = 18;
const person = {
name,
age
}
console.log(person);
</script>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R73Crtj6-1610960137103)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20201231145700763.png)]
函数增强写法
<script>
/* ES5 */
const obj = {
run:function () {
},
eat:function () {
}
}
/* ES6 */
const data = {
run(){
},
eat(){
}
}
</script>
ES6 模块化开发导入与导出
/* 在 aaa.js 中定义 name属性与sum函数 并导出 */
let name = '张三';
function sum(a,b){
return a + b;
}
/* 导出对象 */
export{
name,sum
}
/* bbb.js 导入 aaa.js 导出的sum函数与name属性 */
import {sum,name} from "./aaa.js";
// 执行输出
console.log(sum(10,20));
console.log(name);
<body>
<!-- 主页面引入bbb.js type为 module -->
<script src="bbb.js" type="module">
</script>
</body>
浏览器结果预览:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q2KNuRgV-1610960137105)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210103165838755.png)]
插值指令
1.v-once : 当 name 值改变时 ,标签内的值不会变化
<p v-once>{{ name }}</p>
2.v-for : 遍历
<p v-for=" item in scholl ">{{ item }}</p>
data = {"北京","上海","天津"}
3.v-html : 填充html
<div>
{{ url }}
</div>
data:{
url:'<a src="www.baidu.com">百度</a>'
}
4.v-text : 填充文本
<div>
{{ url }}
</div>
data:{
url:'今天天气不错啊!'
}
绑定属性 v-bind
缩写: : (冒号)
<img v-bind:src="imgUrl" alt="">
<!-- 缩写后,v-bind可省略 -->
<img :src="imgUrl" alt="">
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
name:'张三',
imgUrl:'https://cn.vuejs.org/images/logo.png'
},
})
</script>
动态绑定 class 属性 v-bind
(方式一)
<style>
.line{
color:red
}
.stone{
font-size: 30px;
}
</style>
<div id="app">
<!-- 通过 {} boolean判断该class属性的绑定与否 -->
<p :class="{line:isline,stone:isstone}">今天天气不错</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
isline:true,
isstone:true,
},
})
</script>
(方式二)
<div id="app">
<!-- 通过 {} boolean判断该class属性的绑定与否 -->
<p :class="getClass()">今天天气不错</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
isline:true,
isstone:true,
},
methods:{
getClass:function(){
return {line:this.isline,stone:this.isstone}
}
}
})
</script>
练习——点击变色
<style>
.active{
color: red;
}
</style>
<div id="app">
<ul>
<li v-for="(food,index) in foods" @click="activeIndex = index" :class="{'active':activeIndex==index}"> {{ index }}----{{ food }}</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
activeIndex:-1,
foods:["杂酱面","捞面","海底捞","火锅"]
}
})
</script>
计算属性——computed
Methods 与 computed方法不能重名,重名使用methods定义的方法
Computed 为属性,调用时 使用属性名 例如; {{cur}} 而不是 {{cur()}}
Methods 调用时需要带()
<!-- -->
<div id="app">
<p>{{msg}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
name:"小龙",
age:18
},
<!--computed 会将数据转化后进行显示 -->
computed:{
msg:function(){
return this.name + this.age + '岁'
}
}
})
</script>
结论 :调用方法时.每次都需要进行计算,既然有计篇过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销。
事件监听 v-on
缩写: @
<body>
<div id="app">
<button v-on:click="run">btn1</button>
<button @click="run">btn2</button>
<!-- 在方法调用时,我们需要event对象但又需要其他参数,可使用 $event 手动获取浏览器的event对象 -->
<button @click="eat('汉堡',$event)">btn2</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
methods:{
run(){
alert('runing....')
},
eat(food,event){
alert('我在吃' + food)
console.log(event);
}
}
})
</script>
条件判断
<div id="app">
<p v-if="score == 100">棒极了</p>
<p v-else-if="score >= 80">还行啊</p>
<p v-else-if="score >= 60">勉强及格</p>
<p v-else>???</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
score:90
}
})
</script>
显示切换 v-show
<div id="app">
<!--
v-if : 当条件为false时,包含v-if指令的元素根本不会存在dom中
v-show : 根据 boolean 值 切换元素的显示方式 false 时 display:noe,元素存在dom中
当 显示频率 切换比较高的时候 使用 v-show,当只有一次切换时 使用 v-if
-->
<p v-show="type">
我该显示吗
</p>
<p v-if="type">
我该显示吗
</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
type:true
}
})
</script>
数组响应式方法
<div id="app">
<ul>
<li v-for="item in names">{{ item }}</li>
</ul>
<button @click="change">点我</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
names:['a','b','c','d']
},
methods:{
change() {
// 1.push() 方法 数组添加数据 可通过逗号分隔 添加多个值
this.names.push('x');
this.names.push('x','y','z');
// 2.pop() 方法 数组添加数据
this.names.pop('x');
// 3.shift() 方法 删除数组的第一个元素
this.names.shift();
// 4.unshift() 方法 在数组最前面添加元素 可通过逗号分隔 添加多个值
this.names.unshift('t');
this.names.unshift('y','u','i');
/*
* 4.splice() 方法 可 删除、插入、替换元素
* splice(start,nubmers,)
* start: 起始位置
* numbers:要删除及格元素,不传则删除后面所有元素
* 替换元素:第二个参数表示我们要替换及格元素,后面是替换前面元素的内容
*/
// [删除] 将 第一个元素后面的全部删除
this.names.splice(1);
// [替换] 从 第一个开始,删除 3 个元素 再将 'x','y','z','o' 填充达到数组中
this.names.splice(1,3,'x','y','z','o');
// [插入] 第二个参数为 0 ,后面跟上插入的元素 'x','y','z','o'
this.names.splice(1,0,'x','y','z','o');
// 5.sort() 方法 排序
this.names.sort();
// 6.reverse() 方法 数组反转
this.names.reverse()
// 非响应式 方法 通过索引值 改变数组中的元素
this.names[0] = 'xxx';
// 可使用 splice() 方法完成修改 变成响应式操作
this.names.splice(0,1,'xxx');
// set(要修改的元素,元素的下标,所要修改的值)
Vue.set(this.name,0,'xxx');
}
}
})
</script>
书籍购物车案例
<div id="app">
// 当购物车内容不为空时显示
<div v-if="books.length>1">
<table>
<thead>
<tr>
<th>名称</th>
<th>出版日期</th>
<th>价格</th>
<th>购买数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in books">
<td>{{item.title}}</td>
<td>{{item.time}}</td>
<td>¥{{item.price}}</td>
<td>
<button @click="less(index)" :disabled="item.count <=1 ">-</button>
{{item.count}}
<button @click="add(index)">+</button>
</td>
<td>
<button @click="remove(index)">移除</button>
</td>
</tr>
</tbody>
</table>
<h2>总价:¥ {{ totalPrice }}</h2>
</div>
// 购物车为空则显示当前数据
<div v-else>
<h2>购物车为空</h2>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el: '#app',
data: {
books: [
{
title: 'java',
time: '2020',
price: '20',
count: '1'
},
{
title: 'php',
time: '2020',
price: '30',
count: '1'
},
{
title: 'python',
time: '2011',
price: '40',
count: '1'
},
{
title: 'C++',
time: '2020',
price: '50',
count: '1'
}
]
},
methods: {
// 数量减少
less(index) {
this.books[index].count--;
},
// 数量增加
add(index) {
this.books[index].count++;
},
// 移除购物车
remove(index) {
this.books.splice(index, 1);
}
},
// 通过计算属性 返回总价
computed: {
totalPrice() {
let totalPrice = 0
for (let i = 0; i < this.books.length; i++) {
totalPrice += this.books[i].price * this.books[i].count;
}
return totalPrice;
// 使用 reduce函数 返回
return this.books.reduce(function (preValue,book) {
return preValue + book.price * book.count;
},0)
}
}
})
</script>
* 高级函数 filter map reduce
<!-- 基础写法 -->
<script>
let arr = [10,20,30,50,100,200];
console.log(arr)
// 将 小于 100的元素返回
let newArr = arr.filter(function(n){
// 满足以下条件时,会将 n 添加到新的数组
return n<100;
})
console.log(newArr)
// 将数组内 每个元素 *2 再返回
let doubleArr = arr.map(function(n){
// 对 每个 n *2
return n * 2;
})
console.log(doubleArr);
// 返回数组累加的和
let sumArr = arr.reduce(function (preValue,n) {
return preValue + n;
},0) // 0 表示 preValue的初始值
console.log(sumArr)
</script>
<!-- 进阶写法 -->
<script>
let arr = [10,20,30,50,100,200];
console.log("数组初始数据:")
console.log(arr)
let newArr = arr.filter( n => n<100);
console.log("小于 100:")
console.log(newArr)
let doubleArr = arr.map( n => n*2);
console.log("双倍数值:")
console.log(doubleArr)
let sumArr = arr.reduce((preValue,n) => preValue + n);
console.log("累加总和:")
console.log(sumArr)
</script>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nTGJ2vo6-1610960137107)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20201231192729361.png)]
双向绑定 v-model
<div id="app">
<input type="text" v-model="msg">
// 使用 v-value 与 v-on动态绑定事件可同样实现 数据双向绑定
<input type="text" :value="msg" v-on:input="valueChange">
<p>{{msg}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
msg:'张三'
},
methods:{
valueChange(event){
this.msg = event.target.value;
}
}
})
</script>
v-model 结合 radio
<div id="app">
<input type="radio" value="男" name="sex" v-model="sex">
<input type="radio" value="女" name="sex" v-model="sex">
性别: {{ sex }}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
sex:''
}
})
</script>
v-model 结合 checkbox
<div id="app">
<input type="checkbox" value="吃饭" name="sex" v-model="sex">吃饭
<input type="checkbox" value="看电影" name="sex" v-model="sex">看电影
<input type="checkbox" value="玩游戏" name="sex" v-model="sex">玩游戏
<input type="checkbox" value="吃零食" name="sex" v-model="sex">吃零食br <br/>
爱好: {{ sex }}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
/* 数组类型 */
sex:[]
}
})
</script>
v-model 结合 select
<div id="app">
<select name="d" id="" v-model="msg">
<option value="吃饭">吃饭</option>
<option value="玩游戏">玩游戏</option>
<option value="打豆豆">打豆豆</option>
</select>
<p>选择的是:{{msg}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
/* 数组类型 */
msg:''
}
})
</script>
v-model 修饰符
<div id="app">
<!-- 1.lazy 当用户输入完成(input失去焦点 或 用户按下回车) 更新绑定的数据 -->
<input type="text" v-model.lazy="msg">
<p>输入的是:{{msg}}</p>
<!-- 2.number 会将用户输入的数据转为数组 -->
<input type="text" v-model.number="count">
<p>输入类型:{{typeof count}}</p>
<!-- 2.trim 取出数据左右两端的空格-->
<input type="text" v-model.trim="msg">
<p>输入类型:{{msg}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
/* 数组类型 */
msg:'小爱同学',
count:'dsada'
}
})
</script>
Vue组件
<div id="app">
// 自定义组件名称
<cpm></cpm>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('cpm', {
template:'<div>' +
'<h1>我是标题</h1>' +
'<h1>我是文本</h1>' +
'</div>'
});
</script>
模板分离写法
<div id="app">
{{ name }}
<cpm></cpm>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<!-- 1.使用 text/x-template 通过id绑定到 template-->
<script type="text/x-template" id="cpn">
<div>
<h1>我是标题1</h1>
<h1>我是内容1</h1>
</div>
</script>
<!-- 2.使用<template> 标签 -->
<template id="cpn2">
<div>
<h1>我是标题2</h1>
<h1>我是内容2</h1>
</div>
</template>
<script>
Vue.component('cpm', {
// 通过id获取
template:id='#cpn'
});
new Vue({
el:'#app',
data:{
name:'张三'
},
})
</script>
父子组件的通信
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dZn7Ex0i-1610960137108)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210102161813208.png)]
父传子
<div id="app">
<!--
1.mvs 绑定的是 data中 movies 的数据
2.message绑定的是 data中 msg 的数据
3.将 绑定名称传入组件,由 props接收 并在子组件中使用
-->
<cpn v-bind:mvs="movies" :message="msg"></cpn>
</div>
<template id="cpn">
<div>
<!-- 使用 父组件传递来的数据 -->
<ul>
<li v-for="item in mvs">{{item}}</li>
</ul>
<h1>{{msg}}</h1>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('cpn', {
props:['mvs','message'],
template:id='#cpn'
});
// props 的另一种写法
props:{
mvs:{
// 指定 mvs(key值) 的类型 可选 有String\Nbumer\Object\Boolean\Data\Function 多种可选
type:Array,
// 传递是 不可为空
required:true,
// 默认值
default:[]
}
},
new Vue({
el:'#app',
data:{
msg:'今天是个好天气',
movies:['海王','盗墓笔记','鬼吹灯']
},
})
</script>
子传父(自定义事件 $item)
<div id="app">
<!--
1.fclick 为 子组件中自定义的事件名 this.$emit('fclick',item);
2.parclick 为 父组件的事件名 在vue的methods中
-->
<cpn @fclick="parclick"></cpn>
</div>
<template id="cpn">
<div>
<!-- childck 为子组件的methods 参数为当前 item 对象 -->
<button v-for="item in list" @click="childck(item)">{{item.name}}</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('cpn', {
// 函数式 自定义数据格式
data(){
return{
list:[
{id:1,name:'中国移动'},
{id:2,name:'中国电信'},
{id:3,name:'中国联通'}
]
}
},
template:id='#cpn',
// 自定义事件 向父组件传递数据 fclick 为事件名 在 <cpn @fclick="parclick"></cpn> 使用
methods:{
childck(item){
this.$emit('fclick',item);
}
}
});
new Vue({
el:'#app',
methods:{
parclick(item){
console.log("fck" + item);
}
}
})
</script>
<!-- 写法二: -->
<div id="app">
<cpn :item="movies" @parclick="par"></cpn>
</div>
<template id="cpn">
<div>
<!-- child(item) 必须传参-->
<button v-for="movie in item" @click="child(item)">{{movie.name}}</button>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
Vue.component('cpn',{
template:id='#cpn',
props:['item'],
methods:{
child(item){
this.$emit('parclick',item)
}
}
})
new Vue({
el:'#app',
data:{
name:'张三',
movies:[
{id:1,name:'移动'},
{id:1,name:'电信'},
{id:1,name:'联通'}
]
},
methods:{
par(item){
console.log(item)
}
}
})
</script>
父子组件的访问
父访问子 c h i l d r e n 与 children与 children与refs
<div id="app">
<div>
<cpn></cpn>
<cpn ref="aaa"></cpn>
<cpn></cpn>
<button @click="ck">按钮</button>
</div>
</div>
<template id="cpn">
<div>
<p>我是一个子组件</p>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
name:'张三'
},
components:{
cpn:{
template:id="#cpn",
data(){
return "我是子组件的 data信息"
}
}
},
methods:{
ck(){
// $children 通常用于 获取该组件的 所有 子组件
console.log(this.$children);
// $refs 可在子组件中 绑定 ref属性并获得该子组件 <cpn ref="aaa"></cpn>
console.log(this.$refs);
}
}
})
</script>
子访问父 $parent 与 $root
<!-- 自行百度 -->
插槽 slot
提升组件的复用性
<div id="app">
<cpn>
<!-- 替换插槽的内容 -->
<div>P里有个div</div>
</cpn>
<cpn>
<!-- 替换插槽的内容 -->
<h1>cpn 里 有个h1</h1>
</cpn>
</div>
<template id="cpn">
<div>
<p>这是一个P</p>
<!-- 使用插槽占位 -->
<slot>
<button>
插槽默认值
</button>
</slot>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
name:'张三'
},
components:{
cpn:{
template:id="#cpn"
}
}
})
</script>
具名插槽的使用
通过指定 slot 的name属性 替换指定的插槽
<div id="app">
<cpn>
<!-- 替换指定name属性的插槽 -->
<span slot="center">被替换了吧</span>
</cpn>
</div>
<template id="cpn">
<div>
<p>这是一个P</p>
<!-- 插槽 绑定name属性 -->
<slot name="left"><span>左边</span></slot>
<slot name="center"><span>中间</span></slot>
<slot name="right"><span>右边</span></slot>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
name:'张三'
},
components:{
cpn:{
template:id="#cpn"
}
}
})
</script>
作用域插槽
父组件替换插槽的内容
<div id="app">
<cpn>
<!-- slot-scope="slot" 获取插槽对象 -->
<template slot-scope="slot">
<ol>
<!-- slot.data 获取当前插槽对象的data属性 data命名可自定义 -->
<li v-for="item in slot.data">{{item}}</li>
</ol>
</template>
</cpn>
</div>
<template id="cpn">
<div>
<!-- 绑定数据,将languages绑定给 data 为上面获取属性使用,可随便命名 -->
<slot :data="languages">
<ul>
<li v-for="item in languages">{{item}}</li>
</ul>
</slot>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
new Vue({
el:'#app',
data:{
name:'张三'
},
components:{
cpn:{
template:id="#cpn",
data(){
return{
languages:['java','c','c++','javascript']
}
}
}
}
})
</script>
Webpack
跳过 直接开脚手架了。https://www.bilibili.com/video/BV15741177Eh?p=77
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I3ADwE3N-1610960137110)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104110432895.png)]
vue-cli2
安装:
npm install -g @vue/cli
查看 vue 版本
vue --verison
初始化项目
vue init webpack [项目名称]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f1ePyPKV-1610960137111)(E:\学习\webpack .png)]
尝试启动
cd vue-el
npm run dev 启动成功!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vNwR2E2B-1610960137113)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104150341438.png)]
安装遇到错误:
删除 C:\Users\XQi\AppData\Roaming 下的 npm-cache文件夹
npm clean cache --force
重新进行vue-cli安装。
Eslint规范
用于控制代码编写标准规范。
runtime-compiler与runtime-only区别
https://www.bilibili.com/video/BV15741177Eh?p=96
// runtime-compiler vue运行过程
vdom 为 virtual dom(虚拟 dom)
template -> ast -> render -> v DOM -> ui
将 template(模板) 解析为 ast (abstract syntax tree) 抽象语法树 ,ast 编译为 render函数 ,从 render函数创建虚拟DOM节点形成虚拟DOM树,最终显示为真实DOM
// runtime-only 省略了 将模板解析文 ast的过程
render > v DOM > ui
总结:runtime-only 代码更少性能更高
[main.js] 代码区别如下
/* runtime-compiler */
new Vue({
el: '#app',
components: { App },
template: '<App/>'
})
/* runtime-only */
new Vue({
el:'#app',
render:h => h(App)
})
vue-cli3
安装
1.卸载现有 vue-cli
npm uninstall vue-cli -g
2.安装新的vue-cli
npm install -g @vue/cli
3.查看版本,应该是 3.xxx
vue --version
初始化项目
vue create [项目名称]
选择配置:
一开始只有两个选项: default
(默认配置)和Manually select features
(手动配置)
默认配置只有babel
和eslint
其他的都要自己另外再配置,所以我们选第二项手动配置。
在每次选择手动配置之后,会询问你是否保存配置,也就是图片中的koro
选项,这样以后我们在进行创建项目的时候只需使用原先的配置就可以了,而不用再进行配置。
根据项目需要来选择配置,空格键是选中与取消,A键是全选
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
// 检查项目所需的功能:(按<space>选择,<a>切换所有,<i>反转选择)
>( ) TypeScript // 支持使用 TypeScript 书写源码
( ) Progressive Web App (PWA) Support // PWA 支持
( ) Router // 支持 vue-router
( ) Vuex // 支持 vuex
( ) CSS Pre-processors // 支持 CSS 预处理器。
( ) Linter / Formatter // 支持代码风格检查和格式化。
( ) Unit Testing // 支持单元测试。
( ) E2E Testing
如果你选择了Css预处理器选项,会让你选择这个
完成后打开项目!
npm run serve // 启动项目
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-heJJiTFY-1610960137115)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104165443734.png)]
图形化创建项目
命令行输入,进入创建页面,然后就是无脑的手动操作,此处略过。
vue ui
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bgCpf1FB-1610960137117)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104165552624.png)]
vue-cli3 的配置
vue ui // 进入图形化界面,导入项目
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5lu9cdeJ-1610960137117)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104171101075.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9ogRcGy7-1610960137118)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104171112915.png)]
安装指定版本的vue-cli
卸载当前版本;
npm uninstall -g @vue/cli
安装新版本:
npm install -g @vue/cli@版本号
例如:
npm install -g @vue/cli@3.2.1
箭头函数(ES6)
<script>
// 普通写法
function sum(a,b){
return a + b;
}
// 调用
sum(10,20)
//Es6 x函数计算 a与b的和
let x = (a,b) => a + b;
console.log(x(10,20));
// 当只有一个参数时
let y = (x) => {
return x * x
}
// 只有一个参数小括号可省略
let y = x => {return x * x}
// 只有一行代码时 , {} 也可以省略
let z = n => n*2
console.log( y(20) );
</script>
Vue-Router
基本概念
后端路由概念
当页面需要请求不同的路径时,交给服务器来进行处理,服务器渲染好整个页面并将页面返回给客户端。
前后端分离阶段
后端只负责提供数据,不负责提供给任何界面的内容。
前端渲染
网页中大部分内容都是有前端js代码在浏览器中执行,最终渲染出的网页。
SPA页面
单页面应用 single page web application
在前后端分离基础上 增加 前端路由,前端来维护路由规则
url 与 页面 对应关系 由前端管理
前端路由核心
改变url,但是页面不进行整体刷新
官方网址:
https://router.vuejs.org/zh/
安装与使用
安装
npm install vue-router --save
使用: src目录下 创建 router目录,并新增 index.js
/**
* 配置所有的路由信息
*/
// 导入Vue 与 VueRouter
import Vue from 'vue'
import VueRouter from 'vue-router'
// 1.通过Vue.use(插件) 安装插件
Vue.use(VueRouter);
// 2.创建路由对象
const routers = [
]
const router = new VueRouter({
// routers 负责配置组件质之间的映射关系
routers
})
// 3.将router传入 Vue实例中
export default router
在 main.js 导入并使用路由
import Vue from 'vue'
import App from './App'
// 导入路由
import router from "./router";
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
// 使用路由
router,
components: { App },
template: '<App/>'
})
使用步骤
1.创建路由组件 在conponents 目录下 创建 about与home组件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EEGTV94O-1610960137120)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104220143066.png)]
<!-- home.vue 内容如下 -->
<template>
<div>
<h2>我是首页</h2>
</div>
</template>
<script>
export default {
name: "home"
}
</script>
<style scoped>
</style>
<!-- about.vue 内容如下 -->
<template>
<div>
<h2>我是About</h2>
</div>
</template>
<script>
export default {
name: "about"
}
</script>
<style scoped>
</style>
2.配置路由映射:组件和路径映射关系
/**
* 配置所有的路由信息
*/
// 导入Vue 与 VueRouter
import Vue from 'vue'
import VueRouter from 'vue-router'
// 导入组件
import home from "../components/home";
import about from "../components/about";
// 1.通过Vue.use(插件) 安装插件
Vue.use(VueRouter);
// 2.创建路由对象
const routes = [
// path 为 组件路径,component 为具体组件 上方有引入
{
path:'/home',
component:home
},
{
path: '/about',
component: about
}
]
const router = new VueRouter({
// routes 负责配置组件质之间的映射关系,Es6 写法
routes
})
// 3.将router传入 Vue实例中
export default router
3.使用路由,通过 和
<template>
<div id="app">
<!-- to 表示指向组件路径 -->
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<!-- 组件内容渲染位置 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
效果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2nmKKkQN-1610960137121)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210104220515644.png)]
默认路径与
修改 启动 默认路径
routes 中 配置
// 默认路径重定向 到 home首页
{
path:'',
redirect:'/home'
},
# 删除
const router = new VueRouter({
// routers 负责配置组件质之间的映射关系
routes,
// 省去 url中的 # 号
mode:'history'
})
router-link的其他属性
<div id="app">
<!-- to 表示指向组件路径 -->
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<!-- tag属性 会将 router-link以指定组件方式渲染,此处渲染为 button-->
<router-link to="/home" tag="button">首页</router-link>
<router-link to="/about" tag="button">关于</router-link>
<!-- replace属性 不会留下history记录,使用该属性无法点击返回按钮返回上一级-->
<router-link to="/home" replace>首页</router-link>
<router-link to="/about" replace>关于</router-link>
<!-- active-class属性 当该组件被点击后,处于活跃状态,会为当前元素设置 一个 router-link-active 的class -->
<!-- 在进行 高亮显示 时会使用该属性 无需手动增加-->
<router-link to="/home">首页</router-link>
<router-link to="/about">首页</router-link>
<!-- 组件内容渲染位置 -->
<router-view></router-view>
</div>
<style>
// 直接进行 高亮渲染
.router-link-active{
color: red;
}
</style>
通过代码实现跳转
<!-- 通过代码方式 跳转路径 -->
<button @click="homeClick">首页</button>
<button @click="aboutClick">关于</button>
<!-- 组件内容渲染位置 -->
<router-view></router-view>
<script>
export default {
name: 'App',
methods:{
homeClick(){
// $router 为 vue-router源码自带属性
this.$router.push('/home');
// replace 不支持 浏览器 返回
this.$router.replace('/home');
},
aboutClick(){
this.$router.push('/about');
this.$router.replace('/about');
}
}
}
</script>
动态路由
<template>
<div>
<h2>我是用户</h2>
<!-- $route 为当前活跃路由 截取传递来的参数,id为参数名 -->
<h1>{{$route.params.id}}</h1>
</div>
</template>
<script>
export default {
name: "user"
}
</script>
<style scoped>
</style>
路由对象配置:
const routes = [
// 默认路径重定向 到 home首页
{
path:'',
redirect:'home'
},
// path 为 组件路径,component 为具体组件 上方有引入
{
path:'/home',
component:home
},
{
path: '/about',
component: about
},
// 传递参数 参数名 为 id
{
path: '/user/:id',
component: user
}
]
App.vue配置:
<template>
<div id="app">
<!-- to 表示指向组件路径 -->
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<!-- 动态获取id,通过v-bind 内部进行拼接-->
<router-link :to="'/user/'+id">用户</router-link>
<!-- 组件内容渲染位置 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name:'App',
data(){
return{
id:123
}
}
}
</script>
路由懒加载
当打包构建应用时,js文件较大,加载缓慢,影响页面加载。
我们把不同的路由组件分割为不同的代码模块,当路由访问时,去加载对应组件,这就是懒加载。
懒加载效果图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lXe1zcrN-1610960137122)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210105105112245.png)]
具体实现
const home = () => import('../components/home.vue)
const about = () => import('../components/about')
const user = () => import('../components/user')'
const routes = [
// 默认路径重定向 到 home首页
{
path:'',
redirect:'home'
},
// path 为 组件路径,component 为具体组件 上方有引入
{
path:'/home',
component:home
},
{
path: '/about',
component: about
},
{
path: '/user/:id',
component: user
}
]
路由嵌套
路径与组件关系如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SOydupkl-1610960137123)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210105105856660.png)]
// home 路径下 有两个 子组件 ,
{
path:'/home',
component:home,
children:[
// 设置子组件默认路径 path 的 / 可省略
{
path: '',
redirect:'news'
},
{
path:'news',
// 懒加载 导入组件
component: () => import('../components/homeNews')
},
{
path: 'message',
component:()=> import('../components/homeMessage')
}
]
},
```
```vue
<template>
<div>
<h2>我是首页</h2>
<!-- 添加 路由显示 -->
<router-link to="/home/news">新闻</router-link>
<router-link to="/home/message">消息</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "home"
}
</script>
<style scoped>
</style>
```
#### 参数传递
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7Q0FXeZW-1610960137125)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210105112300311.png)]
创建 profile.vue 组件
```vue
<template>
<div>
<h1>我是一个档案,嘿嘿嘿</h1>
<!-- 获取路由传递的 query字段 -->
<h2>{{$route.query}}</h2>
<!-- 获取路由传递的 query字段 的指定参数 -->
<h2>{{$route.query.name}}</h2>
</div>
</template>
<script>
export default {
name: "proFile"
}
</script>
<style scoped>
</style>
```
index.js 增加组件配置
```javascript
{
path: '/profile',
component:() => import('../components/proFile')
}
```
App.vue配置路由
```javascript
<template>
<div id="app">
<!-- to 表示指向组件路径 -->
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<router-link :to="'/user/'+id">用户</router-link>
<!-- 以 query方式传递参数 -->
<router-link :to="{path:'/profile',query:{name:'张三',age:18}}">档案</router-link>
<!-- 组件内容渲染位置 -->
<router-view></router-view>
</div>
</template>
```
#### $router 与 $route 的区别
**$router为当前 vue实例,想要导航到不同的url,使用$router.push 方法**
**$route为当前活跃 route,可从跳转对象中获取name、parms、path、query等相关信息**
[参考 vue-router源码]
#### vue-router全局导航守卫
**导航守卫?: 负责监听路由的跳转**
##### 生命周期函数补充说明
created() 当组件创建时 执行
mounted() 组件 被挂载时执行
updated() 组件刷新时执行
##### 导航守卫实现——前置钩子
**router/index.js**
```javascript
/**
* 配置所有的路由信息
*/
// 导入Vue 与 VueRouter
import Vue from 'vue'
import VueRouter from 'vue-router'
// 导入组件
import home from "../components/home";
import about from "../components/about";
import user from "../components/user";
// 1.通过Vue.use(插件) 安装插件
Vue.use(VueRouter);
// 2.创建路由对象
const routes = [
// 默认路径重定向 到 home首页
{
path:'',
redirect:'/home/news'
},
// path 为 组件路径,component 为具体组件 上方有引入
{
path:'/home',
component:home,
// 设置当前页面title名称
meta:{
title:'首页'
},
children:[
{
path: '',
redirect:'/home/news'
},
{
path:'news',
component: () => import('../components/homeNews')
},
{
path: 'message',
component:()=> import('../components/homeMessage')
}
]
},
{
path: '/about',
component: about,
meta:{
title:'关于'
},
},
{
path: '/user/:id',
component: user,
meta:{
title:'用户'
},
},
{
path: '/profile',
component:() => import('../components/proFile'),
meta:{
title:'档案'
},
}
]
const router = new VueRouter({
// routers 负责配置组件质之间的映射关系
routes,
// 省去 url中的 # 号
mode:'history'
})
// 3.将router传入 Vue实例中
export default router
```
**main.js**
```javascript
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
// 导入路由
import router from "./router";
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
// 使用路由
router,
components: { App },
template: '<App/>'
})
// 配置 导航守卫 beforeEach 前置钩子
router.beforeEach(function (to,from,next) {
// 将当前页面(to) title 设置为 目标路由(form)的title
// matched.neta.title 防止路由嵌套 无法获取正确的 title
document.title = to.matched[0].meta.title
// 必写,next()函数中可填写url,跳转指定的路径
next()
})
// Es6 写法
router.beforeEach((to,from,next) => {
document.title = to.matched[0].meta.title
// 必写
next()
})
})
```
##### 导航守卫实现——后置钩子
router**.beforeEach(to,from,next)** 变为 router.**afterEach(to,from)**
##### 官网教程
> https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
##### 路由独享守卫
```javascript
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
```
##### 组件内的守卫
```javascript
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
```
#### keep-alive
> vue生命周期,保持组件不被频繁创建、频繁销毁·
```vue
<template>
<div id="app">
<!-- to 表示指向组件路径 -->
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<router-link :to="'/user/'+id">用户</router-link>
<router-link :to="{path:'/profile',query:{name:'张三',age:18}}">档案</router-link>
<keep-alive>
<!-- 组件内容渲染位置 -->
<router-view></router-view>
</keep-alive>
</div>
</template>
```
**相关属性**
```javascript
<!--
include:只有 匹配的组件不会被缓存,
exclude:任何匹配的组件都不会缓存
属性内填写组件的name属性,user为组件中 name为 user的组件
-->
<keep-alive exclude="profile,user">
<!-- 组件内容渲染位置 -->
<router-view></router-view>
</keep-alive>
// 组件详情
<template>
<div>
<h2>我是用户</h2>
<!-- $route 为当前活跃路由 截取传递来的参数,id为参数名 -->
<h1>{{$route.params.id}}</h1>
</div>
</template>
<script>
export default {
name: "user"
}
</script>
<style scoped>
</style>
```
#### 代码练习:tabbar
> https://gitee.com/iQeKiaLieW/tabbar.git[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-78adcAIb-1610960137126)(C:\Users\XQi\AppData\Roaming\Typora\typora-user-images\image-20210105163946688.png)]
### Promise(ES6)
> 处理异步操作。使用promise对异步请求进行封装
***
```javascript
<script>
/*
* new -> 构造函数(1.保存状态信息2.执行传入的函数)
*/
new Promise((resolve,reject) => {
// resolve 仅负责异步请求
resolve('hello world')
// 成功时调用 resolve,失败时调用 reject
reject('error message')
// then 负责 处理异步请求的 数据
}).then(data => {
console.log(data); // 输出 hello world
// catch 负责处理请求失败的操作
}).catch(err => {
console.log(err); // 输出 error message
})
</script>
```
##### 三种状态
> pending:等待状态,比如正在进行网络请求,定时器没有到时间
>
> funfill: 满足状态,当我们主动调用 resolve() 会处于 满足状态,并回调 then()
>
> reject: 拒绝状态,当我们主动调用 reject() 会处于 满足状态,并回调 catch()
##### 另外处理方式
```javascript
<script>
new Promise((resolve,reject) => {
setTimeout(() => {
//resolve('SUCCESS');
reject('ERROR');
},1000)
// then 中 可同时处理 请求成功回调与请求失败回调,以两个参数传入,第一个参数为成功回调,第二个参数为失败回调
}).then(data =>{
console.log(data)
},err => {
console.log(err)
})
</script>
```
### Promise的 all 方法
> 当 A 请求需要 B请求与C请求请求完成后才可以发送请求,使用一下方法。
```javascript
<script>
Promise.all([
new Promise((resolve,reject) => {
$.ajax({
url:'url1',
success(data){
resolve(data);
}
})
$.ajax({
url:'url2',
success(data){
resolve(data);
}
})
}).then( results =>{
// results 为一个数组,存放上面两个请求的 响应结果
// results[0] 为第一个请求的结果,results[1] 为第二个请求的结果
console.log(results[0]);
console.log(results[1]);
})
])
</script>
```
### Vue X
***
> 定义: 状态管理工具,管理共享数据,比如用户登录状态、名称、头像等。
#### 下载使用
```bash
npm install vuex --save
```
**创建 store 文件夹,创建index.js**
```javascript
import Vue from 'vue'
// 导入 vuex
import Vuex from 'vuex'
// 使用插件
Vue.use(Vuex)
// 创建对象 Store大写
const store = new Vuex.Store({
// 状态(数据)存放
state:{
count:0
},
// 函数处理
mutations:{
increment(state){
state.count ++;
},
decrement(state){
state.count --;
}
}
})
// 导出 store
export default store
```
**main.js中 使用 store**
```javascript
import Vue from 'vue'
import App from './App'
// 导入 store
import store from "./store";
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
// 使用 store
store,
render: h => h(App)
})
```
**数据展示及处理**
```vue
<template>
<div id="app">
<div>
<p>—————————————Div内容———————————————</p>
<!-- 在 vue组件中 获取 vuex状态 -->
<h2>{{$store.state.count}}</h2>
<button @click ="add"> + </button>
<button @click="sub"> - </button>
</div>
</div>
</template>
<script>
import HelloVuex from "./components/HelloVuex";
export default {
name: 'App',
comments:{
HelloVuex
},
methods:{
// 使用 commit 调用 括号内的函数
add(){
this.$store.commit('increment');
},
sub(){
this.$store.commit('decrement');
}
}
}
</script>
<style>
</style>
```
#### 核心概念
>1.State 单一状态树,一个项目只有一个 store
>
>2.Getters 类似计算函数(computed),
>
>3.Mutation 当修改 Store中的 State,必须通过 Mutation
>
>4.Action 处理异步操作
>
>5.Module
##### Getters使用
```javascript
state:{
count:0,
player:[
{id:110,name:'aaa',age:10},
{id:111,name:'bbb',age:15},
{id:112,name:'ccc',age:20},
{id:113,name:'ddd',age:25}
]
},
// 响应式计算 count 的乘积
getters:{
powerCount(state){
return state.count * state.count;
},
// 返回 小于 10 岁的 运动员
lessAge (state){
return state.player.filter( p => p.age<=10)
},
// 返回 小于 10 岁的 运动员的 长度
lessAgeLength (state){
return state.player.filter( p => p.age<=10).length;
},
// 返回 小于 10 岁的 运动员的 长度
length(state,getters){
// 通过传入 getters 返回
return getters.lessAge.length;
},
// 返回小于指定 age 的数据
lessLength(state){
// 嵌套函数
return age => {
return state.player.filter( p => p.age<=age)
}}
},
调用并显示:$store.getters.xxxx
<div id="app">
<div>
<p>—————————————Div内容———————————————</p>
<!-- 在 vue组件中 获取 vuex状态 -->
<h2>{{$store.state.count}}</h2>
<button @click ="add"> + </button>
<button @click="sub"> - </button>
<p>—————————————Getters相关信息———————————————</p>
<h2>{{$store.getters.powerCount}}</h2>
<p>—————————————Getters小于 20岁球员———————————————</p>
<h1>{{$store.getters.lessAge}}</h1>
<p>—————————————Getters的长度———————————————</p>
<h1>{{$store.getters.length}}</h1>
<p>—————————————Getters小于指定age———————————————</p>
<h1>{{$store.getters.lessLength(20)}}</h1>
</div>
```
##### Mutations的使用
**定义**
```javascript
mutations:{
increment(state){
state.count ++;
},
decrement(state){
state.count --;
}
}
```
**调用**
```javascript
methods:{
// 使用 commit 调用 括号内的函数
add(){
this.$store.commit('increment');
},
sub(){
this.$store.commit('decrement');
}
}
```
**传递参数**
```javascript
<button @click="addCount(5)"> +5 </button>
<button @click="addCount(10)"> +10 </button>
<button @click="addPlayer"> 添加球员 </button>
// 传递参数,num
addCount(num){
this.$store.commit('addCount',num);
},
// 传递对象
addPlayer(){
const player = {id:1000,name:'xxxx',age:1};
this.$store.commit('addPlayer',player);
}
<!--mutations 定义-->
mutations:{
// 增加指定数值
addCount(state,num){
state.count = state.count + num;
},
// 添加对象
addPlayer(state,player){
state.player.push(player);
}
}
```
**提交分格**
```javascript
addCount(num){
// 普通写法
this.$store.commit('addCount',num);
// 新写法 格式: this.$store.commit('',payload)
this.$store.commit({
type:'addCount',
num
});
},
// 增加指定数值(普通)
addCount(state,num){
state.count = state.count + num;
},
// 新写法
addCount(state,payload){
state.count = state.count + payload.num;
},
```
##### Actions的使用
> 在 Mutations处理异步请求无法实现,故在Actions中使用
```javascript
actions:{
aRename(content){
setTimeout(()=>{
// 最终 都要 commit 到 Mutations中处理
content.commit('rename');
},2000)
}
}
// App.vue methods中写法:
methods:{
rename(){
// 使用 dispatch 调用 action中的方法
this.$store.dispatch('aRename');
}
}
```
##### Modules的使用
> store 模块化封装
```javascript
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态
```
> 官网链接 https://vuex.vuejs.org/zh/guide/modules.html
***
### 网络请求封装 axios
##### 下载使用
```bash
npm install axios --save
```
```javascript
axios({
url:'http://123.207.32.32:8000/home/multidata'
}).then(res => {
console.log(res);
})
axios({
url:'http://123.207.32.32:8000/home/data',
// 可 在 url直接拼接参数,也可配置 params添加参数
params:{
type:'sell',
page:2
}
}).then(res => {
console.log(res);
})
```
##### 发送并行请求 axios.all()
```javascript
axios.all([axios(
{
url:'http://123.207.32.32:8000/home/multidata'
}
),axios(
{
url:'http://123.207.32.32:8000/home/data',
params:{
type:'sell',
page:2
}
}
)]).then( results => {
console.log(results);
})
```
##### 全局配置
```javascript
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
```
> 官方文档——http://www.axios-js.com/zh-cn/docs/#%E5%85%A8%E5%B1%80%E7%9A%84-axios-%E9%BB%98%E8%AE%A4%E5%80%BC
##### axios实例封装
```javascript
import axios from "axios";
export function request(config) {
// 创建axios实例对象
const instance = axios.create({
baseURL:'http://123.207.32.32:8000',
timeout:5000
})
// 基本写法
return new Promise((resolve,reject) => {
instance(config).then(result => {
resolve(result);
}).catch(error => {
reject(error);
})
})
// 优于 axios 内置了 Promise,所以直接返回即可
return instance(config);
}
```
> 调用
```javascript
request({
url:'/home/multidata'
}).then(res => {
console.log(1);
console.log(res);
})
```
##### axios 拦截器
```javascript
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
```
**ajax实例添加拦截器**
```javascript
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
```
**错误处理**
```javascript
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
```
发送并行请求 axios.all()
```javascript
axios.all([axios(
{
url:'http://123.207.32.32:8000/home/multidata'
}
),axios(
{
url:'http://123.207.32.32:8000/home/data',
params:{
type:'sell',
page:2
}
}
)]).then( results => {
console.log(results);
})
```
##### 全局配置
```javascript
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
```
> 官方文档——http://www.axios-js.com/zh-cn/docs/#%E5%85%A8%E5%B1%80%E7%9A%84-axios-%E9%BB%98%E8%AE%A4%E5%80%BC
##### axios实例封装
```javascript
import axios from "axios";
export function request(config) {
// 创建axios实例对象
const instance = axios.create({
baseURL:'http://123.207.32.32:8000',
timeout:5000
})
// 基本写法
return new Promise((resolve,reject) => {
instance(config).then(result => {
resolve(result);
}).catch(error => {
reject(error);
})
})
// 优于 axios 内置了 Promise,所以直接返回即可
return instance(config);
}
```
> 调用
```javascript
request({
url:'/home/multidata'
}).then(res => {
console.log(1);
console.log(res);
})
```
##### axios 拦截器
```javascript
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
```
**ajax实例添加拦截器**
```javascript
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
```
**错误处理**
```javascript
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
```