Coderwhy老师的Vue知识量化课笔记

Vue知识量化

邂逅Vue

认识Vue

为什么学习Vue

  • 你的公司正要将原有的项目使用Vue进行重构
  • 你的公司新项目决定使用Vue技术栈
  • 现在的前端招聘需求中,10个里面有8个需要对Vue有或多或少的要求
  • 目前前端必备的技能

简单认识Vue

  • 声明式编程(Js属于命令式编程)
  • 渐进式框架
    • 渐进式框架意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验
    • 如果你希望将更多的业务逻辑使用Vue实现,那么Vue的核心库以及其生态系统
    • 不如Core+Vue+router+Vuex,也可以满足你各种各样的需求
  • Vue有很多特点和Web开发中常用的功能
    • 解耦视图和数据
    • 可复用的组件
    • 前端路由技术
    • 状态管理
    • 虚拟DOM

Vue的MVVM

Vue的MVVM

Vue基础

Vue的options选项

实例:el

  • 类型:strong丨HTMLElement
  • 作用:决定之后Vue实例会管理哪一个DOM

数据:data

  • 类型:Object丨Function(组件当中data必须是一个函数)
  • 作用:Vue实例对应的数据对象

事件:methods

  • 类型:{key:string:function}
  • 作用:定义属性Vue的一些方法,可以在其他地方调用,也可以在指令中使用

声明周期函数:computed

  • 类型:Function
  • 作用:在某种情况下,需要对数据进行转化后再显示,或者需要将多个数据结合起来进行显示
  • 计算属性默认只有getter,不过在你需要的时候也可以提供setter

Vue的生命周期

Vue的生命周期

模板语法

插值操作(渲染的方式)

  • Mustache语法
    • <div>{{data}}</div>
    • 不仅仅可以直接写变量,也可以写一些简单的表达式
  • v-once
    • <div v-once>{{data}}</div>
    • 只渲染一次,不会随着数据的变化而改变
  • 事件监听
  • v-html
    • <div v-html="data"></div>
    • 会将string的html解析出来并进行渲染
  • v-text
    • <div v-text="data"></div>
    • 与Mustache比较相似,都是将数据显示在界面中
  • v-pre
    • <div v-pre="data"></div>
    • 跳过编译过程,取消转义,显示原本的内容
  • v-clock
  • <div v-clock></div>
  • 在Vue解析之前,隐藏未解析的内容

绑定属性:v-bind

  • 作用:动态绑定属性
  • 缩写::
  • 动态绑定class
    • 对象语法:<div :class="{active: isActive}"></div>
    • 数组语法:<div :class="[activeClass, errorClass]"></div>
  • 动态绑定style
    • 对象语法:<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
    • 数组语法:<div :style="[baseStyles, overridingStyles]"></div>

事件监听:v-on

  • 作用:绑定事件监听器
  • 缩写:@
  • 参数问题
    • 如果该方法不需要额外参数,那么方法后的()可以不添加
    • 如果方法本身有一个参数,那么会默认将原生事件event参数传递进去
    • 如果需要同时传入参数与event,可以通过$event参数传递进去
  • v-on的修饰符
    • .stop
      • 作用:阻止事件冒泡
      • 语法:<button @click.stop="doThis"></button>
    • .prevent
      • 作用:阻止默认事件
      • 语法:
      1. 默认:<button @click.prevent="doThis"></button>
      2. 没有表达式:<button @submit.prevent></button>
    • keyup
      • 作用:键修饰符
      • 语法:
      1. 键别名:<input @keyup.enter="onEnter">
      2. 键代码:<input @keyup.13="onEnter">
    • .once
      • 作用:点击回调只会执行一次
      • 语法:<button @click.once="doThis"></button>

