vue x2.0入门基础知识

文章目录

  • 1. vue的介绍
    • 1.1 概念
    • 1.2 设计模式MVVM
    • 1.3 数据双向绑定内在原理
    • 1.4.插值表达式{{}}
  • 2.指令
    • 2.1 v-model
    • 2.2 v-text 与 v-html
    • 2.3 v-bind
    • 2.4 v-on
      • 2.4.1事件修饰符
      • 2.4.2按键修饰符
    • 2.5 v-for
    • 2.6 v-if 与v-show
    • 2.7 条件渲染指令
    • 2.8其它指令
  • 3. computed(计算属性)
  • 4.$nextTick(解决DOM异步更新问题)
  • 5. $set (解决数据响应式问题)
  • 6.watch(监听器)
      • computed与watch的区别
  • 7.filter(过滤器)
  • 8.生命周期
  • 9.组件
  • 10. 通信机制
    • 10.1 父传子
    • 10.2 子传父
    • 10.3 非父子
  • 11. props
  • 12. refs
  • 13. 路由
    • 13.1概念
    • 13.2基本使用
    • 13.3 $route 路由对象
    • 13.4 动态路由
    • 13.5 嵌套路由
    • 13.5 命名路由
    • 13.6 命名视图
    • 13.7 重定向
    • 13.8 组件传参
    • 13.9 导航守卫
    • 13.10 路由组件所独有的两个生命周期钩子
    • 13.11 keep-alive 标签
  • 14. webpack
    • 14.1 介绍
    • 14.2 使用
      • 14.2.1 webpack 命名初始化阶段
      • 14.2.2 webpack 配置文件
        • 14.2.2.1 webpack 打包的两种方式
        • 14.2.2.2 插件 html-webpack-plugin
        • 14.2.2.3 插件 webpack-dev-server
        • 14.2.2.4 示例代码(webpack.config.js)
      • 14.2.3 webpack 打包上线
      • 14.2.4webpack 打包非js文件
        • 14.2.4.1处理 css 文件
        • 14.2.4.2 处理 less 文件
        • 14.2.4.3 处理 图片 文件
        • 14.2.4.4 处理 字体 文件
        • 14.2.4.5 处理 ES6 语法
  • 15. 单文件组件
  • 16. vue-cli vue脚手架
    • 16.1 初始化项目时的问题
  • 17. cnpm 和 yarn
  • 18. Promise
    • 18.1 async 与 await
    • 18.2 resolve与reject
    • 18.3 all与race
    • 18.4 promise的三个状态
  • 19. Vuex
    • 19.1 Vuex的介绍
      • 19.1.1 概念
      • 19.1.2 使用
      • 19.1.3 使用范围
    • 19.2 Vuex的基本使用
      • 19.2.1 vuex的基本使用
      • 19.2.2 vuex的传参
      • 19.2.3 vue和vuex的配合使用
    • 19.3 核心概念
    • 19.4 常用的几个辅助函数
      • 19.4.1 mapGetters
      • 19.4.2 mapMutations
      • 19.4.3 mapActions
  • 20. 反向代理
    • 20.1 说明
    • 20.2 演示跨域问题
    • 20.3 反向代理的原理
  • 21.keep-alive组件
    • 21.1作用
    • 21.2 属性
    • 21.3 生命周期函数

1. vue的介绍

1.1 概念

vue官网称vue.js是渐进式的JavaScript框架,但什么是渐进式?什么是框架呢?

  • 渐进式:vue的渐进式主要体现在它的全家桶(vue + vue-router + vuex)
在项目的开发中,起初是一个简单的demo,使用vue的基础知识就足够了。
但随着项目的开发,页面会越来越多,这时就需要使用vue-router(路由)来管理页面,从而实现组件化开发。
后期数据会逐渐增多,这时就可以使用vuex(状态管理工具)来管理数据。
  • 框架与库的区别参考网址
 库(Lib):一系列函数的集合,需要实现某个功能,由开发人员去调取。类似于自己购买配件,需要自己去组装成一台台式电脑之后才能使用。

框架(Framework):一套完整的解决方案,框架中制定了一套规则,使用框架的时候,只需要按照规则,把代码放到合适的地方,然后框架会在合适的时机,主动调用开发人员的代码。类似于购买了笔记本电脑,只需要按照它给定的方式去使用。

二者核心的区别在于:控制反转。库的控制权在开发人员,但框架的控制权在于框架。

1.2 设计模式MVVM

  • MVC
    Controller负责将Model的数据用View显示出来,换句话说就是在Controller里面把Model的数据赋值给View
M:model(数据层)专门用于操作数据
V:view(视图层)相对于前端来说就是页面
C:controller(控制层)是数据层与视图层沟通的桥梁,用于处理逻辑业务
  • MVVM
    MVVM 提出了 通过 数据双向绑定 让数据自动的双向同步的思想。因为在前端中频繁操作DOM比较消耗性能,因此为优化性能即减少操作DOM,vue就根据MVVM的思想,采用数据驱动视图的模式,以 数据为核心。以后如果想要操作 DOM, 立马想到的不是拿到元素设置,而是数据。
M:model(数据层)
V:view(视图层)
VM:view model(视图模型)
核心 : M <===> VM <===> V

1.3 数据双向绑定内在原理

vue的数据双向绑定(v-model) 是通过 数据劫持 Object.defineProperty() 来实现的,因此本质上vue是单向数据流
注意 :Object.defineProperty() 是 es5 提出来的一个 无法 shim(兼容) 的特性 , 无法兼容ie8以下。

<input type="text" id="txt" />
let obj = {}
let temp
var txt = document.querySelector("#txt")
//V→M
txt.oninput =>{
   obj.name = this.value
}

// M→V
// 参数1 : 要给哪个对象设置属性
// 参数2 : 给对象设置什么属性
// 参数3 : 属性的修饰符
Object.defineProperty(obj,'name',{
   set(newVal){
   	temp = newVal
   	txt.value = newVal
   },
   get(){
   	return temp
   }
})

1.4.插值表达式{{}}

  • 作用:绑定data中的数据,显示到模板上。数据发生变化,视图中展示的数据也会发生变化
  • 注意:双括号中间只能放表达式(运算、方法、三元),不能放语句(例如:if、for、while)

2.指令

指令是HTML标签上特殊的属性,添加额外的功能。vue的指令统一是‘v-’开头

2.1 v-model

作用:实现数据的双向绑定。
使用场景:只能用于表单元素(文本框、单选框、多选框、文本域、下拉框等)
注意:使用在不同的表单元素,绑定的类型也不一样。例如:文本框是文本内容,单选框绑定的是状态(false/true)

2.2 v-text 与 v-html

作用:展示数据
用法类似于innerText与innerHtml,v-text不识别标签,v-html识别标签。与插值表达式实现的效果一样。

2.3 v-bind

作用:动态显示一个属性值
写法:


<div v-bind:title="msg">嗯哼div>

<div :title="msg">嗯哼div>

运用

<style>
	.blue{color:blue}
	.fz{font-size:24px}
style>

