# CodeWhy-Vue学习
**Repository Path**: greentreecloud/vue-learning-notes
## Basic Information
- **Project Name**: CodeWhy-Vue学习
- **Description**: Vue2学习过程
原课程链接:https://www.bilibili.com/video/BV15741177Eh
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2024-06-18
- **Last Updated**: 2024-06-18
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 简介
[vue官网](https://cn.vuejs.org/)
vue 是一套用于构建用户界面的渐进式框架。
Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,易于上手,且方便与第三方库或既有项目整合。
## 安装方式
1. CDN引入
```html
```
2. 下载和引入
[开发版本](https://cn.vuejs.org/js/vue.js)
[生产版本](https://cn.vuejs.org/js/vue.min.js)
3. npm安装
```shell
npm install vue
```
## Vue简介
### 1. Vue中的MVVM
将图形用户界面的开发与业务逻辑或后端逻辑(数据模型)的开发分离开来,这意味着视图模型负责从模型中暴露(转换)数据对象,以便轻松管理和呈现对象。
缺点:非常大的应用程序中的数据绑定会导致相当大的内存消耗。
MVVM模式组成部分:
- 模型、数据层|model (服务器请求数据,或固定数据)
- 视图|view (前端中,一般指的是dom层,常用来展示信息)
- 视图模型|VueModel (实现了Data Binding,也就是数据绑定的同时实现了DOM监听)
- 绑定器
### 2. Vue实例optinos选项
el:
类型:string|HTMLElement
作用:决定之后Vue示例会管理哪个dom
data:
类型:Object|Function(组件中data必须是一个参数)
作用:Vue示例对应的数据对象
methods:
类型:{[key:string]:Function}
作用:定义属于Vue实例的一些方法,可以在其它方法调用,也可以在其它指令中调用
created:
类型:
作用:
mounted:
类型:
作用:
### 3. Vue生命周期
1. 补充开发中什么时候称为方法,什么时候称为函数
- 方法:method
- 函数:function
2. 生命周期:事物从诞生到消亡的整个过程
3. 生命周期钩子
[官方文档-生命周期钩子](https://v3.cn.vuejs.org/api/options-lifecycle-hooks.html#beforecreate)
生命周期图示:

## Vue模板语法
### 插值操作
#### Mustache语法(八字胡语法)与其它指令
```html
{{ message }}
{{ firstname + message }}
{{ (n1 + n2)*2 }}
{{ message }}
{{ url }}
你好 世界
{{ message }} = 你好 世界
```
#### 补充 v-cloak 指令
在渲染完成后,vue 会自动删除 v-cloak 属性
```html
{{ message }}
```
总结:
1. {{message}} 插值表达式,在元素 content 中渲染指定文本内容,可以进行简单计算
2. v-once 初始化解析一次,不参与响应式
3. v-cloak 指定属性会在 vue 解析渲染之后自动删除,与css搭配用来解决 js 延迟带来的问题
4. v-html 指定文本按照dom元素解析渲染
5. v-text 指定文本覆盖标签内容渲染
6. v-pre (prevent,阻止解析)
### 绑定属性
#### v-bind基本使用
一般用来动态绑定属性,例如:v-bind:src='url'
语法糖:可以省略 v-bind 关键字,例如::src='url',类似的语法糖还有很多,例如:@click是 v-on 监听器的语法糖
```html
```
#### v-bind动态绑定class(对象语法)
v-bind可以使用键值对的方式动态绑定多个class属性
```html
123
```
#### v-bind动态绑定class(数组语法)
v-bind可以使用数组(字符串)的方式绑定多个class属性,较少使用
```
123
```
#### v-bind动态绑定style属性(对象语法)
`:style="{key(属性名):value(属性值)}"`
```html
{{ message }}
{{ message }}
```
#### v-bind动态绑定style属性(数组语法)
```html
{{ message }}
{{ message }}
{{ message }}
```
### 计算属性
#### 计算属性的基本操作
```html
{{ firstName +' '+lastName }}
{{ firstName }} {{ lastName }}
{{ getFullName() }}
{{ fullName }}
```
#### 计算属性的复杂操作
注意:computed 和 methods的区别
- computed 计算会进行缓存,多次调用可以减轻计算压力
- methods 调用一次计算一次
计算属性的优势就是:1.让代码变得简洁,2.提高效率
```html
总价格:{{ totalPrice }}
```
#### 计算属性中的 setter 和 getter 方法
```html
{{ fullName }}
```
### ES6 补充
#### let/var 变量
1. 变量作用域定义:变量在什么范围内是可用的
2. 块级作用域
js中使用var来声明一个变量时,变量的作用域主要是和函数的定义有关。
针对其它块定义来说时没有作用域的,比如if/for等,这会造成一些问题。
3. 没有块级作用域,会造成内存污染
示例1
```javaScript
var func;
if(true){
var name = "lisi";
func = function(){;
console.log(name)
}
}
name = 'wangwu';//子作用域的变量可以被随意修改
func();//wangwu
```
示例2
```JavaScript
var btns = document.getElementsByTagName('button');
for (var index = 0; index < btns.length; index++) {
// 问题(给 button 绑定点击事件返回序号 5)
// btns[index].addEventListener('click',function(){
// console.log(index);
// })
// 解决方案(闭包)
// 原因:函数有作用域,换言之闭包是一个私有作用域
(function(i){
btns[i].addEventListener('click',function(){
console.log(i);
})
})(index)
}
```
#### const 常量
1. const修饰的变量一旦赋值,不能被再次赋值
2. 在使用const定义标识符,必须进行赋值
3. 常量的含义是指向的内容不可以改变,但是可以改变对象内部的属性
```javascript
const obj = {
id: 1,
name: 'lisi',
age: 18,
hobbies:{
car:'suiki',
book:['说文解字','张三说刑法']
}
}
obj.naem = 'wangwu'
```
#### 对象字面量的增强写法
1. 创建对象的方法
```javascript
// 利用new关键字创建对象
const obj = new Object()
// 利用字面量创建对象
const obj = {}
```
2. 属性的增强写法
```javascript
const name = 'lisi'
const age = 18
const height = 1.77
// es5的写法
const obj = {
name = name,
age = age,
height = height
}
// es6的写法
const objTwo = {
name,
age,
height
}
```
3. 函数的增强写法
```javascript
// ES5的写法
const obj = {
run: function() {}
}
// ES6的写法
const objTwo = {
run() {}
}
```
#### 常用数组遍历方法
1. 常规for循环
```javaScript
for (let index = 0; index < array.length; index++) {
const element = array[index];
}
```
2. for...in
```javaScript
for (const key in object) {
if (Object.hasOwnProperty.call(object, key)) {
const element = object[key];
}
}
```
3.for...of
```javascript
for (const iterator of object) {
}
```
4. foreach
```javascript
array.forEach(element => {
});
```
### 事件监听
#### 1. v-on 简单使用
```html
{{ counter }}
```
#### 2. v-on调用 methods 中定义的方法需要传参
1. 需要传入参数,没有传入,这个时候浏览器会默认将浏览器生成的 event 对象作为参数、
2. 方法定义时,需要 event 对象,同时又需要其它参数,则使用 `$event` 获取 event 对象
```html
{{ counter }}
```
3. v-on阻止事件冒泡(.stop修饰符的使用)
```html
```
4. v-on 阻止默认事件(.prevent修饰符的使用)
```html
```
5. v-on监听键盘事件 (.{keyCode|keyAlias} 只当事件是从特定键触发时才触发回调)
```html
```
6. .native 监听组件根元素的原生事件
7. .once 只触发一次回调
```html
```
### 条件判断
#### v-if 、v-else、v-elseif
```html
{{message}}
{{message}} + else
优秀
良好
及格
不及格
```
#### 登录切换案例
```html
```
补充:Vue在进行dom元素渲染时,出于性能考虑,会尽可能复用已经存在的元素,而不是重新创建新的元素
解决方案:不希望Vue重复利用的问题。可以给对应的元素绑定 key 属性,key不同不会进行复用
#### v-show 显示与1隐藏
```html
{{ message }}
{{ message }}
```
### 循环遍历
#### v-for
```html
{{ index + 1}}. {{ item }}
- {{ index }} {{ key }} {{ value }}
```
#### 补充 组件的key属性和数组的响应式方法
1. 组件的key属性
官方推荐:在使用v-for时,给对应的元素或组件添加上一个:key属性
key的作用主要是为了高效的更新虚拟DOM
2. 数组的响应式方法
Vue包含了一组观察数组编译的方法,使用这些方法也会触发视图更新
- push()
- pop()
- shift()
- unshift()
- splice() splice(start,[number, ...items])
- sort()
- reverse()
```javascript
// push() 添加元素至末尾
this.letters.push('abc')
//pop() 删除末尾元素
this.letters.pop()
//shift() 删除第一个元素
this.letters.shift()
//unshift() 在数组最前面添加元素
this.letters.unshift('aaa')
// splice() 删除元素 ;添加元素; 删除元素
/*
splice(start,[number, ...items])
start 开始下标
number 删除/替换数量
...items 替换文本或对象
*/
// 从第2个元素开始,删除0个元素,将这 0个元素替换为“exit”
this.letters.splice(1, 0, "exit")
// sort() 排序(默认升序,可选参数为函数)-该方法会改变数组
this.letters.sort()
// reverse() 反转数组(前边的去后边,后边的去前边)
this.letters.reverse()
// 通过索引值修改值(不会响应),解决方案:splice() / vue.set(修改的对象,索引值,修改后的值)
this.letters[0] = "12"
```
### 高阶函数
```javaScript
const nums = [12,34,231,111,2,78];
// filter函数要求返回布尔值(filter是过滤)
let newNums = nums.filter(function(n){
return n < 100
})
console.log(newNums);//[12, 34, 2, 78]
```
```javaScript
// map函数(map是映射)
let newNums2 = nums.map(function(n){
return n * 2
})
console.log(newNums2);//[24, 68, 462, 222, 4, 156]
```
```javaScript
//map--映射,filter--过滤,reduce--汇总(结果为1个值)
// reduce 函数 ,reduce (callback(累计器,当前值,当前索引,原数组),初始值),典型求兔子数列
let newNums3 = nums.reduce(function(preValue, n){
return preValue + n
},0)
console.log(newNums3);//468
```
### 表单绑定 v-model
1. 原理;
v-bind 绑定一个value属性 , `:value="message"`
v-on指令给当前元素绑定 input 元素, `message = $event.target.value`
```html
```
2. v-model:radio
当存在多个单选框时
```javascript
{{ sex }}
```
3. v-model:checkbox
存在单个复选框的情况
```javaScript
const app = new Vue({
el: '#app',
data: {
isAgree:false
},
methods: {}
})
```
当存在多个复选框时
```javaScript
{{ hobbies }}
const hob = new Vue({
el: '#hob',
data: {
hobbies:[]
},
methods: {}
})
```
4. v-model:select
存在单个下拉列表
```javascript
{{ fruit }}
```
存在多个下拉列表的情况
```html
{{ hobbies }}
```
5. input中的(动态)值绑定
指的是 动态的值的绑定
```html
{{ hobbies }}
```
6. v-model 修饰符
```html
{{ message }}
```
### 组件化
#### 组件基本使用
1. 组件化是Vue中的重要思想
组件化提供了一种抽象,主要是开发出独立可复用的小组件来构造我们的应用
任何的应用都可以被抽象成一颗组件树
组件化优点:可扩展,复用性强,易维护
2. 注册组件的基本步骤
创建组件构造器 - 调用 Vue.extend() 方法创建组件构造器
注册组件(全局/局部组件) — 调用 Vue.component() 方法注册组件
使用组件 — 在Vue实例的作用范围内使用组件
```html
```
3. 全局组件和局部组件
- 注册局部组件
```javascript
...
const app = new Vue({
el: '#app',
data: {},
methods: {},
components: {
// key:value key:组件名,value:组件
cpn:cpnC
}
})
```
4. 父组件和子组件
- 注意子组件必须在父组件上面加载
- 要想在Vue实例中使用组件要么在全局注册 要么在他的实例内注册
```html
```
- 语法糖注册方式(推荐)
注册全局组件
```javascript
Vue.component('my_cpn',{
template: `
...
了解详情
`
})
```
注册局部组件语法糖
```javascript
// 注册局部组件语法糖
const app = new Vue({
el: '#app',
components: {
// key:value key:组件名,value:组件实例
cpn: {
template: `
...
了解详情
`
}
}
})
```
5. 自定义模板分离写法
- 使用script标签(必须添加属性 type="text/x-template" 和 id属性)
```html
```
- 使用template标签
```html
...
用户xxx
...
```
#### 组件访问数据
1. 组件要访问数据应该有自己的 data:{}
2. 组件对象也有自己的data属性(也可以有methods等属性),这个data属性是函数,返回一个对象,对象内部保存着数据
3. 为什么组件 data 是函数且返回对象(调用多次,返回不同地址),本质是将不同的函数返回,而非常量(返回一个内存地址),防止不同的组件对象使用同一个data对象
```javascript
Vue.component('my_cpn',{
template: "#cpn",
data(){
return {
counter:0
}
},
methods:{
increment(){
this.counter++
},
decrement(){
this.counter--
}
}
})
```
#### 组件通信(父组件 --> 子组件)
1. 子组件是不能引用父组件或者Vue实例中的数据的
2. 在开发中,是需要数据从上层传递到下层的(父组件统一发送请求将数组发送给各个子组件)
3. 解决方案:通过props()向子组件传递数据 ; 通过事件想父组件发送消息
4. props 支持多种类型 如:数组、对象、自定义验证函数
```html
```
5. props数据验证
```javascript
const my_cpn = {
template: '#cpn',
// props数组形式(绑定在标签属性内绑定)
props: ['cmovies', 'cmessage'],
// props对象形式
props: {
// 1. 类型限制
cmovies:Array,
cmessage:string ,
// 2.限制类型 提供默认值 是否为必要
cmessage: {
type: String,
default: '默认值内容',
required: true
} ,
cmovies: {
type: Array,// 限制类型为 Object/Array 时,默认值必须是一个函数
default() {
return []
}
}
}
}
```
6. props 驼峰写法
```html
当 props中的树形使用驼峰命名时,标签绑定属性的要采用短横线连接
...
```
#### 组件通信(子组件 --> 父组件)
1. 在子组件中,通过$emit()来触发事件,在父组件中,通过v-on来监听子组件事件
```html
```
#### 组件通信(综合案例)
父子组件(number1,number2)数据互通,修改一个伴随着进行修改
```html
(父)props : {{ number1 }}
(子)data : {{ dnumber1 }}
(父)props : {{ number2 }}
(子)data : {{ dnumber2 }}
```
#### 父子组件访问方式
父组件访问子组件:使用 $children 或 $refs referenvce(引用)
```html
'子组件'
```
子组件访问父组件:使用 $parent / root
```html
cpn 组件
ccpn 组件
```
### 组件化高级-插槽slot
#### 插槽slot理解
组件的插槽:为了让封装的组件更具有扩展性
注意:现在具名插槽和作用插槽都统一使用 v-slot ,缩写为#
```html
{{ message }}
默认值
```
具名插槽的使用
```html
左
中
右
```
#### 编译作用域
父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。
```html
左
中
右
```
#### 作用域插槽
父组件替换插槽的标签,但是内容由子组件来提供
最新语法:插槽上给一个name='标记',绑定:dada='变量',调用时#name='get',{{get.data}}'
原理:绑定在 slot 元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字
理解:父组件引用时加个 template,然后v-slot:(插槽名)="别名",v-slot:可以用缩写"#default"
```html
{{ item }} ---
{{ item }} ---
{{ slot.data.join(' --- ') }} ---
```
### 模块化
常见的模块化规范:CommonJS、AMD、CMD,也有ES6的 Modules
原始的js模块化
```javascript
var ModuleA = (
// 1.定义一个对象
var obj = {}
// 2.在对象内部添加变量和方法
obj.flag = true
obj.myFunC = function(info){
console.log(info)
}
// 3.将对象返回
return obj
)()
if(ModuleA.flag) {
ModuleA.myFunc("hello")
}
```
#### CommonJS
模块化的核心:导入和导出
- 导入
```javascript
let { test,demo,flag } = require('moduleA')
// 等同与
let _ma = require('moduleA')
let sum = _ma.sum(1,3)
```
- 导出
```javascript
module.exports = {
flag:true,
sum(a,b){
return a+b
},
demo(a,b){
return a*b
}
}
```
#### ES6
- 导出 export
```javascript
let flag = true
let name = 'user'
// 直接定义并导出
// export let num = 10
// 利用对象直接导出多个(可以起别名,不希望暴露自己的变量,导入时也必须写别名导入)
// export {
// flag as myflag,
// name as myname
// }
// 导出函数或类
function sum (num1,num2) {
return num1+num2
}
class Person {
run(){
return 'running 3000...'
}
}
export {sum,Person}
```
- 导入 import
1. 使用export指令导出了模块对外提供的接口,就可以通过import命令来加载对应的模块
2. 需要在html代码中引入模块文件,并且类型设置为module
``
3. 导入方式 import用于导入模块中的内容
```javascript
import { flag,name,sum, Person} from "./info.js";
console.log(name)
// 利用 *号代替对象,但必须起别名,使用别名.的方式调用)
import * as info from "./info.js";
console.log(info.name)
```
- export default
1. 使用export default命令,为模块指定默认输出,这样就不需要知道所要加载模块的变量名
2. export default在同一个模块中,不允许同时存在多个
3. 通过export方式导出,在导入时要加{ },export default则不需要
```javascript
const str = "blablabla~";
export default str;
import str from 'a'; //导入的时候没有花括号
```
- 混合导出(理解)
```javascript
const name = "lisi";
const url = "127.0.0.1:3000";
export {
name as fname,
url as myurl
}
export default {
function run(){
return 'running...'
},
flag:true
};
import myff, { fname,myurl } from './info.js';
console.log(myff.flag)
```
### Vue CLI
[Vue CLI 官方指南](https://cli.vuejs.org/zh/guide/installation.html)
使用vue.js开发大型应用时,需要考虑代码目录结构、项目结构和部署、热加载、代码单元测试等,手动完成这些工作效率较低。
#### 1、CLI介绍
1. Command-Line Interface(命令行界面,俗称脚手架)
2. Vue CLI 是官方发布的vue.js项目脚手架,可以快速搭建Vue开发环境和webpack环境配置
3. 前提安装node环境(要求8.9以上版本)、使用了webpack模板`npm install webpack -g`
#### 2、npm切换源(nrm用法)
[简书 nrm用法](https://www.jianshu.com/p/4f9b09c428d1)
#### 3、安装(CLI3):
`npm install -g@vue/cli`
拉取CLI 2.x模板:
Vue CLI >= 3 和旧版使用了相同的 vue 命令,所以 Vue CLI 2 (vue-cli) 被覆盖了。如果你仍然需要使用旧版本的 vue init 功能,你可以全局安装一个桥接工具:
```shell
npm install -g @vue/cli-init
# `vue init` 的运行效果将会跟 `vue-cli@2.x` 相同
vue init webpack my-project
```
#### 4、初始化
- Vue CLI2初始化命令
`vue init webpack my-project`
- Vue CLI3初始化命令
`vue create my-project`
以Vue CLI2为例:
```shell
PS vue init webpack my-project
? Project name vuecli2test //项目名称
? Project description test vue cli2 //项目介绍
? Author //作者
? Vue build standalone //runtime
? Install vue-router? No //是否配置路由
? Use ESLint to lint your code? No //选择js规范
? Set up unit tests No //单元测试
? Setup e2e tests with Nightwatch? No //e2e测试
? Should we run `npm install` for you after the project has been created? (recommended) npm //选择命令行管理工具
```
#### 5.runtime-only与runtime-complier
runtime-only(1.性能更高 2.代码量更少,但是需要安装vue-template-compiler)
`render -> vdom - ui`
runtime-complier
`template -> ast -> render -> vdom - ui`
补充:createElement
createElement() 方法通过指定名称创建一个元素
用法1:createElement('标签',{标签属性},[标签内容])
`createElement('h2',{class:'box'},[createElement('button',['提交'])])`
用法1:createElement()
`createElement({
template:'{{ message }}
',
data() {
return {
message: "hello"
}
}
})`
#### 6.Vue-CLI3
初始化:`vue create 项目名`
配置:
```shell
PS C:\Users\Mrnianj\Desktop\my\Vue\Day06> vue create testvuecli3
Vue CLI v4.5.15
? Please pick a preset: Manually select features //选择配置方式,手动
? Check the features needed for your project: Choose Vue version, Babel, Router, Vuex //选择配置空格选中
? Choose a version of Vue.js that you want to start the project with 3.x
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes //router配置
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files //配置文件是否整合到package.json文件中
? Save this as a preset for future projects? No //是否将当前配置作为模板
```
1. Vue-CLI3与2的区别
- 基于webpack4打造,2是基于webpack3
- 设计原则是 “0配置” ,移除的配置文件根目录下的build和config等目录
- 提供了vue ui命令,提供了可视化配置
- 移除了static文件夹,新增了public文件夹,并且index.html移动到public中
2. Vue-CLI3修改配置方法
方法1:执行`vue ui`,访问http://localhost:8000/
方法2:隐藏的webpack.config.js文件路径(不要更改),要配置在根文件夹下,新建`vue.config.js`文件会自动覆盖配置
```
module.exports = {}
```
### Vue-Router
#### 单页面应用
只有一个主页面的应用(一个html页面),一开始只需要请求并加载一次js、css资源。
所有内容都包含在主页面,对每一个功能模块组件化。
单页应用跳转,就是切换相关组件,仅仅刷新局部资源
#### 改变url不刷新页面
1. URL的hash
URL的hasn也就是锚点(#),本质上是window.location的href属性,可以通过直接赋值location.hash来改变href,但是页面不刷新
```shell
# http://localhost:8080/#/
location.hash="bin"
'bin'
# 需要注意 hash 和 href 的区别
location.href
'http://localhost:8080/#/bin'
location.hash
'#/'
```
2.1 HTML5的history模式:pushState
底层采用栈结构,pushState压栈;back弹栈
```shell
history.pushState({},"","home")
undefined
# http://localhost:8080/#/home
history.pushState({},"","me")
undefined
# http://localhost:8080/#/me
history.back()
undefined
# http://localhost:8080/#/home
```
2.2 HTML5的history模式:replaceState
替换地址,不可返回,没有历史记录
```shell
history.replaceState({},'','me')
undefined
# http://localhost:8080/me
```
2.3. HTML5的history模式:go
history.back(参数),手动实现压栈或弹栈,实现浏览器手动返回功能.参数可以为压栈弹栈的数量
```shell
history.replaceState({},'','me')
undefined
# http://localhost:8080/me
```
补充:
`history.back() == history.go(-1)`
`history.forword() == history.go(1)`
这三个接口等同于浏览器界面的前进后退,在vue配置中,默认配置为hash方式
#### vue-router基础
1. 安装vue-router
`npm install vue-router --save`
2. 在模块化工程中使用它(因为它是插件,可以通过vue.use()安装路由功能)
第一步 导入路由对象,并且调用Vue.use(VueRouter)
第二步 创建路由对象,并且传入路由映射配置
第三步 在vue实例中挂载创建的路由实例
3. 使用vue-router的步骤
第一步 创建路由组件
第二步 配置路由映射:组件和路劲映射关系
第三步 使用路由:通过``和``
``:该标签是vue-router中已经内置的标签,最终会被渲染成a标签
``:根据当前路径,动态渲染组件
#### 使用history模式
vue路由默认情况下,路径的改变使用URL的hash模式,
如果希望使用html5的history模式,需要进行以下配置
```javascript
export default new Router({
routes: [],
// 切换为 history模式
// cli4 改为 history:createWebHistory() 上面导入文件也要改
mode: 'history',
})
```
#### router-link补充
`to=""` 属性指定跳转路径
`tag=""` 属性指定渲染组件类型(注意:vue-cli3.0以上已移除,需要渲染嵌套在标签内写)
`replace` 不会留下 history 记录,后退键不能返回到上一个页面中
`active-class` 指定对应路由匹配成功之后会自动添加router-link-active的calss(修改见下)
```html
首页
export default new Router({
... ,
linkActiveClass:'active'
})
```
#### 路由跳转的两种方式
1. 在 vue-router 中添加to属性,指定跳转路径
2. 在 vue-router 中添加方法,方法中指定路径
```javascript
methods: {
homeClick(){
// push
// this.$router.push('/home')
// history
this.$router.replace('/home')
// 注意:router高版本使用:this.$router.push('/about').catch(err=>{})
}
}
```
3. 补充:重复路由跳转,解决:push('/xxx').catch(err=>{console.log('错误信息',err)}),类似Java的捕获异常
#### 路由重定向
采用 redirect:'url' 重定向操作
```
routes: [
{
path: '/',
name: 'Home',
// 重定向
redirect:'/Home'
}
]
```
#### 动态路由(路由传递参数的一种方式)
在页面的path路径可能是不确定的,如进入用户界面时,希望是/user/auseris或/user/auseris
利用v-bind实现动态绑定属性,这种paht和Component的匹配关系,称之为动态路由(路由传参的一种方式)
User组件
```vue
Hello User
{{ Getuserid() }}
```
路由表
```javascript
export default new Router({
// 3、配置路由表
routes: [
{
path:'/user/:userID',
component: User
}
]
})
```
home.vue
```vue
用户
```
#### 路由;懒加载
- 补充:传统路由定义模式:引用后直接使用
```
const routes = [
{
path>:'/home',
component:Home
},
{
path>:'/about',
component:About
}
]
```
1. 懒加载路由定义模式
```
const routes = [
{
path>:'/home',
component:() => import{'../imports/Home'}
},
{
path>:'/about',
component:() => import{'../imports/About'}
}
]
```
2. 路由懒加载的三种方式:
第一种(结合Vue的异步组件和webpack代码分析):
```
const Home = resolve => {
require.ensure(['../components/Home.vue']),
() => {
resolve(require('../components/Home.vue'))
}
}
```
第二种(AMD写法):
```
const About = resolve => require(['../components/About.vue'],resolve)
```
第三种(ES6中,组织Vue异步组件和webpack的代码分割,常用):
```
const home = () => import('../components/Home.vue')
```
#### 路由嵌套
实现嵌套路由的步骤:
1. 创建对应的子组件,并且在路由映射中使用 children 属性配置
```javascript
// 路由懒加载
const Home = () => import('../components/Home.vue')
const HomeNews = () => import('../components/HomeNews.vue')
const HomeMessage = () => import('../components/HomeMessage.vue')
export default new Router({
// 3、配置路由表
routes: [
{
path:'/home',
component: Home,
children: [
{
path:'news',
component: HomeNews,
},
{
path:'message',
component: HomeMessage,
},
{
path:'',
redirect:'news'
}
]
}
]
})
```
2. 在组件内部使用``标签
```vue
Hello Home
新闻
消息
--------------------------------------------------------
```
#### 路由传参
```
网络协议规范
协议://域名:端口/path?query
Protocol://hostname:port/filepath?query
```
传递参数主要有两种类型:params 和 query
如何使用这两种路由传参 也有两种方式:的方式和javascript代码方式
补充:先记住$route是取值 $router是负责跳转就行了
1. params的类型:
- 配置之路由格式:/router/:id
```javascript
export default new Router({
routes: [
{
path: './user/:id',
component: User
}
]
})
```
- 传递的方式:在path后面追加对应的值
```javascript
// app.vue
用户
```
- 传递后的路径: /router/124,/router/abc,
```javascript
// user.vue
user
$route.params.userID
```
2. uery的类型:
- 配置之路由格式:/router,也就是普通配置
```javascript
export default new Router({
routes: [
{
path: './user',
component: User
}
]
})
```
- 传递的方式:对象中使用query的key作为传递参数
```html
// app.vue
用户
```
#### 导航守卫 (guard)
1. 导航守卫就是路由跳转过程中的一些钩子函数,每个过程都有一个函数 这个函数,能让你操作一些其他的事
2. 导航钩子的三个参数:
to:路由将要跳转的路径信息,信息是包含在对像里边的。
from:路径跳转前的路径信息,也是一个对象的形式。
next:路由的控制参数,常用的有next(true)和next(false)。
3. 前置钩子:在路由跳转之前的回调函数`router.beforeEach(`
4. 后置钩子:... `router.afterEach(`
5. 补充:如果时后置钩子,也就是afterEach,不需要主动调用next()
6. 补充:上面使用的导航守卫,被称为全局守卫(还有路由独享守卫,组件内守卫)
需求:首页title显示首页 ,登录页title显示登录...
实现方法1(利用生命周期函数 created):
```javascript
```
实现方法2(router.beforeEach(()=>{})):
```javascript
const Home = () => import('../components/Home.vue')
...
// 1、通过vue.use(插件),安装插件
Vue.use(Router)
// 创建 router 对象
const router = new Router(
{
// 3、配置路由表
routes: [
{
path: '',
redirect:'/home'//重定向到 home
},
{
path:'/home',
component: Home,
meta: {
title:'首页'
},
children: [
{
path:'news',
component: HomeNews,
},
{
path:'message',
component: HomeMessage,
}
]
},
{
path:'/about',
meta: {
title:'关于'
},
component: About
}
],
// 切换为 history模式
mode: 'history',
linkActiveClass:'active'
}
)
// 导航守卫
router.beforeEach((to,from,next) => {
从 from 跳转到 to
// document.title = to.meta.title
document.title = to.matched[0].meta.title
next()
})
// 3、将router对象传入到vue实例
export default router
```
#### keep-alive和vue-router
1. keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,或者避免被重新渲染(它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。)
2. router-view也是一个组件,如果直接被包在keep-alive中,所有的路径匹配的视图组件都会被缓存
3. 当使用了keep-alive时,activated和deactivated两个两个生命周期函数是有效的
4. 当组件在 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。
5. 注意:activated,deactivated这两个生命周期函数一定是要在使用了keep-alive组件后才会有的,否则则不存在当引入keep-alive的时候,页面第一次进入,钩子的触发顺序created-> mounted-> activated,退出时触发deactivated。当再次进入(前进或者后退)时,只触发activated。
6. keep-alive有两个非常重要的属性:include和exclude
`include`-字符串或者正则表达式,只有匹配的组件会被缓存
`exclude`-字符串或正则表达式,任何匹配的组件都不会被缓存
```html
```
### 生命周期函数
8个生命周期函数,创建、挂载、更新、销毁
created(){} 当组件被注册时会自动进行回调
mounted(){} 当组件中template挂载到dom元素上时会自动进行回调
updated(){} 当界面发生更新(刷新)时
```html
```
### Promise
1. Promise是一种异步编程解决方案(常见异步操作:网络请求)
2. Promise是es6为了避免ajax异步请求导致回调函数嵌套太深,陷入回调地狱
3. async await是promise的语法糖
4. Promise的三种状态
- pending(等待状态)
- fulfill(满足状态),主动调用 resolve() 方法,就处于此状态,并且回回调.then()
- reject(拒绝状态),主动调用 reject() 方法,就处于此状态,并且回回调.catch()
```javascript
new Promise((res,rej) => {
res('/home')
}).then((res) => {
// 原始写法
// return new Promise(res => {
// res (res+'/login')
// })
// 语法糖:简写为
// return Promise.resolve(res+'/login')
// 语法糖:还可以简写为
return data+'/login'
}).then((res,rej) => {
console.log(res);
return Promise.reject('err...')
// 手动抛出异常
throw "err message"
}).catch(rej => {
console.log(rej)
})
```
#### Promise.all
语法: Promise.all(iterable);
用处:并行执行一系列异步操作,返回结果集。
Promise.all(iterable)方法返回一个 [Promise],此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);
如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败 promise 的结果。
```javascript
Promise.all([
new Promise ((resolve,reject) => {
setTimeout(() => {
resolve ('100')
}, 1000);
}),
new Promise ((resolve,reject) => {
setTimeout(() => {
resolve ('200')
}, 500);
})
]).then((results) => {
console.log(results);
})
console.log('end...');
```
### VueX
1. 概念:专为vue.js应用程序开发的状态管理模式。采用了集中式存储管理应用的所有组件状态,并以相应的规则保证状态以可预测的方式变化
2. vueX集成到Vue的官方调试工具devtools,提供了高级调试功能
3. 状态管理:需要多个组件共享的变量全部存储在一个对象中,将这个对象放在顶层Vue示实例中,让其他组件可以调用(多个组件共享某个对象的变量属性)
4. 常用管理对象:用户状态(姓名、位置、登录状态...)、购物车物品、收藏的商品等
5.
state(保存共享状态信息)
mutation(修改保存状态)
Getters(类似计算属性)
Module(针对模块操作)
Action(异步操作)
#### State单一状态树
也叫单一数据源,只能定义一个Store对象,
#### Getters的应用
```javascript
{{ $store.state.counter }}
{{ $store.getters.over20stu}}
共计个数为:{{ $store.getters.over20stuLength}}
{{ $store.getters.moreageStu(20)}}
const store = new Vuex.Store({
state: {
students: [
{id:2102012323,name:"lisi",age:"17"},
{id:2102012324,name:"wangwu",age:"21"},
{id:2102012325,name:"zhangsan",age:"18"},
{id:2102012326,name:"godan",age:"17"}
]
},
getters: {
powerCounter (state){
return state.counter * state.counter
},
over20stu (state){
return state.students.filter((stu) => {
return stu.age >= 18
})
},
// getters中定义的函数可以传入第二个参数,此参数为 getters 本身
over20stuLength (state,getters){
return getters.over20stu.length
},
// 掌握以下高阶用法 ( 返回的是函数,调用.()相当于function(){} )
moreageStu (state){
return age => {
return state.students.filter(stu => {
return stu.age >= age
})
}
}
}
})
```
#### Mutation
1. Mutation状态更新
Vuex中的store状态的更新唯一方式:提交Mutation
Mutation主要包括两部份:
字符串的事件类型(type)
一个回调函数(handle),该回调函数的第一个参数就是state。
2. mutation的定义方式:
```javascript
mutations: {
increment(state){
state.counter++
}
}
```
3. 通过mutation更新:
```javascript
increment: function (){
// 传入事件类型
this.$store.commit('increment')
}
```
4. Mutation传递参数:
在通过 mutation 更新参数时,有可能希望携带一些额外的参数(参数被称为mutation的载荷[Payload])
多个参数则采用对象的形式进行传递,也就是playload时一个对象,再从对象中取出相关参数。
```javascript
//
export default {
name: 'App',
methods: {
addStudent(){
let stu = {id:'12345',name:"lisi",age:56}
this.$store.commit("addStudent",stu)
}
}
}
// index.js
mutations: {
addStudent(state,stu){
state.students.push(stu)
}
}
```
5. Mutation提交风格
常规提交方式:
```javascript
add (obj){
this.$store.commit('increment',obj)
}
```
对象形式提交:
```javascript
add (obj){
this.$store.commit({
type:"increment",//事件类型
stu:obj //数据(传递多个数据会以对象形式调用)
})
}
// index.js
mutations: {
addStudent(state,payload){
//palyload.的形式调用
}
}
```
6. Mutation的响应规则
Vuex的store中的state是响应式的,当state中的数据发生改变时,Vue组件会自动更新
预先在store对象定义的属性是被加入到响应式系统中的,只有加入到响应式系统中的属性才会发生响应式的变化。
当state中定义的对象添加新的属性时,不会被响应。如:`state.info['address']='China'`
解决方法:
通过set方法:`Vue.set(state.info,'address','China')`
该方法第一个参数是要修改的对象名,第二个参数是要增加是属性名,第三个参数是新增加属性的值。
需要注意的是:该方法可以同时被数组和对象使用
补充:删除对象属性: `Vue.delete(state.info,'age')`
7. Mutation常量类型
为了解决方法调用频繁,需要多个文件之间切换的问题。
```javascript
// mutations-types.js
export const INCREMENT = 'increment'
//app.vue
import { INCREMENT } from './store/mutations-types'
//
export default {
name: 'App',
methods: {
addStudent(){
let stu = {id:'12345',name:"lisi",age:56}
this.$store.commit(INCREMENT,stu)
}
}
}
// index.js
import { INCREMENT } from '../store/mutations-types'
const store = new Vuex.Store({
state: {
students: [
{id:2102012323,name:"lisi",age:"17"}
],
},
mutations: {
[INCREMENT] (state , stu){
state.students.push(stu)
}
}
})
```
8. Mutation同步函数中定义异步操作
通常情况下,Vuex要求Mutation中的方法必须是同步方法(主要是当我们使用devtools时,可以帮助我们捕捉mutation的快照,但异步操作难以追踪)
确实需要进行网络请求等异步操作,可以使用sction:
```javascript
// app.vue
//
export default {
name: 'App',
components: {},
methods: {
addkey (){
// 常规更新方法(同步)
// this.$store.commit({
// type: "addkey"
// })
// 异步操作
// this.$store.dispatch 分发 actions-> 调用 mutations->改变 states
this.$store.dispatch('updateStu')
}
}
}
// index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
info: {
name: "lisi"
}
},
mutations: {
addkey (state){
Vue.set(state.info,'id',12)
}
},
actions: {
// context 上下文,此处等于 Store 对象,
// 可以定义第二个形式参数 playload(接收数据)如:updateStu (context,playload)
updateStu (context,playload){
setTimeout(()=>{
context.commit('addkey')
console.log(playload)
},1000)
}
}
})
export default store
```
当同时需要传递参数并且执行回调函数时,官方推荐使用promise,具体用法如下:
```javascript
export default {
name: 'App',
components: {},
methods: {
addkey (){
this.$store
.dispatch('updateStu',"携带的信息")
.then(res => {
console.log("回调函数被执行",res);
})
}
}
}
// index.js
const store = new Vuex.Store({
state: {
info: {
name: "lisi"
}
},
mutations: {
addkey (state){
Vue.set(state.info,'id',12)
}
},
actions: {
updateStu (context,playload){
return new Promise((resolve,reject) => {
setTimeout(()=>{
context.commit('addkey')
},1000)
resolve('传递的数据')
})
}
}
})
```
#### modules
Vue使用单一状态树,许多状态都会交给VueX管理,应用复杂时,store对象就有可能变得臃肿。
VueX允许我们将store分割为模块(Module),而每个模块拥有自己的state、Mutations、actions、getters等
在模块中需要时访问根中的数据时,方法形参可以添加第三个参数(rootState)
模块中需要进行异步操作时,此时actions:{fun(,此处的context){}},此处的context.commit指向的是模块中的mutation
```javascript
// index.js
const moduleA = {
state: {},
mutations: {},
actions: {},
getters: {
update(state,getters,rootState){}
}
}
const store = new Vuex.Store({
modules: {
moudeleA,
...
}
})
store.state.moudeleA //访问moduleA的状态
```
#### vuex的项目结构
store
index.js
actions.js
mutations.js
getters.js
modules/modulesA.js
### 网络封装(axios)
#### 有哪些网络模块可以选择
1. AJAX(基于XMLHttpRequest)
存在的问题:配置调用混乱;编码方式复杂;实际开发中经常被JQuery-Ajax代替
2. JQuery-Ajax
存在的问题:Vue开发中不需要调用jQuery这个重量级框架(1w+行)
3. vue-resource(vue1.x推出)
vue2.0之后不在更新和维护,作者推荐了axios
#### JSONP
使用jsonp的原因主要是为了解决跨域问题,
原理:jsonp通过`
```
6. 拦截器
用与发送请求或者得到响应后(请求成功/失败,响应成功/失败),进行对应处理。