# 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) 生命周期图示: ![生命周期图示](https://v3.cn.vuejs.org/images/lifecycle.svg) ## 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
{{ baidu.text }}
``` #### 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 }}

``` #### 补充 组件的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 ... ``` #### 组件访问数据 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
    ``` #### 父子组件访问方式 父组件访问子组件:使用 $children 或 $refs referenvce(引用) ```html
    ``` 子组件访问父组件:使用 $parent / root ```html
    ``` ### 组件化高级-插槽slot #### 插槽slot理解 组件的插槽:为了让封装的组件更具有扩展性 注意:现在具名插槽和作用插槽都统一使用 v-slot ,缩写为# ```html
    ``` 具名插槽的使用 ```html
    返回
    ``` #### 编译作用域 父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。 ```html
    返回
    ``` #### 作用域插槽 父组件替换插槽的标签,但是内容由子组件来提供 最新语法:插槽上给一个name='标记',绑定:dada='变量',调用时#name='get',{{get.data}}' 原理:绑定在 slot 元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字 理解:父组件引用时加个 template,然后v-slot:(插槽名)="别名",v-slot:可以用缩写"#default" ```html
    ``` ### 模块化 常见的模块化规范: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 ``` 路由表 ```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 ``` #### 路由传参 ``` 网络协议规范 协议://域名:端口/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 ``` 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. 拦截器 用与发送请求或者得到响应后(请求成功/失败,响应成功/失败),进行对应处理。