<div id="app">
	<div :class="{blue:isBlue,fz:isFz}">嗯哼div>
div>

<script>
	const vm = new Vue({
		el:"#app",
		data:{
			isBlue:true,
			isFz:false
		}
	})
script>
  • 与v-model的区别
v-model v-bind
写法
使用场景 表单元素 任何元素的属性
方向 双向数据绑定 单向M→V

2.4 v-on

作用:注册/绑定事件
写法:


<button v-on:click="fn">嗯哼button>

<button @click="fn">嗯哼button>
  • 事件中的“this”指向vue实例
  • 事件函数带参数传参,要获取事件对象时用$event

2.4.1事件修饰符

官方地址
格式:@事件.事件修饰符 = “事件函数”
范围:修饰任意事件

.prevent .stop .capture .once .self .passive
功能 阻止默认行为 阻止冒泡(添加在子元素) 捕获(添加在父元素) 只触发一次(添加在子元素) 只有点击自己才触发(关闭冒泡和捕获) 用于移动端提高性能,只需判断一次是捕获还是冒泡

2.4.2按键修饰符

官方地址
格式:@事件.按键修饰符 = “事件函数”
范围:修饰按键事件

.enter .up .down .left .right .esc delete
功能 回车 esc键 删除

2.5 v-for

作用:遍历数据,根据数据里元素的个数创建对应个数的标签
注意

  1. 官方推荐使用v-for时加上 key,目的是为了防止就地复用
  2. 默认key的取值是索引index,但使用时,不能改变数据的顺序
  3. key的取值应是数据中唯一固定的值,常取id值,即 :key=‘item.id’

<ul>
	<li v-for="(item,index) in arr" :key="index">{{item}}li>
ul>


<ul>
	<li v-for="(value,key,index) in obj" :key="index">{{key}}:{{value}}li>
ul>


<ul>
	<li v-for="item in arrObj" :key="item.id">{{item.name}}li>
ul>

2.6 v-if 与v-show

作用:控制元素的显示与隐藏
区别:控制方式不同

v-show v-if
显示 display:block 新建节点
隐藏 display:none 删除节点

因为v-if操作的是节点,因此比较消耗性能 ,操作频率高的情况下,不推荐使用v-if

2.7 条件渲染指令

包含v-if、v-else-if、v-else,用法与if(){}else if (){}else(){}类似

<div id="app">
	<p v-if="age >= 18">成年人p>
	<p v-else-if="age >= 12">青少年p>
	<p v-else="age < 12">儿童p>
div>

2.8其它指令

v-pre:不解析,可直接显示 Mustache 标签即“{{ }}”符号
v-once :解析一次
v-cloak :遮盖,可以隐藏未编译的 Mustache 标签直到实例准备完毕。



<div v-cloak>{{ num}}div>

<style>
	[v-cloak]{
		display:none
	}
style>

3. computed(计算属性)

  1. 为什么需要用计算属性?
  • vue中的data里的数据发生改变时,当前页面中所有的指令与表达式都会重新计算,因此操作频繁的情况下比较消耗性能。但有时只需要某一条数据改变而影响得到的结果,为避免性能的消耗,就需要用计算属性。
  1. 什么时候用计算属性?
  • 官方: Vue.js 的内联表达式非常方便,但它最合适的使用场景是简单的布尔操作或字符串拼接。如果涉及更复杂的逻辑,你应该使用计算属性。
  • 根据data中的已知值,想得到一个新值,且新值会根据data里的那个已知值变化而变化时。
  1. 特点
  • 一定有一个返回值(结果)
  • 计算结果会受相关数据的变化而变化,但是不会其它无关数据的影响
  1. 注意点
  • 一定要有一个返回值
  • 不能当方法使用
  • 计算属性不能和data中的数据重名

<div id="app">
      num1 : <input type="text" v-model="num1" /> + 
      num2 :<input type="text" v-model="num2" /> =
      <span>{{ sum }}span>
div>
<script>
      const vm = new Vue({
        el: '#app',
        data: {
          num1: '',
          num2: ''
        },
        computed: {
          sum() {
            return +this.num1 + +this.num2
          }
        }
      })
script>

4.$nextTick(解决DOM异步更新问题)

DOM异步更新,若需获取DOM更新后的数据就需要用setTimeOut(延时器)或者 $nextTick 。但延时器的时间不好把控,因此需要使用 $nextTick。
this. $nextTick()在DOM异步更新结束之后,自动执行回调函数,可在回调函数中获取自己所需的数据。

<div id="app">
      <p>{{ num }}p>
      <button @click="fn">按钮button>
div>
<script>
  const vm = new Vue({
    el: '#app',
    data: {
      num: 100
    },
    methods: {
      fn() {
        console.log(document.querySelector('p').innerText)
        this.num += 1
         // 方式1 : 延时器
         // setTimeout(() => {
         //   console.log(document.querySelector('h1').innerText)
         // }, 1000)
         // 方式2 : $nextTick,DOM更新完毕后,就可以获取DOM数据了
        this.$nextTick(() => {
          console.log(document.querySelector('p').innerText)
        })
      }
    }
  })
script>

5. $set (解决数据响应式问题)

data中存在的数据,vue可监测到,在进行修改时,数据能响应式改变;但data中不存在的数据,数据就不会响应式变化。如果想让data中不存在的数据进行响应式更新,就需要借助于 $set
格式:this. $set(对象,属性,初始值)

this.$set(this.obj,'name','stitch')

6.watch(监听器)

作用:监听数据的变化,可应用于本地持久化
使用:

//简单类型
watch:{
	//参数1:新值
	//参数2:旧值(可省略)
	被监听数据(newVal,oldVal){
		console.log(newVal)
	}
}

//复杂类型(复杂类型监听到的是地址,地址一直未改变,因此监听数据的变化需要深度监听)
//方式1:深度监听
watch:{
	obj:{
		//深度监听
		deep:true,
		//立即监听(非必要)
		immediate:true,
		//处理函数
		handler(newVal,oldVal){
			console.log(newVal.name)
		}	
	}
}
//方式2:直接监听需要的属性
watch:{
	'obj.name'(newVal){
		console.log(newVal)
	}
}

computed与watch的区别

computed是根据一个或多个值(data里的值),通过计算得到一个新值,当data的值发生变化得到的新值随着改变,是多对一或者一对一的关系。别人影响我。
watch监听的是data里的数据,当数据改变时,影响接下来的操作,是一对多的关系。自己改变影响别人。

7.filter(过滤器)

作用:vue.js允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示。

步骤:

  • 先注册
	参数1:过滤器名称
	参数2:回调函数(参数1:需格式化的数据,参数2(可省略):过滤器传过来的参数)
	注意:回调函数一定要有返回值
  1. 全局注册
    
    Vue.filter('filterName', function (value) {
    	return value的处理
    })
    
    new Vue({
    	el:'#app',
     	data:{
     		date: new Date()
     	}
    })
    
  2. 局部注册
    new Vue({
    	el:'#app',
    	data:{
    		date: new Date()
    	}
        filters: {
       	 filterName(value) {
       		return value的处理
       	  }
       }
    })
    
  • 再使用
  1. 双括号插值,格式:{{ 需处理的数据 | 过滤器 }}
    <p> {{ date |  filterName }} p>
    
  2. v-bind表达式(从 2.1.0+ 开始支持)
    <div v-bind:id="rawId | formatId">div>
    