v-if和v-else-if`和v-else

  • 可以根据表达式在DOM中进行渲染或销毁元素或组件
  • v-if后面的条件为false时,对应的元素及子元素不会进行渲染

v-if和v-show的区别

  • v-show会把DOM的样式display更改为none
  • v-if会把DOM进行销毁删除

遍历循环:v-for

  • 语法:
    • 没有索引值(下标值):<li v-for="item in array">{{item}}</li>(如果只要获取一个值,那么获取到的就是value)
    • 获取索引值:<li v-for="(item, index) in array"></li>
    • 获取键值对的name和value:<li v-for="(item,key) in array">{{item}}-{{key}}</li>
    • 获取index和键值对的name和value:<li v-for="(item,key,index) in array">{{item}}-{{key}}-{{index}}</li>
  • :key:
    • 官方推荐在使用v-for时,给对应元素或组件添加一个:key的属性
    • 作用:
      • 做唯一标识
      • 高效的更新虚拟DOM

数组中哪些方法是响应式的

  • .push():
    • 作用:向数组的末尾添加一个或多个元素,并返回新的长度。
    • 语法:arrayObject.push(newelement1,newelement2,....,newelementX)
参数描述
newelement1必需。要添加到数组的第一个元素。
newelement2可选。要添加到数组的第二个元素。
newelementX可选。可添加多个元素。
  • .pop():
    • 作用:删除并返回数组的最后一个元素。
    • 语法:arrayObject.pop()
  • .shift:
    • 作用:把数组的第一个元素从其中删除,并返回第一个元素的值。
    • 语法:arrayObject.shift()
  • unshift():
    • 作用:向数组的开头添加一个或更多元素,并返回新的长度。
    • 语法:arrayObject.unshift(newelement1,newelement2,....,newelementX)
参数描述
newelement1必需。向数组添加的第一个元素。
newelement2可选。向数组添加的第二个元素。
newelementX可选。可添加若干个元素。
  • splice()
    • 作用:splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。
    • 语法:arrayObject.splice(index,howmany,item1,.....,itemX)
参数描述
index必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany必需。要删除的项目数量。如果设置为 0,则不会删除项目。
item1, …, itemX可选。向数组添加的新项目。
  • .reverse():
    • 作用:用于颠倒数组中元素的顺序。
    • 语法:arrayObject.reverse()

双向绑定:v-model

  • 原理
    • v-model其实是一个语法糖,他的背后本质是包含两个操作
      • v-bind绑定一个value属性
      • v-on指令给当前元素绑定input事件
      • 等同于<input type=:"text" :value="message" @input="message = $event.target.value">
  • 修饰符
    • lazy修饰符
      • 默认情况下,v-model默认是在input事件中同步输入框的数据的, lazy修饰符可以让数据在失去焦点挥着回车时才会更新
    • munber修饰符
      • 默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串进行处理,munber修饰符可以让在输入框中输入的内容自动转成数字类型
    • trrm修饰符
      • 可以过滤内容左右两边的空格
  • 结合radio单选框使用
     <div id="app">
     	<label for="male">
    		<input type="radio" :value="abc" v-model="gender" id="male">男
    	</label>
     	<label for="female">
    		<input type="radio" :value="female" v-model="gender" id="female">女
    	</label>
    	<p>您的选择:{{gender}}</p>
     </div>
     <script src="vue.js"></script>
     <script>
     	let app = new Vue({
     		el: '#app',
     		data: {
     			gender: '',
     			abc: 'male'
     		}
     	})
     </script>
    
  • 结合checkbox复选框使用
     <div id="app">
    	<!--
    		单个复选框:
    		v-model即为布尔值。
    		此时input的value并不影响v-model的值。
    	-->
     	<label for="check">
     		<input type="checkbox" v-model="checked" id="check"/>同意协议
     	</label>
     	<p>是否选中:{{checked}}</p>
     	<!--
     		多个复选框:
     		当时多个复选框时,因为可以选中多个,所以对应的data钟属性是一个数组。
     		当选中某一时,就会将input的value添加到数组中。
     	-->
     	<label>
     		<input type="checkbox" v-model="hobbies" value="篮球"/>篮球
     	</label>
     	<label>
     		<input type="checkbox" v-model="hobbies" value="足球"/>足球
     	</label>
     	<label>
     		<input type="checkbox" v-model="hobbies" value="台球"/>台球
     	</label>
     	<p>您选中的爱好:{{hobbies}}</p>
     </div>
    
  • 结合select下拉框使用
    <!-- 和checkbox一样,select也分单选和多选两种情况 -->
    <!--
    	单选:只能选中一个值
    	v-model绑定的是一只。
    	当我们选中option中的一个时,会将他对应的value复制到mySelect中
    -->
    <select v-model="mySelect">
    	<option value="apple">苹果</option>
    	<option value="orange">桔子</option>
    	<option value="banana">香蕉</option>
    </select>
    <p>您最喜欢的水果:{{mySelect}}</p>
    <!--
    	多选:可以选中多个值
    	v-model绑定的是一个数组。
    	当选中多个值时,就会将选中的option对应的value添加到数组mySelect中
    -->
    <select v-model="mySelects" multiple>
    	<option value="apple">苹果</option>
    	<option value="orange">桔子</option>
    	<option value="banana">香蕉</option>
    </select>
    <p>您最喜欢的水果:{{mySelects}}</p>
    

组件化开发

什么是组件化?

  • 如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展。
  • 但如果,我们将一个页面拆成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就会变得非常容易了。

Vue的组件化思想

  • 组件化是Vue中的重要思想。
  • 他提供了一种抽象,让我们可以开发出一个个独立且可以复用的小组件来构造我们的应用。
  • 任何应用都会被抽象成一颗组件数

    组件数

  • 组件化思想的应用
    有了组件化思想,我们就要在开发过程中利用好他,尽可能的将页面拆分成一个个个小的、可复用的组件,这样我们的代码更方便组织和管理,并且扩展性也更强。

组件使用的三个步骤

<div id="app">
	<!--
		步骤三:
		使用组件,
		在Vue的实例的作用范围内使用该组件。
	-->
	<my-cpn/>
</div>

<script>
	/*
		步骤一:
		创建组件的构造器,
		调用`Vue.extend()`方法创建组件构造器。
	*/ 
	const myComponent = Vue.extend({
		template: `
			<div>
				<h2>组件标题</h2>
				<p>组件内容</p>
			</div>
		`
	})
	/*
		步骤二:
		注册组件,
		调用Vue.component()来注册组件,并且定义组件标签的名称。
	*/
	Vue.component('my-cpn', myComponent)
</script>

父组件与子组件

<div id="app">
	<parent-cpn/>
</div>

<script>
	// 1.创建一个组组件构造器
	const childComponent = Vue.extend({
		template: `
			<div>我是子组件</div>
		`
	})
	// 2.创建一个父组件构造器
	const = parentComponent = Vue.extend({
		template: `
			<div>
				<p>我是父组件的内容</p>
				<child-cpn/>
			</div>
		`,
		// 在父组件内引用子组件
		components: {
			'child-cpn': childComponent
		}
	})
	let app = new Vue({
		el: '#app',
	 	// 引用父组件
		components: {
			'parent-cpn': parentComponent
		}
	})
</script>
  • 组件和组件之前存在层级关系
  • 而其中一种非常重要的关系就是父子组件关系

组件的语法糖注册方式

// 方法一
Vue.component('my-cpn', {
	template: `
		<div>组件内容</div>
	`
})
// 方法二
let app = new Vue({
	el: '#app',
	compoments: {
		'my-cpn': {
			template: `
				<div>组件内容</div>
			`
		}
	}
})
// 方法三
const myComponent = Vue.extend({
	template: `
		<div>组件内容</div>
	`
})
Vue.component('my-cpn', myComponent)
// 方法四
const myComponent = Vue.extend({
	template: `
		<div>组件内容</div>
	`
})
let app = new Vue({
	el: '#app',
	compoments: {
		'my-cpn': myComponent
	}
})
  • Vue为了简化注册组件的过程,提供了注册的语法糖
  • 主要省去了调用Vue.extend()的步骤,直接使用一个对象来代替

组件模板的分离写法

  • 将组件的HTML分离写出来,然后挂载到对应组件上,必然始结构变的更加清晰。
  • Vue使用了<script>标签和<templat>标签两种方案来定义组件的HTML内容

组件的数据存放

  • 组件是一个单独功能模块的封装,这个模块有属于自己的html模板,也可以有组件自己的data,有自己保存数据的地方。
  • 组件对象也有data属性,只是这个data属性必须是一个函数,而且这个函数返回一个对象,对象内部保存着数据。

父子组件的通信

  • 子组件是不能引用父组件或者Vue实例的数据的。
    在开发中,往往一些数据需要从上层传递到下层。
    比如在一个页面中,从服务器请求到了很多数据。
    其中一部分数据,并非是组件来展示的,而是需要下面的子组件进行展示。
    但是这个时候,不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)
  • 如何进行父子组件之间的通信

    父子组件之间的通信

    • 父组件通过components向子组件传递数据,使用选项props来声明需要从父组件接收到的数据,props的值有两种方式:

      • 字符串数组:数组中的字符串就是传递时的名称。
      • 对象,对象可以设置传递时的类型,也可以设置默认值等。
      <div id="app">
      	<!--
      		2.通过
      		:message="message"
      		将data中的数据传递给了props
      	-->
      	<child-cpn :message="message"/>
      </div>
      <template id="childCpn">
      	<!--
      		4.将props中的数据
      		渲染到子组件中
      	-->
      	<div>显示的信息:{{message}}</div>
      </template>
      <script>
      	let app = new Vue({
      		el: '#app',
      		/*
      			1.Vue
      			实例中的data
      		*/ 
      		data: {
      			message: 'hello world'
      		},
      		components: {
      			'child-cpn': {
      				template: '#childCpn',
      				/*
      				3.获取父组件通过
      				:message="message"
      				得到的数据
      				*/
      				props: ['message']
      			}
      		}
      	})
      </script>
      
    • 通过事件向父组件发送消息

      <div id="app">
      	<!--
      		发生两个事件时,
      		调用同一个函数
      		changeTotal
      	-->
      	<child-cpn @increment="changeTotal" @decrement="changeTotal"/>
      	<h2>点击次数:{{total}}</h2>
      </div>
      
      <template id="childCpn">
      	<div>
      		<button @click="increment">+1</button>
      		<button @click="decrement">-1</button>
      	</div>    
      </template>
      
      <script>
      	let app = new Vue({
      		el: '#app',
      		data: {
      			total: 0
      		},
      		methods: {
      			changeTotal(counter) {
      				this.total = counter
      			}
      		},
      		components: {
      			'child-cpn': {
      				template: '#childCpn',
      				data() {
      					return {
      						counter: 0
      					}
      				},
      				/*
      					子组件发出事件
      					在使用child-cpn使用
      					通过@increment和@decrement监听事件
      				*/
      				methods: {
      					increment() {
      						this.counter++;
      						this.$emit('increment', this.counter)
      					},
      					decrement() {
      						this.counter--;
      						this.$emit('increment', this.counter)
      					}
      				}
      			}
      		},
      	})
      </script>
      
      • 在子组件中,通过$emit()来触发事件。
      • 在父组件中,通过v-on来监听子组件事件。
    • 传递的验证方式

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

组件访问

父组件访问子组件

  • children:this.$children,返回一个数组,包含所有的子组件(不推荐使用)
  • refs:this.$refs,通过标签绑定ref使用(推荐使用)

子组件访问父组件

  • parent:this.$parent,返回子组件的上级父组件
  • root:this.$root,返回当前子组件上的根组件

插槽:slot

  • slot可以让封装的组件更加具有扩展性,并且可以决定组件内部的展示内容
  • 插槽的基本使用:<slot></slot>
  • 插槽的默认值:<slot>button</slot>
  • 如果有多个值,同时放入到组件进行替换是,它会一起放到slot中去替换掉

具名插槽

  • 插槽内容
    <template id="mycpn">
    	<div>
    		<slot name="left">我是左侧</slot>
    		<slot name="center">我是中间</slot>
    		<slot name="right">我是右侧</slot>
    	</div>
    </template>
    
    <script>
    	Vue.component('my-cpn', {
    		template: '#mycpn'
    	})
    </script>
    
  • 渲染内容
    <div>
    	<!--
    		没有传入任何内容
    		得到
    		我是左侧 我是中间 我是右侧
    	-->
    	<mycpn/>
    	<!--
    		没有某一个内容
    		得到
    		我是返回 我是中间 我是右侧
    	-->
    	<mycpn>
    		<span slot="left">我是返回</span>
    	<mycpn/>
    	<!--
    		没有所有内容
    		得到
    		我是返回 我是标题 我是菜单
    	-->
    	<mycpn>
    		<span slot="left">我是返回</span>
    		<span slot="center">我是标题</span>
    		<span slot="right">我是菜单</span>
    	<mycpn/>
    	
    </div>
    
  • 当子组件的功能复杂时,子组件的插槽可能不止一个,这个时候就需要给插槽起一个名字
  • 具名插槽的使用
    • 给slot元素一个name属性:<slot name="myslot"></slot>

编译作用域

  • 父组件模板的所有东西都会在父级作用域内编译。
  • 子组件模板的所有东西都会在子级作用域内编译。

模块化开发

常用的模块化开发

  • CommonJS
    • 导出方式:
      module.exports = {
      	flag: true,
      	test(a, b) {
      		return a + b
      	},
      	dome(a, b) {
      		return a* b
      	}
      }
      
    • 导入方式:
      // CommonJs
      let { test, dome, flag } = require('moduleA')
      
      // 等同于
      let _mA = require('moduleA')
      let test = _mA.test
      let demo = _mA.demo
      let flag = _mA.flag
      
  • AMD
  • CMD
  • ES6的Modules

webpack

认识webpack

webpack是一个现代的JavaScript应用的静态模块打包工具

在这里插入图片描述

webpack的安装

  • 安装webpack首先需要安装node.js,node.js自带了软件包管理工具npm
    • 查看自己的node版本:node -V
  • 安装webpack:
    • 全局安装:npm install webpack -g
    • 局部安装:npm install webpack --save-dev
    • 为什么安装之后还需要局部安装?
      • 在终端直接执行webpack命令,使用的是全局安装的webpack;
      • 当在package.json中定义了script时,其中包含了webpack命令,那么使用的就是局部webpack
      • 查看webpack版本:webpack --version

webpack的起步

  • 文件与文件夹解析

    文件与文件夹解析

webpack的配置

  • 需要引入node的path模块
    • 第一步:由于path属于node里的系统模块,所以需要将模块进行npm init初始化。初始化完成后会生成package.json文件
      • package.json内容解析
        • name:项目的名字
        • version:项目的版本号
        • description:项目的描述
        • entry pointer:项目入口文件 没有的直接回车跳过
        • test command:测试命令 后面可直接用npm执行的一句话,可以先不写到生成完的json文件中去改
        • git repository:仓储地址 比如在github上的
        • keywords:关键字
        • author:作者姓名。
        • license:(ISC) 授权证书 按照默认的走 直接回车
        • homepage:项目的官网 url 。
        • contributors:项目的其他贡献者姓名。
        • dependencies:依赖列表。如果依赖包没有安装,npm 会自动将依赖包安装在 node_module 目录下。
        • repository:代码存放的地方的类型,可以是 git 或 svn,git 可在 Github 上。
        • main - main 字段是一个模块ID,它是一个指向你程序的主要项目。就是说,如果你包的名字叫 express,然后用户安装它,然后require(“express”)。
        • scripts:配置终端的脚本以及它的版本
      • 第二步:将入口路径(绝对路径)与出口路径放置配置文件webpack.config.js
        const path = require('path')
        
        moudle.exports = {
        	entry: './src/main.js',
        	output: {
        		path: path.resolve(___dirname, 'dist'),
        		filename: 'bundle.js'
        	}
        }
        
      • 第三步:直接在终端内输入webpack

loader

  • loader是webpack中的一个非常核心的概念
  • loader的作用
    • 在开发过程中不仅有基本的js代码处理,我们也需要加载css、图片,也包括一些暴击的将es6转成es5代码,
      将typescript转成es5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等等。对于webpack本身的能力来说,这些转化是不支持的。
      Q:那怎么办呢?
      A:给webpack扩展对应的loader就可以啦
  • loader的使用过程
    • 步骤一:通过npm安装需要使用的loader
    • 步骤二:在webpack.config.js中的modules关键字下进行配置
  • 对应的loader
    • css:style-loader、css-loader
    • less:style-loader、css-loader、less-loader
    • url:url-loader、file-loader
    • es6 -> es5:babel-loader

webpack中配置Vue

  • 安装Vue:npm install vue --S
  • 引用Vue:import Vue from 'vue'
  • 挂载实例
  • .vue文件封装处理

    .vue文件封装处理

plugin

  • plugin是什么
    • 插件的意思,通常是对某个现有的框架进行扩展。
    • webpack中的检查,就是对webpack现有功能的各种扩展,比如打包优化,文件压缩等。
  • loader和plugin的区别
    • loader主要用于转换某些类型的模块,它是一个转换器。
    • plugin是插件,它是对webpack本身的扩展,是一个扩展器。
  • plugin的使用过程
    • 步骤一:通过npm安装需要的plugins(某些webpack已经内置的插件不需要安装)。
    • 步骤二:在webpack.config.js中的plugins中配置插件。
  • 案例:打包html的plugin
    • 步骤一:安装HtmlWebpackPlugin插件npm install html-webpack-plugin --S
    • 步骤二:在webpack.config.js文件中的plugins进行修改
      plugins: [
      	new htmlWebpackPlugin({
      		new webpack.BannerPlugin('最终版权归曹杰所有')
      		template: 'index.html'
      	})
      ]
      
  • js压缩的plugin
    • 在项目发布之前,就需要对打包的js文件进行压缩
      • 步骤一:使用第三方插件uglifyjs-webpack-plugin:npm install uglifyjs-webpack-plugin --S
      • 步骤二:修改webpack.config.js文件,使用插件
      const path = require('path')
      const webpack = require('webpack')
      const uglifyJsPlugin = require('uglify-webpack-plugin')
      
      module.exports = {
      	plugins: [
      		new uglifyJsplugin()	//压缩代码
      	]
      }
      

搭建本地服务器:webpack-dev-server

  • derServer也是作为webpack中的一个选项,选项本身可以设置一些属性:
    • contentBase:为哪一个文件提供本地服务,默认是根文件夹
    • prot:端口号
    • inline:页面实时刷新
    • historyApiFallback:在SPA页面中,依赖HTML5的history模式
  • webpack.config.js文件配置
    derServer: {
    	contentBase: '/dist',
    	inline: true
    }
    
  • 我们可以再配置另外一个script设置直接打开浏览器
    	"dev": "webpack-dev-server --open"
    

webpack的配置分离

  • 步骤一:执行npm install webpack-merage --S
  • 步骤二:配置的文件的作用分离成不同的config.js文件
  • 步骤三:在package.json中设置build与dev的路径

Vue-Cli详解

什么是Vue-Cli

  • 开发大型项目,必然需要使用Vue-Cli
    • 使用Vue.js开发大型应用时,我们需要考虑代码目录结构、项目结构和部署、热加载、代码单元测试等事情。
    • 如果每个项目都要手动完成这些工作,那无疑效率比较低效,所以通常我们会使用一些脚手架工具来帮助完成这些事情

Cli的意思

  • Cli是Command-Line Interface,翻译为命令行界面,但是俗称脚手架
  • Vue-Cli是一个官方发布的Vue.js项目脚手架
  • 使用Vue-cli可以快速搭建Vue开发环境以及对于webpack配置

Vue-Cli使用的前提

  • Node
    • 官网下载安装http://nodejs.cn/download
    • 检测安装的版本node -v以及npm -v
    • 什么是npm
      • npm的全称是Node Package Manager
      • 是一个NodeJS包管理和分发工具,已经成为了非官方发布的发布Node模块(包)标准
      • 后续我们会经常使用npm来安装一些开发过程中的依赖包
    • cnpm的安装:npm install -g cnpm --registry=https://registry.npm.taobao.org
  • webpack
    • Vue官方脚手架就使用了webpack模板
    • webpack的全局安装:npm install webpack -g

Vue-Cli的使用

  • 安装Vue脚手架:npm install -g @vue/cli
  • 拉取旧版本的模板
    • Vue-Cli3和旧版本使用了相同的vue命令,所以Vue-Cli2(vue-cli)被覆盖了,如果你仍然需要使用旧版本的vue init功能,可以全局安装一个桥接工具:npm install -g @vue/cli-init

Vue-Cli初始化项目

  • Vue-Cli2初始化项目:vue init webpack 项目名称
    • 会根据项目名称创建一个文件夹,存放之后项目的内容,该名称也会作为默认的项目名称,但是不能包含大写字母等。
    • 创建解析:
      • Project name:项目的名称
      • Project description:作者的信息
      • Author:后面的详细介绍
      • Vue build:项目的解析方式
        • runtime-compiler
          • 处理方式:temaplate -> ast -> rander -> 虚拟dom -> 真实dom
        • runtime-only
          • 处理方式:rander -> 虚拟dom -> 真实dom
          • 通过rander函数可以直接传人组件,省去了创建组件以及编译解析的过程,性能更高,下面的代码量更多
      • Install vue-router:是否需要安装vue-router
      • Use Eslint to lint your code?:是否需要ESLint检测代码规范
      • Set up unit tests:单元测试
      • Setup e2e tests with Nightwatch?:e2e测试,end to end
      • Should we run npm install for you after the project has been created?:选择yarn或者npm进行安装
  • Vue-Cli3初始化项目:vue create 项目名称
    • 创建详解
      • Please pick preset:选择配置
        • default(babel,eslint):默认的配置(配置babel和eslint)
        • Manually select features:手动配置

          手动配置

          • Babel:是否使用babel做转义
          • TypeScript:是否使用class风格的组件语法
          • Progressive Web App (PWA) Support:支持PWA
          • Router:安装使用路由Router
          • Vuex:安装使用Vuex状态管理,简单项目不建议使用安装
          • CSS Pre-processors:选择CSS 预处理类型
          • Linter / Forcessors:选择Linter / Formatter规范类型
          • Unit Testing:选择Unit测试方式
          • E2E Testing:选择E2E测试方式
          • Where do you prefer placing config for Babel,PostCSS,ESLint,etc.?:需要把相关配置放到独立的配置文件里还是统一放入package.json文件中去
          • Save this as a preset for future projects?:是否需要保存当前配置
    • 如何进行配置:
      • 方法一:UI方面的配置:启动配置服务器vue ui
      • 方法二:找到隐藏的配置文件:

        配置文件

      • 自定义配置文件vue.config.js

        自定义配置文件

Vue-Cli生成文件详解

在这里插入图片描述

  • build:webpack的配置文件,主要用于服务
  • config:webpack的配置文件,主要用于定义变量
  • node_modules:项目的相关依赖
  • src:开发的文件夹
  • static:放置静态资源

npm run build过程

在这里插入图片描述

npm run dev过程

在这里插入图片描述

Vue-router

SPA单页面富应用

  • 整个网页只有一个html页面
  • SPA最主要的特点就是在前后端分离的基础上加了一层前端路由
  • Vue-router是前端路由的核心,改变了URL,但是页面不进整体的刷新

路由的模式

  • hash
    vue-router默认使用的是hash模式,URL中带有#号
  • history
    • history.pushState:入栈路由
    • history.back():返回
    • history.replaceState:替换路由
    • history.go(-1):返回路由的数
    • history.forward():向前
  • 将hash改成history模式
    const router = new
    VueRouter({
    	routes,
    	mode: ‘history’	// 将hash改成history模式
    })
    

安装vue-router

  • 步骤一:安装npm install vue-router --save-dev
  • 步骤二:在模块化工程中使用它(因为他是一个插件,所以可以通过vue.use()来安装路由功能)

使用vue-router

  • 第一步:创建路由组建

  • 第二步:配置路由映射,组件与路径映射关系

    • 在配置中多配置一个映射关系,默认路径到首页
      const routes = [
      	{
      		path: '/',
      		redirect: '/home'
      	}
      ]
      
      • path配置的是根路径
      • redirect是重定向,也就是将根路径重新定向到/home路径下
  • 第三步:使用路由,通过<router-link><router-view>

    • <router-link>
      • 该标签是vue-router已经内置的一个组件,他会渲染成一个<A>标签
      • <router-link>的属性
        • to:渲染跳转的路径
          <router-link :to="/home">Home</router-link>	
          <!-- 渲染结果 -->
          <a href="/home">Home</a>
          
        • tag:<router-link>默认渲染的是<a>标签,tag可以定义渲染的DOM元素
      • 如何通过代码进行跳转
        • 通过@click进行元素的事件监听
        • 通过this.$router.push进行代码跳转
    • <router-view>
    • 改标题会根据不同的路径;
    • 网页的其他内容,比如顶部的标题和导航,都会在<router-view>处于同一个等级;
    • 在切换路由时,切换的是<router-view>挂载的组件,不会跟变其他的内容;

动态路由

  • 在某些情况下,一个页面的路径是不确定的,不如user/aaauser/bbb,这种path和component之间的关系,我们称之为动态路由
<script>
	{
		path: '/user/:id',
		component: User
	}
</script>

<div>
	<h2>{{$route.params.id}}</h2>
	<router-link to="/user/123">用户</router-link>
</div>

懒加载

  • 当打包构建应用时,javascript包会变得非常大,影响页面加载路由中通常会定义很多不同的页面,这些页面最终会被打包到一个js文件中。如果我们一次性从服务器请求下来这个页面,可能需要花费一定的时间。
  • 如果我们把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就高效了。
    • 业务代码
      import Home from '../components'/home
      const routes = [
      path: '/home',
        component: Home
      ]
      // ↓↓↓↓↓↓↓↓↓↓↓
      // 改为直接使用
      // ↓↓↓↓↓↓↓↓↓↓↓
      const routes = [
        path: '/home',
        component: () => import ('../components'/home)
      ]
        ```
      
    • 底层支撑
    • 第三方
  • 懒加载的方式
    • 方式一:集合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')
      