8.生命周期

概念: 生命周期函数又称为钩子函数
注意: 钩子函数到对应阶段时自动调用;命名是规定好的
vue x2.0入门基础知识_第1张图片

钩子函数 阶段 使用场景
beforeCreate 挂载阶段 初始化内部使用的事件,开启生命周期 无法获取data中的数据;加loading事件
created★ 挂载阶段 数据响应式之后 发送Ajax请求;操作data中的数据;获取本地存储数据
beforeMount 挂载阶段 DOM渲染前,数据与模板初始化完成 \
mounted ★ 挂载阶段 DOM渲染完成后 操作DOM元素;发送Ajax请求
beforeUpdate 更新阶段 更新前 获取更新前的数据
updated ☆ 更新阶段 数据更新完成后 获取更新后的数据
beforeDestory 卸载阶段 \
destoryed 卸载阶段 清理开启的定时器;移除手动创建的DOM对象等

9.组件

概念:可复用的UI模块;本质上是一个Vue实例。
注册:


Vue.component('child',{
	template:`<div> child div>`,
	data(){
		return{
		}
	}
})

const vm = new Vue({
	components : {
		child : {
			template : `<div>childdiv>`
		}
	}
})

const child = {  
	template : `<div>div>`
}
const vm = new Vue({
	components : child
})

注意:

 1. 注册组件需要在vue实例前
 2. template只有一个根组件
 3. 配置对象和vue实例中大部分一样
 4. 组件中的data是一个函数,函数里面返回一个对象是组件里的数据,因为我们希望组件被复用,但不希望组件中的数据被复用

组件化开发
概念:将一个页面抽象成一个个独立的组件。
优点:可复用性强
与模块化开发的区别:模块化开发重业务,重逻辑,重功能,而组件化开发重界面/UI。

10. 通信机制

原因:组件是一个封闭的个体,组件之间无法直接获取对方的数据,因此需要组件之间的通信机制来访问数据。

10.1 父传子

实现思路:子组件通过配置项props,自定义一个属性,父组件通过这个属性将数据传递给子组件。

<div id="app">
	
	<child :msg="pmsg">child>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script>
	Vue.component('child',{
		template:`
子组件:{{msg}}
`
, // 2.子组件通过配置项props,指定需接收来的数据 props:{ msg : String } }) const vm = new Vue({ el:'#app', data:{ pmsg:'父组件中的数据' } })
script>

10.2 子传父

实现思路:子组件通过触发自定义事件,利用函数传参的方式,将数据传递给父组件。

<div id="app">
	<p>父组件:{{cmsg}}p>
	
	<child @event="pfn">child>
div>
<script>
	Vue.component('child',{
		template:`
`
, data(){ return{ cmsg:'子组件中的数据' } }, created(){ // 3.触发自定义事件 this.$emit('event',this.cmsg) } }) const vm = new Vue({ el:'#app', data:{ cmsg:'' }, methods:{ // 1.在父组件中准备好一个方法 pfn(cmsg) { this.cmsg = cmsg } } })
script>

vm.$emit( event, arg ) :触发当前实例上的事件,(参数1:事件名,参数2:传递的参数)

10.3 非父子

实现思路:通过事件总线(event bus)为媒介,发送数据的组件触发事件,接收数据的组件注册事件

<div id="app">
	<child1>child1>
	<child2>child2>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script>
	// 1.创建事件总线
	const bus = new Vue()
	
	Vue.component('child1',{
		template:`
child1:
`
, data(){ return{ msg1:'child1发送的数据' } }, methods:{ send(){ // 2.发送数据的组件,触发事件 bus.$emit('transferData',this.msg1) } } }) Vue.component('child2',{ template:`
child2:{{msg2}}
`
, data(){ return{ msg2:'' } }, created(){ // 3.接收数据的组件,注册事件 bus.$on('transferData',(res)=>{ this.msg2 = res }) } }) const vm = new Vue({ el:'#app' })
script>

在这里插入图片描述
注意: 要保证注册事件的代码先执行,触发事件的代码后执行

11. props

  • 单向数据流

    所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
    
    额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。
    
  • 大小写问题

    HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:
    
    
    <blog-post post-title="hello!">blog-post>
    <script>
    Vue.component('blog-post', {
     // 在 JavaScript 中是 camelCase 的
     	props: ['postTitle'],
    	template: '

    {{ postTitle }}

    '
    })
    script>
  • prop校验
    当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。

    props: {
        // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
        propA: Number,
        // 多个可能的类型
     	propB: [String, Number],
    	// 必填的字符串
        propC: {
       		type: String,
     		required: true
    	 },
         // 带有默认值的数字
         propD: {
       		type: Number,
       		 default: 100
        },
         // 带有默认值的对象
       	propE: {
     		type: Object,
      		// 对象或数组默认值必须从一个工厂函数获取
     		default: function () {
       			return { message: 'hello' }
    		 }
      	 },
       	// 自定义验证函数
       propF: {
     		validator: function (value) {
        		// 这个值必须匹配下列字符串中的一个
       			return ['success', 'warning', 'danger'].indexOf(value) !== -1
       	     }
         }
    }
    

12. refs

作用:获取标签/组件
先注册ref,凡是注册过ref的标签/数组,都会被refs收集起来,refs是一个键值对(键:ref值; 值:注册refs的组件或元素)。

<div id="app">
	
	<child ref='c'>child>
div>

<script>
Vue.component('child',{
	template:`
`
, data(){ return{ cmsg:'子组件中的数据' } } }) const vm = new Vue({ el:'#app', mounted(){ //2.使用 //父组件可获取到子组件 console.log(this.$refs.c) //父组件可获取到子组件中的信息 console.log(this.$refs.c.cmsg) } })
script>

注意: 若想一进来就要获取$refs的值,最早也要等DOM元素渲染之后,即mounted中。

13. 路由

13.1概念

学习目的:为了更好管理单页面应用程序(SPA)

路由是浏览器URL中的哈希值,与展示视图内容之间的对应规则。
vue中的路由是由hash和component的对应关系,一个哈希值对应一个组件。

13.2基本使用

  • 准备工作 (3个)

    • 安装 : npm i vue-router

    • 引入 :
      注意: 引入路由一定要在引入vue之后,因为vue-router是基于vue工作的

      <script src="./vue.js">script>
      <script src="./node_modules/vue-router/dist/vue-router.js">script>
      
    • 实例路由对象 + 挂载到vue上

    • 实例路由对象 : const router = new VueRouter()

    • 挂载到vue上 : new Vue({ router,data,methods })

    • 验证路由是否挂载成功, 就看打开页面,最后面有没有个 #/

  • 具体步骤

  1. 入口
    1). 手动:在地址栏手动输入(测试用)
    2). 声明式导航: 
    3). 编程式导航: 
    	跳转:this.$router.push('/one')  有记录,可返回
    	返回:this.$router.back()  
    	替换:this.$router.replace('/one')  没有记录,不可返回(返回到根目录,常用于支付)
    
  2. 规则
    // path : 路由路径
    // component : 将来要展示的路由组件
    routes: [
    	{ path: '/one', component: One }, 
    	{ path: '/two', component: Two }
    ]
    
  3. 组件
  4. 出口
    <router-view />
    

13.3 $route 路由对象

  • 一个路由对象 (route object) 表示当前激活的路由的状态信息,包含了当前 URL 解析得到的信息

  • 一个哈希值路径 对应 一个路由对象

  • $route.path

    • 类型: string
    • 字符串,对应当前路由的路径,总是解析为绝对路径,如 "/detail/4"
    • # 后面?前面的内容
  • $route.params

    • 类型: Object
    • 一个 key/value 对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。
  • $route.name

    • 类型: string
    • 路由匹配规则里面的name值
  • $route.meta 元信息

    • 类型: Object
    • 对应路由匹配规则中的meta。
  • $route.query

    • 类型: Object
    • 参数对象
    • 一个 key/value 对象,表示 URL 查询参数。例如,对于路径 /4?age=21,则有 $route.query.age == 21,如果没有查询参数,则是个空对象。
  • $route.hash

    • 类型: string

    • 当前路由的 hash 值 (带 #) ,如果没有 hash 值,则为空字符串。

  • $route.fullPath

    • 类型: string
    • 全路径
    • 完成解析后的 URL,包含查询参数和 hash 的完整路径。
# 演示 : 
<router-link to="/detail/4?age=21#one">detail</router-link>
{ path: '/detail/:id?', component: detail ,name='detail',meta:{title:'stitch'}} 
在组件内 created打印 this.$route
> fullPath: "/detail/4?id=001#one"
> hash : "#one"
> params : {id:'4'}
> query : {age : 21}
> path : '/detail/4'
> name:'detail'
> meta:{title:'stitch'}

13.4 动态路由

作用:根据不同的条件动态的去配置路由规则。在vue-router的路由路径中,可以使用动态路径参数给路径动态的传值。

动态路由在来回切换时,由于它们都是指向同一组件,Vue不会销毁再重新创建这个组件,而是复用这个组件。

<div id="app">
	
	<router-link to="/detail/1">手机1router-link>
	<router-link to="/detail/2">手机2router-link>
	<router-link to="/detail/3">手机3router-link>
	
	<router-view >router-view>
div>
<script src="../node_modules/vue/dist/vue.js">script>
<script src="../node_modules/vue-router/dist/vue-router.js">script>
<script >
	//3.组件
	//获取参数的三种方式
	const detail = {
		// 方式1 : 组件中直接读取
		template:`
详情页信息:{{$route.params.id}}
`
, // 方式2 : js直接读取 created(){ // 打印只会打印一次,因为组件是复用的,每次进来钩子函数只会执行一次 console.log(this.$route.params.id) }, // 方式3 : 监听路由的参数。为什么不需要深度监听,因为一个路径变化,就会对应一个对新的路由对象(地址变) watch:{ $route(to,from){ console.log(to.params.id) } } } const router = new VueRouter({ //2.匹配规则 routes : [ {path:'/detail/:id?',component:detail} ] }) const vm = new Vue({ el:'#app', router, components :{detail} })
script>

13.5 嵌套路由

作用:嵌套路由就是在路由里面嵌套它的子路由,简而言之,就是让一个组件显示在另一个组件中。

const Parent = {
	//1.在父组件中留一个出口 
	template:`
Parent
`
} const Child = { template:`
Child
`
} const router = new VueRouter({ routes:[{ path:'/parent', component:Parent, //2.子组件的路由的路由规则需放到父组件的children中 /** * path:'/child' =>入口:'/child' * path:'child' =>入口:'/parent/child' */ // children:[{path:'/child',component:Child}] children:[{path:'child',component:Child}] }] })

13.5 命名路由

作用:在创建Router实例的时候,在 routes中给某个路由设置名称name值作为标识,然后就可以通过这个名称来代替path路径去指向某个路由组件


<router-link :to="{name:'one'}">Onerouter-link>
//命名name
routes:[
	{path:'/one',name:'one',component:One}
]

13.6 命名视图

作用:想同时或同级在一个页面中展示多个视图,而不是嵌套展示,则可以在页面中定义多个单独命名的视图

  1. 需要展示几个视图就需要指定几个出口
  2. 配置规则中的component改为components
  3. 出口 没添加name时,显示默认视图
routes:[
	{
		//1.配置名字
		path:'/',components:{
			h:Header,
			m:Main,
			//指定默认显示视图
			default:Footer
		}
	}
]

<router-view name='h'>router-view>
<router-view name='m'>router-view>

<router-view >router-view>

13.7 重定向

const router = new VueRouter({
    routes: [
        //方式1:路径
        { path: '/', redirect: '/one' },
        //方式2:name        
        { path: '/', redirect: { name: 'one' }},
    	//方式3:函数
    	//to:目标路由对象
        { path: '/', redirect: to => {
            //return '/two'
            //可根据路由中的条件,来决定重定向到哪
            if(to.params.id ==1){
            	return {name:'one'}
            }else{
            	return {name:'two'}
            }
        }}
    ]
})

13.8 组件传参

  1. 原始:
    • 入口:/one/1
    • 规则路径:/one/:id?
    • 使用:$route.params.id
  2. 布尔模式:
    • 入口:/one/1
    • 规则路径:/one/:id?
    • 规则:props:true
    • 指定:props:[‘id’]
    • 使用:{{id}}
  3. 对象模式:
    • 规则路径:/one
    • 规则:props:{id:‘1’}
    • 指定:props:[‘id’]
    • 使用:{{id}}
  4. 函数模式:
    • 规则路径:/one
    • 规则:props:to=>{return {bb:‘bbb’}}
    • 指定:props:[‘id’]
    • 使用:{{id}}
    • 优点:可根据to返回的信息,条件显示
const One = {
	//使用
	template:`
组件One:{{id}}
`
, //指定 props:['id','aa','bb'] } const router = new VueRouter({ routes:[ // 方式1:原始 {path:'/one/:id?',component:One} // 方式2:布尔模式 将路由参数id,作为组件one的属性存在 {path:'/one/:id?',component:One,props:true} // 方式3:对象模式 {path:'/one',component:One,props:{aa:'aaa'}} // 方式4:函数模式 {path:'/one',component:One,props:to=>{return {bb:'bbb'}}} ] })

13.9 导航守卫

导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。
to: 即将要进入的目标 路由对象
from: 当前导航正要离开的路由对象
next:1).允许访问:next() 2).不允许访问:next(false) 3).跳转到其它界面访问:next(‘login’)

const isLogin = false

router.beforeEach((to,from,next)=>{
	if(to.name == 'login'){
		next()
	}else{
		// isLogin ? next():next(false)
		isLogin ? next():next('/login')
	}
})
全局前置路由守卫:beforeEach((to,from,next)=>{ })
全局后置路由守卫:afterEach((to,from)=>{ })
独享路由守卫:beforeEnter((to,from,next)=>{ })
组件内路由守卫:beforeRouteEnter((to,from,next)=>{ })  /  beforeRouteLeave((to,from,next)=>{ })  通过路由规则触发才有

13.10 路由组件所独有的两个生命周期钩子

activated路由组件被激活时触发。
deactivated路由组件失活时触发。

13.11 keep-alive 标签

keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 transition 相似,keep-alive 是一个抽象组件:它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中。

14. webpack

  • webpack官网
  • webpack中文网

14.1 介绍

  1. 概念
  • 前端模块化打包(构建)工具
  • WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块、其它的一些浏览器不能直接运行的拓展语言(Scss,less等)以及新语法,并将其转换和打包为合适的格式供浏览器使用。
  1. ** 使用WebPack的原因**
  • 浏览器不识别 SASS、Less ==> 需要对Less/SASS 预编译CSS => 供浏览器使用
  • 项目中的模块化以及互相之间引用依赖包造成文件分散 ==> 需要把各个分散的模块集中打包成大文件,减少HTTP的链接的请求次数
  • 打包成了大文件,体积就变大了 ==> 代码压缩
  • 部分ES6语法有兼容问题 => ES5 => 浏览器使用

  • 以上这些操作以前都是需要我们手动处理,这是非常繁琐的, 这个时候webpack就可以上场了,在webpack里,只要配置好,一下就可以都搞定了
  1. 基本能力
  • 处理依赖:方便引用第三方模块,让模块更容易复用、避免全局注入导致的冲突、避免重复加载或者加载不必要的模块
  • 合并代码:把各个分散的模块集中打包成大文件,减少HTTP的链接的请求次数,优化代码的体积(压缩代码)
  • 各种插件:babel 把 ES6+ 转化为 ES5- 等
  1. 工作原理
  • 简单的说就是分析代码,找到“require”、“import”、“define”等关键词,并替换成对应模块的引用。
  • 在一个配置文件中,指明对某些文件进行编译、压缩、组合等任务。把你的项目当成一个整体,通过一个给定的主文件 (index.js),webpack将从这个文件开始找到你的项目的所有的依赖文件,使用loaders处理他们,最后打包为一个浏览器可 以识别的js文件。
  1. 四个核心概念
  • 入口(entry) : 要打包哪个文件
  • 出口(output) : 要打包到哪里
  • 加载器(loader) : 加载除了js文件其他文件的功能
  • 插件(plugins) : 处理加载器完成不了的功能, 使用插件

14.2 使用

14.2.1 webpack 命名初始化阶段

项目名不能有汉字,不能取名叫 webpack

  1. 创建项目名称并生成 package.json, 命令 : npm init -y
  2. 安装 : npm i -D webpack webpack-cli
webpack  :  webpack 工具的核心包
webpack-cli : 提供了一些在终端中使用的命令
-D(--save-dev) : 表示项目开发期间的依赖,也就是 : 线上代码中用不到这些包了
  1. 创建一个main.js文件
console.log('要被打包了');
  1. package.jsonscripts中,添加脚本
// webpack 是webpack-cli 中提供的命令, 用来实现打包的
// ./main.js 入口文件,要打包哪个文件
 "scripts": {
    "build": "webpack main.js"
  },

  1. 运行 : npm run build
  2. 设置开发状态 : mode
    "build" : "webpack ./main.js --mode development"

如果没有设置 mode 配置项, webpack 会默认提供 生产环境(production);生产环境下, 打包生产的js文件都是压缩后的, 开发环境下代码一般是不压缩的

  • 开发环境 (development) : 开发过程就是开发环境
  • 生产环境 (production) : 线上环境, 也就是 : 项目做好了,发布上线

14.2.2 webpack 配置文件

14.2.2.1 webpack 打包的两种方式
  • 方式 1 : 命令行
"build" : 入口  --output 出口
"build": "webpack ./src/js/main.js --output ./dist/bundle.js  --mode development",
  • 方式 2 : 配置项
第一步 : 项目`根目录`下, 创建一个 `webpack.config.js`文件 (文件名固定死)

第二步 : 在 `webpack.config.js` 中,进行配置
* webpack 是基于 node的 , 所以配置文件符合 node 方式书写配置
* 注意 : 不要再这个文件中使用ES6的的模块化 import语法
* main.js里可以使用,是因为要通过webpack转化为es5的
* 而这个是webpack 的配置文件,它是要转化别人的,所以必须要通过

第三步 : 修改 `package.json` 中的 `scripts` , 脚本命令为: "build": "webpack"

第四步 : 执行命令 : `npm run build`
14.2.2.2 插件 html-webpack-plugin

作用:

  • 能够根据指定的模板文件 (index.html),自动生成一个新的 index.html,并且注入到dist文件夹下
  • 能够自动引入js文件

安装: npm i html-webpack-plugin
配置 :

//第一步: 引入模块
const htmlWebpackPlugin = require('html-webpack-plugin')
//第二步: 配置

plugins: [
  // 使用插件 指定模板
  new htmlWebpackPlugin({
    template: path.join(__dirname, './src/index.html')
  })
]
14.2.2.3 插件 webpack-dev-server

作用 : 为使用 webpack 打包提供一个服务器环境

  • 自动为我们的项目创建一个服务器
  • 自动打开浏览器
  • 自动监视文件变化,自动刷新浏览器…

安装: npm i -D webpack-dev-server
配置:

方式 1 : 命令行配置

  • 脚本 : "dev" : "webpack-dev-server --open --port 3001 --hot"

  • 运行: npm run dev

  • 自动打开: 添加 --open

  • 指定端口号 : 添加 --port 3001

  • 热更新: --hot ( 局部更新 )

方式 2 : 配置文件配置

// hot 不要写在配置文件里面,,不然的话还要配其他插件麻烦
 "dev" : "webpack-dev-server --hot",
  devServer : {
    open : true,
    port : 3001
  }
14.2.2.4 示例代码(webpack.config.js)
const path = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  // 入口
  entry: path.join(__dirname, './src/js/main.js'),
  // 出口
  output: {
    // 出口目录
    path: path.join(__dirname, './dist'),
    filename: 'bundle.js'
  },
    // 开发模式
	mode: 'development'
  
    // 插件
	plugins: [
    // 使用htmlWebpackPlugin插件 指定模板
      new htmlWebpackPlugin({
        template: path.join(__dirname, './src/index.html')
      })
    ]
    // 使用webpack-dev-server插件 
    devServer : {
      open : true,
      port : 3001
    }
  }

14.2.3 webpack 打包上线

  • 开发模式 : npm run dev ==> 不会打包的 ,只会把项目放到服务器里
  • 打包:npm run build 对项目进行打包,生成dist文件
1 执行 : `npm run build`
2 模拟本地服务器 : 安装 : `npm i -g http-server`
3 把dist文件里的内容放到服务器里即可, 直接运行`http-server`

14.2.4webpack 打包非js文件

webpack 只能处理 js 文件,非 js(css.less.图片.字体等)处理处理不了, 借助 loader 加载器

14.2.4.1处理 css 文件
  1. 安装 : npm i -D style-loader css-loader
  2. webpack.config.js 中,添加个新的配置项 module
// loader
module: {
  rules: [
    //1.处理 css
      // 注意点 use执行loader 顺序 从右往左
      // css-loader  :  读取css文件内容,将其转化为一个模块
      // style-loader :拿到模块, 创建一个style标签,插入页面中
    { test: /\.css$/, use: ['style-loader', 'css-loader'] }
  ]
}
14.2.4.2 处理 less 文件
  1. 安装 : npm i -D less-loader less style-loader css-loader
  2. 在 webpack.config.js 中, 配置 module->rules
  { test :/\.less$/, use : ['style-loader','css-loader','less-loader'] },
14.2.4.3 处理 图片 文件
  1. 安装 : npm i -D url-loader file-loader
  2. 在 webpack.config.js 中, 配置 module->rules
// 处理图片
  { test : /\.(jpg|png)$/, use : ['url-loader'] },

**注意:**url-loader (推荐) 和 file-loader 二选一即可

url-loader 默认会将图片转化为 base64 编码格式, 目的:提高性能,减少请求次数。
file-loader 在处理图片时, 会对文件进行重命名 :
原始: background-image: url(…/images/1.jpg);
处理后: background-image: url(9c9690b56876ea9b4d092c0baef31bb3.jpg);

base64 编码格式的图片说明 :

  • 精灵图 : 将一些小图片合并为一张图片,减少请求次数,提高性能
  • 字体图标 :直接将一些小的图片,合并到字体文件中,并且不会失真
  • base64 : 是一种编码格式,能够将图片、文字等常见的文件,转化为 base64 格式,这种字符串格式, 浏览器能够识别并且读取显示到页面中;
  • base64 是一个字符串,也可以直接被内嵌到页面中, 或者 css 中
  • 注意 : 大图片不适合用 base64 处理, 只有小的图标才适合 base64 处理

设置配置:

//方式1 :
{ test : /\.(jpg|png)$/, use : ['url-loader?limit=57417'] }, 
//方式2 : 
{
        test: /\.(jpg|png)$/, use: [
          {
            loader: 'url-loader',
            options: {
              //  比57417这个小 => 转化为base64
              //  大于等于这个57417值 => 不会转base64 内部调用 file-loader 加载图片
              limit: 57417
            }
          }
        ]
      }
14.2.4.4 处理 字体 文件
  1. 安装npm i -D url-loader
  2. 在 webpack.config.js 中, 配置 module->rules
 // 4. 处理字体图标
  { test:/\.(svg|woff|woff2|ttf|eot)$/,use:'url-loader'}
14.2.4.5 处理 ES6 语法
  1. 现在的项目都是使用 ES6 开发的, 但是这些新的 ES6 语法, 并不是所有的浏览器都支持, 所以就需要有一个工具,帮我们转成 es5 语法, 这个就是: babel
  2. babel
  3. Babel is a JavaScript compiler. ==> babel 是一个 JavaScript 编译器
  4. webpack 只能处理 import / export 这个 es6 模块化语法
    而其他的 js 新语法,应该使用 babel 来处理
  5. 比如 : var o = { ...obj } 在谷歌上可以,edge 就不可以
  6. babel 的使用 :
  • 6.1 安装 1 : npm i -D babel-core babel-loader@7
    • babel-core 是 babel 的核心包
    • babel-loader 加载 js 文件, 并将 js 代码内容交给 babel-core 解析为 es5 低版本的 js
  • 6.2 安装 2 : npm i -D babel-preset-env babel-preset-stage-2
    • babel-preset-* 表示能够解析什么版本的 js 语法
    • babel-preset-env : 表示能够解析 es2015,es2016,es2017,es2018 这些标准的语法
    • babel-preset-stage-2 : 用来解析经过会遇到,但是还没有被采纳为标准的语法
    • 比如 : ‘abc’.padStart(10, ‘6’) : 准备 10 位字符,有 abc,前面不够用 6 补充,是 es2017 的语法,
    • babel-polyfill与babel-plugin-transform-runtime 也是做兼容处理的,以前都是用这个,兼容更早的
  • 6.3 在 webpack.config.js 配置
  { test: /\.js$/, use: 'babel-loader', exclude: /node_modules/ }
  • 6.4 在项目根目录中创建 babel 的配置文件,叫:.babelrc
  {
  "presets": [
    "env",
    "stage-2"
  ],

  -----------
  // 暂时不用
  // 如果未来某一天真的用到了polify
    "plugins": [
        ["transform-runtime", {
                "helpers": false,
                "polyfill": true,
                "regenerator": true,
                "moduleName": "babel-runtime"
    }]

15. 单文件组件

后缀为 .vue 的文件

注意 : 单文件组件,无法直接在浏览器中使用,必须经过 webpack 这种打包工具,处理后,才能在浏览器中使用

<template>

template>

<style scoped>
/*scoped:加上之后当前组件内的样式只在当前组件生效*/
/* css代码 */
style>

<script>
export default {
// js代码
}
script>

16. vue-cli vue脚手架

因为 webpack 配置繁琐, 阻止一批想用 vue 但是不会 webpack 的开发人员,所以作者直接将所有 vue 项目中用到的配置全部帮你写好了,这样,就不需要开发人员再去配置基础 webpack 配置项了

  • 安装:
vue版本 安装命令 初始化项目命令
2.0 npm i vue-cli -g vue init webpack 项目名
3.0及以上 npm i @vue/cli -g vue create 项目名/vue ui
  • 查看版本:vue -V

  • 安装过程:

? Project name # 回车	(项目名称)
? Project description # 回车	(项目描述)
? Author  # 回车	(作者)
? Vue build standalone  # => 运行时+编译 => 详见下面的问题1 
? Install vue-router? # Yes		(是否添加路由)
? Use ESLint to lint your code? # Yes 		(是否使用Eslint)
? Pick an ESLint preset Standard  # standard		(使用eslint的什么标准)
? Set up unit tests # No
? Setup e2e tests with Nightwatch? # No
? Should we run `npm install` for you after the project has been created? # (recommended) npm	

16.1 初始化项目时的问题

问题1 : 两种编译模式 和 @

参考 : vue.js => 安装 => 对不同构建本版本的解释

  • 我们选择的是 Runtime + Compiler 模式 : ( 运行时 + 编辑器)
  • 运行时模式 : 用来创建 Vue 实例、渲染并处理虚拟 DOM 等的代码。基本上就是除去编译器的其它一切。
  • 编译器:用来将模板字符串编译成为 JavaScript 渲染函数的代码。
// 需要编译器
new Vue({
  template: '
{{ hi }}
'
}) // 不需要编译器 new Vue({ render (h) { return h('div', this.hi) } })
  • 完整版版本选用 : ES Module (基于构建工具使用) : vue.esm.js
    • build => webpack.base.config.js => 37 行 alias(别名) ‘vue$’: ‘vue/dist/vue.esm.js’,
  • @ : 就是src的绝对路径
    • build => webpack.base.config.js => 38 行 alias(别名) ‘@’: resolve(‘src’),
router/index.js =>
	import HelloWorld from '@/components/HelloWorld'
	import HelloWorld from 'C:/users/.../src/components/HelloWorld'

问题2 : ESLint

  • 概念 : ESLint 是在 JavaScript 代码中识别和报告模式匹配的工具,它的目标是保证代码的一致性和避免错误。

    • 在 vscode等编辑工具 中, 可以提示语法错误

    • 在许多方面,它和 JSLint、JSHint 相似,除了少数的例外:

  • 如何使用 eslint ?

    • 1-安装vscode插件 ESlint
    • 2-vscode 的 settings.json文件添加一些配置
     "vetur.format.defaultFormatterOptions": {
        "prettier": {
          "semi": false,  //不需要分号
          "singleQuote": true,  //使用单引号
          "wrap_attributes": "force-aligned"
        }
      },
    
      // 从这里往下大家都给加上
      "editor.formatOnSave": true, //#每次保存的时候自动格式化
      "eslint.autoFixOnSave": true, // #每次保存的时候将代码按eslint格式进行修复
      "eslint.validate": [
        { "language": "html", "autoFix": true },
        { "language": "vue", "autoFix": true },
        { "language": "javascript", "autoFix": true }
      ],
      "prettier.eslintIntegration": true, // #让prettier使用eslint的代码格式进行校验
      "prettier.semi": false, //#去掉代码结尾的分号
      "prettier.singleQuote": true, //#使用带引号替代双引号
      "javascript.format.insertSpaceBeforeFunctionParenthesis": true,
      "editor.formatOnType": true, //#让函数(名)和后面的括号之间加个空格
      "vetur.format.defaultFormatter.html": "js-beautify-html",
      "vetur.format.defaultFormatter.js": "vscode-typescript"
    
  • 关闭 Eslint :

    • 参考 : config/index.js ==> 26行 : dev.useEslint 设置为false

    • 重启项目: npm run dev

问题3 : vscode安装 格式化插件 Prettier

  • 安装 vscode 插件 Prettier - Code formatter

  • 功能1 : shift + alt + F => 格式化代码

  • 功能2 : 配合 eslint : 见上一个问题的配置

问题4 : eslint 检测警告

`//eslint-disable-next-line` # 忽略下一行的警告  可以使用单行注释/多行注释,其他都是多行注释
`/*eslint-disable*/` # 忽略当前整个文件的警告  需放在文件最前面

`/* eslint-disable no-new */` # 忽略前面是new开头的警告

17. cnpm 和 yarn

  • npm
    npm 是 Node.js 标准的软件包管理器。
  • cnpm
    (1) cnpm跟npm用法完全一致,只是在执行命令时将npm改为cnpm。
    (2) npm安装插件是从国外服务器下载,受网络影响大,可能出现异常。 cnpm 的镜像仓库在国内(淘宝机房),速度会相对快一点。不过现在 npm 加了缓存机制,速度也跟上来了。
    (3) cnpm 安装时不会产生 package-lock.json,并且项目中即使有 package-lock.json,cnpm 也是不管不顾的,只读取 package.json。
    配置:npm install -g cnpm --registry=https://registry.npm.taobao.org
  • yarn
    在npm5.0之前,npm的下载速度较慢,Facebook就写了yarn
    配置: npm i yarn -g
    使用 :安装命令和npm有些不一样,yarn安装用add,例 : yarn add vue

18. Promise

  • 概念: es6提出的一种重要的语法;promise对象用来封装一个异步操作并可以获取其成功/失败的结果值。
  • 优点:
    (1) 支持链式回调,可以解决回调低于问题
    (2) 指定回调函数的方式更加灵活
    基本使用:
const p = new Promise((resolve,reject)=>{
  setTimeout(()=>{
    // 假设操作成功  resolve => then
    // resolve('成功')

    // 假设操作失败  reject => catch
    reject('失败')
  },0)
})

p.then(res=>{
  console.log('then:',res)
}).catch(err=>{
  console.log('catch:',err)
})

promise封装 异步读取多个文件

const fs = require('fs')

function readFiles (filePath) {
  const p = new Promise((resolve, reject) => {
    fs.readFile(filePath, 'utf-8', (err, data) => {
      if (err) {
        reject('读取文件失败')
      }
      resolve(data)
    })
  })
  return p
}

readFiles('./a.txt')
  .then(res1 => {
    console.log(res1)
    return readFiles('./b.txt')
  })
  .then(res2 => {
    console.log(res2)
    return readFiles('./c.txt')
  })
  .then(res3 => {
    console.log(res3)
  })

18.1 async 与 await

  • 作用: 用编写同步代码的形式处理异步代码
  • 使用:
功能 格式
async 修饰一个内部有异步操作的函数 async + 异步函数
await 等待一个异步处理的结果值 await+ 异步操作(promise类型)
  • 注意点:
    1. await必须写在async函数中,但async函数可以没有await
    2. 若await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
    3. async 要加载await 最近的函数(就近原则)
  • 基本使用:
const fs = require('fs')

function readFiles (filePath) {
  const p = new Promise((resolve, reject) => {
    fs.readFile(filePath, 'utf-8', (err, data) => {
      if (err) {
        reject("读取文件失败")
      }
      resolve(data)
    })
  })
  return p
}

async function fn () {
  try {
    let res1 = await readFiles('./a1.txt')
    console.log(res1)
  } catch (err) {
    console.log('读取失败了')
  }

  let res2 = await readFiles('./b.txt')
  console.log(res2)
}
fn()

18.2 resolve与reject

Promise.resolve(value=>{}) :快速返回成功的数据
Promise.regect(reason=>{}):快速返回失败的数据

18.3 all与race

Promise.all(promises=>{ }) :返回一个新的promise,只有所有的promise都成功才成功,有一个失败的promise就失败
Promise.race(promises=>{ }) :第一个完成的promise的结果状态就是最终结果状态

18.4 promise的三个状态

pending: 未完成
resolved: 异步完成成功的结果
rejected: 异步完成失败的结果

promise是微任务,执行代码是先执行宏任务再执行微任务。script与timeout是宏任务,但timeout是下一次的宏任务。

19. Vuex

19.1 Vuex的介绍

19.1.1 概念

  • 状态管理工具

  • 状态即数据, 状态管理就是管理组件中的data数据

  • Vuex 中的状态管理工具,采用了 集中式 方式统一管理项目中组件之间需要通讯的数据

19.1.2 使用

  • 最佳实践 : 只将组件之间共享的数据放在 vuex 中, 而不是将所有的数据都放在 vuex 中 , 也就是说:如果数据只是在组件内部使用的,这个数据应该放在组件中,而不要放在 vuex
  • vuex 中的数据也是响应式的,也就是说:如果一个组件中修改了 vuex 中的数据,另外一个使用的 vuex 数据的组件,就会自动更新 ( vuex 和 localstorage的区别)

19.1.3 使用范围

  • 说明: 项目体量很小,不需要使用 vuex, 如果项目中组件通讯不复杂,也不需要使用 vuex
  • 只有写项目的时候,发现组件通讯多,组件之间的关系复杂,项目已经无法继续开发了,此时,就应该使用 vuex

19.2 Vuex的基本使用

19.2.1 vuex的基本使用

  • 安装 : npm i vuex
  • 引入 : 引入 vuex 之前一定要先引入 vue
  • 实例化 store
    • store 仓库 , 获取数据和操作数据都要经过 store
    • const store = new Vuex.Store()
  • 操作数据
    • 获取数据 : store.state.num
    • 操作数据 : store.state.num = 300
    • 虽然 store.state.count = 300 可以修改值 , 但是vuex 也有严格模式,
    • 添加严格模式 : strict : true,
  • 使用 mutations
    • 注册 : mutations : {}
    • increament(state) { state.count = 20; }
    • 默认第一个参数永远是 state
    • 触发事件 : store.commit('increament')

19.2.2 vuex的传参

  • 触发事件 :
 // 传参最好传一个对象,多个值查看方便
 store.commit('increament', {
     num: 400
 })
  • 事件
// payload 载荷
 increament(state, payload) {
 	state.count = payload.num
 }

19.2.3 vue和vuex的配合使用

需求 : 有个h1显示数字的标题, 点击按钮累加数字

  • 先用vue做出来效果
  • 再用vuex和vue配合使用
    • 实例化vuex的store
    • 实例化vue
    • 把store挂载到vue上
  • 操作数据
    • h1展示数据 :

      {{ $store.state.num }}

    • 点击触发事件修改数据 : this.$store.commit('addNum')
    • addNum(state) { state.num++ }

19.3 核心概念

  1. state: 状态,相当于data
  2. mutations: 相当于methods,只能写同步操作,严格模式 strict:true
    执行方法:this.$store.commit('方法名');
    写法:参数1:state
  3. actions: 写异步操作,监听mutations
    执行方法:this.$store.dispatch('方法名');
    写法:参数1:context,相当于store
  4. getters: 相当于computed(计算属性)
  5. module: 分模块存储数据

19.4 常用的几个辅助函数

19.4.1 mapGetters

  • 引入 : import { mapGetters } from "vuex";
computed:{
	...mapGetters(['方法名'])
}

19.4.2 mapMutations

methods:{
	...mapMutations(['方法名'])
}

19.4.3 mapActions

methods:{
	...mapActions(['方法名'])
}

20. 反向代理

20.1 说明

  • 解决跨域问题的方式 :
    • JSONP == > 只能处理 get 方式
    • CORS ==> 处理自己的服务器
    • 反向代理 ==> 也很常用
  • 说明
    1. 演示跨域问题
    2. 反向代理的原理
    3. 脚手架vue-cli 生成的项目中如何使用反向代理

20.2 演示跨域问题

  1. 代码 :

    // 演示跨域问题
    /* eslint-disable */
    import axios from 'axios';
    
    axios.get('https://api.douban.com/v2/movie/in_theaters').then(res => {
     console.log(res)
    })
    
  2. 报错 :

    Access to XMLHttpRequest at 'https://api.douban.com/v2/movie/in_theaters' from origin 'http://localhost:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
    
  3. 报错原因

    项目运行在  http://localhost:8080
      //  I  Your application is running here: http://localhost:8080  
    发送ajax请求 : //域名是 https://api.douban.com/v2/movie/in_theaters
    因此出现跨域问题
    

20.3 反向代理的原理

  • 修改 config/index.js 配置文件

    proxyTable: {
      '/myapi': {
        // 代理的目标服务器地址
        // https://api.douban.com/v2/movie/in_theaters
        // /myapi/movie/in_theaters
        target: 'https://douban.uieee.com/v2/',
        pathRewrite: { '^/myapi': '' }, // 替换的请求地址
        // 设置https
        secure: false,
        changeOrigin: true // 允许跨域 (必须设置该项)
      }
    },
    
  • 最终代码

    // axios.get('https://api.douban.com/v2/movie/in_theaters').then(res => {
    axios.get("http://localhost:8080/api/movie/in_theaters").then(res => {
      console.log(res);
    });
    
  • 最终配置 cli2.x :

      proxyTable: {
          '/myapi': {
            // 代理的目标服务器地址
            // https://api.douban.com/v2/movie/in_theaters 
            // /myapi/movie/in_theaters
            target: 'https://douban.uieee.com/v2/',
            pathRewrite: { '^/myapi': '' },
    
            // 设置https
            secure: false,
            // 必须设置该项
            changeOrigin: true
          }
        },
    
  • 最终配置 3.X

    • 根目录下 新建一个 vue.config.js
    • 拷贝如下代码
    module.exports = {
      devServer: {
        proxy: {
          '/myapi': {
            // 代理的目标服务器地址
            // https://api.douban.com/v2/movie/in_theaters
            // /myapi/movie/in_theaters
            target: 'https://douban.uieee.com/v2/',
            pathRewrite: { '^/myapi': '' },
    
            // 设置https
            secure: false,
            // 必须设置该项
            changeOrigin: true
          }
        }
      }
    }
    
    // 使用
    axios.get('http://localhost:8080/myapi/movie/in_theaters').then(res => {
      console.log(res)
    })
    axios.get('/myapi/movie/in_theaters').then(res => {
      console.log(res)
    })
    
    
  • 重新启动 : npm run dev (配置vue.config.js 都需要重启项目)

21.keep-alive组件

21.1作用

keep-alive是vue内置的一个组件,而这个组件的作用就是能够缓存不活动的组件,我们能够知道,一般情况下,组件进行切换的时候,默认会进行销毁,如果有需求,某个组件切换后不进行销毁,而是保存之前的状态,那么就可以利用keep-alive来实现。

21.2 属性

  1. include 值为字符串或者正则表达式匹配的组件name会被缓存。
  2. exclude 值为字符串或正则表达式匹配的组件name不会被缓存。

被缓存的路由,第一次进入页面的时候会调用 created() 方法,第二次进入页面时就不会再调用 created() 方法了,因为页面被缓存起来了。那么我们如果页面改动了,怎么刷新页面呢?虽然 created() 方法不会被调用,但是activated、deactivated这两个生命周期钩子函数会被执行。也就是我们的接口可以写在 activated() 方法中。

// 将缓存 name 为 index 或者 home 的组件,结合动态组件使用
<keep-alive include="index,home">
     <router-view :key="key" />
</keep-alive>

21.3 生命周期函数

被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated 与 deactivated

1. activated
   在 keep-alive 组件激活时调用
   该钩子函数在服务器端渲染期间不被调用

2. deactivated
   在 keep-alive 组件停用时调用
  该钩子函数在服务器端渲染期间不被调用

你可能感兴趣的:(vue.js,前端,javascript,webpack)