路由的嵌套

  • 路由嵌套是一个很常见的功能
    • 比如在home页面中,我们希望通过/home/news和/home/message访问一些内容,一个路径映射一个组件,访问这两个路径也会分别渲染两个组件

      ![-](https://www.icode9.com/i/ll/?i=20210224092546647.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9

  • 实现路由嵌套的两个步骤:
    • 步骤一:创建对应的子组件,并且在路由映射中配置children对应的子路由
    • 步骤二:在组件内部使用<router-view>标签

参数传递

  • params类型
    • 配置路由格式:/router/:id
    • 传递的方式:在path后面跟上对应的值
    • 传递后形成的路径:/router/123/router/abc
  • query类型
    • 配置路由格式:/router,也就是普通配置
    • 传递的方式:对象中使用query的key作为传递方式
    • 传递后形成的路径:/router?id=123/router?id=abc

导航守卫/全局守卫

  • 什么是导航守卫
    • vue-router提供的导航守卫主要用来监听路由的进入和离开的
    • vue-router提供了beforeEach和afterEach的钩子函数,他们会在路由即将改变前和改变后出发
  • 钩子函数的三个参数解析
    • to:即将要进入的目标的路由对象
    • from:当前导航即将要离开的路由对象
    • next:调用该方法后,才能进入下一个钩子
  • 案例
    const routes = [
    	{
    		path: '/home',
    		components: Home,
    		// 1.在钩子当中定义一些标题,可以领meta来定义
    		meta: {
    			title: '首页'
    		}
    	}
    ]
    router.beforeEach(( to,from,next ) => {
    	// 利用导航守卫,修改标题
    	window.document.title = to.mate.title
    	next()
    })  
    
  • 补充
    • 如果是后置钩子,也就是afterEach,不需要主动调用next函数
    • 除了全局守卫还有:路由独享守卫、组件内守卫

keep-alive

  • 是vue内置的一个组件可以使被包含的组件保留状态,或避免重新渲染。
  • 他有两个非常重要的属性:
    • include:字符串或者正则表达,只有匹配的组件会被缓存;
    • exclude字符串或者正则表达,任何匹配的组件都不会被缓存;
  • router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存。

路径别名

  • webpack.base.config下设置resolve
    config.resolve.alias
    .set('@',resolve('./src'))
    .set('components',resolve('./src/components')) //set第一个参数:设置的别名,第二个参数:设置的路径
    

Vuex详解

什么是Vuex

  • 是专为vue.js应用程序开发的状态管理模式
  • 它采用集中式储存管理应用的所有组件的状态,并以相应的规则来保证状态以一种可预测的方式发生变化
    • 状态管理是什么
      • 可以理解成利用一个公共的变量来改变程序的状态

访问与修改状态

  • this.$store.state:属性的方式来访问状态
  • this.$store.commit(‘mutation中方法’):来修改状态
    • 注意:我们通过提交mutation的方式,而非直接改变store.state.count,这是因为vuex可以更明确的追踪状态的变化,所以不要直接改变store.state.count的值

核心概念

  • State:保存的状态:单一状态树(单一状态树能够让我们最直接的方式找到某个状态的片段)
  • Getters:类似组件的计算属性(getters需要带参数的话需要runter一个函数)
  • Mutation:用来追踪数据的变化,定义变化的事件
    • Vuex的store状态的更新唯一方式
    • 主要包括2部分:
      • 字符串的事件类型
      • 一个回调函数,改回调函数的第一个参数就是state
    • mutation的定义方式:
      mutations: {
      	increment(state) {
      		state.count++
      	}
      }
      
    • 通过mutation更新:
      increment: function() {
      	this.$store.commot('increment')
      }
      
    • 传递参数:
      • 在通过mutation更新数据的时候,参数被称为是载荷(Payload)
        decrement(state, n) {
        	state.count -= n
        }
        decrement: function () {
        	this.$store.commot('increment', 2)
        }
        
      • 参数不是一个的情况下,通常会以对象的形式进行传递,也就是payload是一个对象

Action:用来操作异步操作

Module:划分模块

ES6

let

  • 块级作用域,更完美的var,不会引起变量污染

const

  • 一旦给const修饰的标识符被赋值后,不能再进行更改
  • 在使用const定义标识符,必须进行赋值
  • 常量的含义是指向的对象不能更改,但是可以更改内部的属性

对象字面量增强写法

  • 属性的增强写法
    	let name = 'caojie'
    	let age = 18
    	// ES6之前
    	let ojb1 = {
    		name: name,
    		age: age
    	}
    	console.log(ojb1)
    	
    	// ES6之后
    	let ojb2 = {
    		name, age
    	}
    	console.log(ojb2)
    
  • 函数的增强写法
    	// ES6之前
    	let ojb1 = {
    		test: function () {
    			console.log('ojb1的test函数')
    		}
    	}
    	ojb1.test()
    	
    	// ES6之后
    	let ojb2 = {
    		test  () {
    			console.log('ojb2的test函数')
    		}
    	}
    	ojb2.test()
    

高阶函数的使用案例

  • filter:过滤函数
    // filter中的回调函数有一个要求:必须返回一个boolean值
    // true:当返回true时,函数内部会自动将这次回调的n加入到新的数组中
    // false:当返回false时,函数内部会过滤到这次n
    const nums = [10, 20, 111, 222, 333, 40, 50]
    // 取大于100的值到新数组中
    let  newNum = nums.filter(function (n) {
    	return n < 100
    })
    
  • map:映射函数
      // 原数组被“映射”成对应新数组。
      const nums = [10, 20, 111, 222, 333, 40, 50]
      let  newNum = nums.map(function (n) {
      	return n * 100
      })
    
  • reduce:累加
      // 对数组中的所有内容进行汇总
      const nums = [10, 20, 111, 222, 333, 40, 50]
      let  total= nums.reduce(function (preValue, n) {
      	return preValue + n
      })
    
  • 链式编程
      // 一行实现以上三个功能
      const nums = [10, 20, 111, 222, 333, 40, 50]
      
      let  total= nums.filter(function (n) {
      	return n < 100
      }).map(function (n) {
      	return n * 100
      }).reduce(function (preValue, n) {
      	return preValue + n
      }, 0)
    
    • 箭头函数实现以上三个功能
      // 箭头函数实现以上三个功能
      const nums = [10, 20, 111, 222, 333, 40, 50]
      
      let  total= nums.filter(
      	n => n < 100
      ).map(
      	n => n * 100
      ).reduce((preValue, n) => 
      	preValue + n
      )
    

箭头函数

  • 传统定义函数的方式
    	// 传统function
    	const aaa = function () {}
    	// 传统对象字面量中定义函数
    	const obj = {
    		bbb = function () {}
    	}
    
  • 箭头函数的定义方式
    	// function
    	const bbb = () => {}
    	// 放置参数
    	const power = num => { return num * num }
    	const power = (num1, num2) => { return num1 * num2 }
    	// 函数
    	const demo = () => console.log('hello Demo')
    	const test = () => {
    		console.log('hello Demo')
    		console.log('hello vue')
    	}
    
  • 箭头函数中的this引用的就是最近作用域中的this

Promise

什么是Promise

  • Promise是异步编程的一种解决方案
  • 可以优雅的处理回调地狱
  • 一般情况下是有异步操作时,使用Promise对异步操作进行封装

Promise的三种状态

  • pending:等待状态,比如正在进行网络请求,或者定时器没有到时间。
  • fulfill:满足状态,当我们主动回调resolove,就会处于该状态,并且会回调.then()。
  • reject:拒绝状态,当我们主动回调reject时,就处于该状态,并且会回调.catch()

Promise链式调用简写

new Promise((resolve, reject) => {
	setTime(function () {
		resolve('Hello Word')
	}, 1000)
}).then(data => {
	console.log(data)	// Hello Word
	return data + '111'
}).then(data => {
	console.log(data)	// Hello Word111
	return data + '222'
}).then(data => {
	console.log(data)	// Hello Word111222
	return Promise.reject(data + 'error')
}).then(data => {
	console.log(data)	// 这里没有输出,这部分代码不会执行
	return data + '333'
}).catch(data => {
	console.log(data)	// Hello Word111222error
	return data + '444'
}).then(data => {
	console.log(data)	// Hello Word111222error444
})

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