vue笔记

1. vue简介

1.1 什么是vue

是一套 用于构建用户界面的前端 框架

  • 构建用户界面
    • 用vue往html页面中填充数据,非常的方便
  • 框架
    • 框架是一套现成的解决方案,程序员只能遵守框架的规范,去编写自己的业务功能!
    • 要学习vue,就是学习vue框架中规定的用法!
    • vue指令、组件(是对UI结构的复用)、路由、Vuex、vue组件库
    • 只有把上面老师罗列的我内容掌握以后,才有开发vue项目的能力

1.2 vue的特性

vue框架的特性,主要体现在如下量方面:

  • 数据驱动视图:数据的变化 会驱动视图 的自动更新

    • 好处:程序员只需要把数据维护好,那么页面结构会被vue自动渲染出来!
    • 注意:数据驱动视图是单向的数据绑定
  • 双向数据绑定:在 填写表单 时,双向数据绑定可以在辅助开发者在 不操作DOM的前提下,自动 把用户填写的内容 同步到 数据源中。

    在网页中,form 表单负责采集数据,Ajax 负责提交数据。

    • 好处:开发者不再需要手动操作DOM元素,来获取表单元素最新的值!
    • js 的数据变化,会被自动渲染到页面上
    • 页面上表单采集的数据发生变化时,会被vue自动获取到,并更新到 js 数据中

1.3 MVVM

MVVM是 vue 实现 数据驱动视图双向数据绑定 的核心原理。MVVM 指的是 Model、View 和 ViewModel,它把每个 HTML 页面都拆分成了这三个部分:

  • Model:表示当前页面渲染是所依赖的数据源。
  • View:表示当前页面所渲染的 DOM 结构。
  • ViewModel:表示 vue 的实例,它是 MVVM 核心

1.4 MVVM 工作原理

ViewModel 作为MVVM 的核心,是它把当前页面的 数据源(Model)和 页面的结构(View)连接在一起。

  • 当数据源发生变化时,会被 ViewModel 监听到,VM 会根据最新的数据源 自动更新 页面的结构
  • 当 表单元素的值发生变化时,也会被 VM 监听到,VM 会把变化过后最新的值 自动同步 到 Model 数据源中

1.5 vue 的版本

当前,vue 共有3个大版本,其中:
2.x 版本的 vue 是目前企业级项目开发中的主流版本
3.x 版本的 vue 于 2020-9-19 发布,生态还不完善,尚未在企业级项目开发中普及和推广
1.x 版本的 vue 几乎被淘汰,不再建议学习与使用

总结:

3.x 版本的 vue 是未来企业及项目开发的趋势
2.x 版本的 vue 在未来的(1-2年内)会被逐渐淘汰

2. vue 的指令

2.1 指令的概念

指令(Directives)是 vue 为开发者提供的模板语法,用于 辅助开发者渲染页面的结构。

vue 中的指令 按照不同的用途 可以分为 6 大类:

  • 内容渲染 指令
  • 属性绑定 指令
  • 事件绑定 指令
  • 双向绑定 指令
  • 条件渲染 指令
  • 列表渲染 指令

注意:指令是 vue 开发中最基础、最常用、最简单的 知识点。

2.2 内容渲染指令

内容渲染指令 用来辅助开发者渲染 DOM元素的文本内容。常用的内容渲染指令有如下3个:

  • v-text
    • 缺点:会覆盖元素内部原有的内容
  • {{ }}
    • 优点:专门用来解决 v-text 会覆盖默认文本内容的问题,在实际开发中用的最多,只是内容的占位符,不会覆盖原有的内容
  • v-html
    • 优点:v-text和 插值表达式 只能渲染 纯文本内容,如果把包含 HTML 标签的字符串 渲染为页面的 HTML 元素,则需要用到 v-html 这个指令. 可以把带有标签的字符串,渲染成真的 HTML 内容

2.3 属性绑定指令

注意:插值表达式只能用在元素的 内容节点 中,不能用在元素的属性节点中!

  • 如果需要 为元素的属性 动态绑定 属性值,则需要用到 v-bind 属性绑定指令 v-bind

  • 简写为 英文:

  • 在使用 v-bind 属性绑定期间,如果绑定内容需要进行动态拼接,则字符串的外面应该包裹单引号,例如:

    <div :title="'box' + index"> 这是一个div </div>
    

使用 JavaScript 表达式

在 vue 提供的模板渲染法中,除了支持 绑定简单的数据值之外,还 支持JavaScript表达式的运算,例如:

{{ number + 1 }}

{{ ok ? 'YES' : 'NO' }}

{{ message.split('').reverse().join('') }}

<div v-bind:id = " 'list-' + id "></div>

2.4 事件绑定指令

vue 提供了 v-on 事件绑定指令,用来辅助程序员为 DOM 元素绑定事件监听。

  1. v-on 简写是 @

  2. 语法格式为:

    <button @click="add"></button>
    
    methods: {
    	add() {
    		// 如果在方法中要修改 data 中的数据,可以通过 this 访问到
    		this.count += 1
    	}
    }
    
  3. $event 的应用场景,如果默认的事件对象 e 被覆盖了,则可以手动传递一个 $event,例如:

    <button @click="add(3,$event)"></button>
    
    methods: {
    	add(n,e){
    		// 如果在方法中要修改 data 数据,可以通过 this 访问到
    		this.count += n
    	}
    }
    
  4. 事件修饰符:
    .prevent

    <a @click.prevent = "xxx">链接</a>
    

    .stop

    <button @click.stop="xxx"></button>
    
  5. 按键修饰符
    在监听 键盘事件 时,我们经常需要 判断详细的按键。此时,可以为 键盘相关的事件 添加 案件修饰符,例如:

    <!-- 只有在 'key' 是 'Enter' 时调用 'vm.submit()' -->
    <input @keyup.enter='submit'/>
    
    <!-- 只有在 'key' 是 'Esc' 时调用 'vm.clearInput()' -->
    <input @keyup.esc='clearInput'/>
    

2.5 双向绑定指令

vue 提供了 v-model 双向数据绑定 指令,用来辅助开发者在 不操作DOM 的前提下,快速获取表单的数据。

<p>用户名是:{{username}}</p>
<input type="text" v-model="username"/>

<p>选中的省份是:{{province}}</p>
<select v-model="province">
    <option value="">请选择</option>
    <option value="1">北京</option>
    <option value="2">上海</option>
    <option value="3">南京</option>
</select>

data: {
	return:{
		province: ''
	}
}
  1. v-model 指令的修饰符

    为了方便对用户输入的内容进行处理,vue 为 v-model 指令提供了 3 个修饰符,分别是:

    .number:自动将用户输入值转为数值类型

    <input v-model.number = "age"/>
    

    .trim:自动过滤用户输入的首尾空白字符

    <input v-model.trim = "msg"/>
    

    .lazy:在 “change” 时而非 “input” 时更新

    <input v-model.lazy = "msg"/>
    

    示例用法如下:

    <input type = "text" v-model.number = "n1"/> +
    <input type = "text" v-model.number = "n2"/> =
    
    <span> {{ n1 + n2 }}
    

2.6 条件渲染指令

条件渲染指令用来辅助开发者 按需求控制 DOM 的显示与隐藏。条件渲染指令有如下两个,分别是:

  • v-if 的原理:每次动态创建或移除元素,实现元素的显示与隐藏
    • 如果刚进入页面的时候,某些元素默认不需要被展示,而且后期这个元素也很可能不需要被展示出来,此时 v-if 性能更好
  • v-show 的原理:动态为元素添加或移除 display: none 样式,来实现元素的显示与隐藏
    • 如果要频繁的切换元素的显示状态,用 v-show 性能更好

示例用法如下:

<div id = "app">
    <p v-if = "networkState === 200" >请求成功 --- 被 v-if 控制</p>
    <p v-show = "networkState === 200" >请求成功 --- 被 v-show 控制</p>
</div>

v-else-if
充当 v-if 的 “else-if 块”,可以连续使用:

   <div v-if = "type === A">优秀</div>
   <div v-else-if = "type === B">良好</div>
   <div v-else-if = "type === C">一般</div>
   <div v-else>差</div>
注意:v-else-if 指令必须配合 v-if 指令一起使用,否则它将不会被识别!

2.7 列表渲染指令

vue 提供了 v-for 列表渲染指令,用来辅助开发者 基于一个数组来循环渲染一个列表结构。v-for 指令需要使用 item in items形式的特殊语法,其中:

  • items是待循环的数组

  • item是被循环的每一项

    data: {
    	list: [
    		{id: 1,name: 'zs'}
    		{id: 2,name: 'ls'}
    	]
    }
    
    // ---------------------分割线-----------------------
    <ul>
        <li v-for = "item in items">姓名是:{{ item.name }}</li>
    </ul>
    
  1. v-for 指令还支持一个 可选的 第二个参数,即 当前项的索引。语法格式为 (item,index) in items ,示例代码如下:

    data: {
    	list: [
    		{id: 1,name: 'zs'}
    		{id: 2,name: 'ls'}
    	]
    }
    
    // ---------------------分割线-----------------------
    <ul>
        <li v-for = "(item,index) in items">姓名是:{{ item.name }}</li>
    </ul>
    

    注意:v-for 指令中的 item项 和index索引 都是形参,可以根据需要进行 重命名。例如(user,i)in userList。

  2. 官方建议:只要用到了 v-for 指令,那么一定要绑定一个 :key 属性,

    而且,尽量把 id 作为 key 的值。

    官方对 key 的值类型,是有要求的:字符串或数字类型。

    key 的值是不能重复的,否则会 终端报错:Duplicate keys detected

  3. key 的注意事项

    • key 的值只能是 字符串 或 数字 类型
    • key 的值必须具有唯一性(即:key的值不能重复)
    • 建议把 数据项id属性的值 作为key的值(因为id属性的值具有唯一性)
    • 使用 index 的值 当作 key 的值 没有任何意义(因为 index 的值不具有唯一性)
    • 建议使用 v-for 指令时 一定要指定key的值(既提升性能,又防止列表状态紊乱)

总结:

  1. 能够知道 vue 的基本使用步骤

    • 导入 vue.js 文件
    • new Vue()构造函数,得到 vm 实例对象
    • 声明 el 和 data 数据节点
    • MVVM 的对应关系
  2. 掌握 vue 中常见 指令 的基本用法

    • 插值表达式、v-bind、v-on、v-if 和 v-else
    • v-for 和 :key、v-model
    • 掌握 vue 中 过滤器 的基本用法

3. 过滤器

3.1 什么是过滤器

过滤器是 vue 为开发者提供的功能,常用于 文本的格式化。过滤器可以用在两个地方:插值表达式 和 v-bind 属性绑定。

过滤器应该被添加在 JavaScript 表达式的 尾部,由 “管道符” 进行调用,示例代码如下:

<!-- 在双花括号中通过“管道符”调用 capitalize 过滤器,对 message 的值进行格式化 -->
<p>
    {{ message | capitalize }}
</p>

<!-- 在 v-bind 中通过 “管道符” 调用 formatId 过滤器,对 rawId 的值进行格式化 -->
<div v-bind: id = "rawId | formatId"></div>

特点:

  • 过滤器函数,必须被定义到 filters 节点之下

  • 过滤器本质上是函数

  • 注意:过滤器函数形参中的 val,永远是 ”管道符“ 前面的那个值

  • 强调:过滤器中,一定要有一个返回值

  • 字符串有个 charAt 方法,这个方法接收索引值,表示从字符串中把索引对应的字符,获取出来

3.2 私有过滤器和全局过滤器

在 filters 节点下定义的过滤器,称为 “私有过滤器”,因为它 只能在当前 vm 实例所控制的 el 区域内使用。如果希望在多个 vue实例之间共享过滤器,则可以按照如下的格式定义 全局过滤器:

// 全局过滤器 - 独立于每个 vm 实例之外
// Vue.filter() 方法接收两个参数
// 	第 1 个参数,是全局过滤器的“名字”
//  第 2 个参数,是全局过滤器的“处理函数”

Vue.filter('capitalize',(str) => {
	return str.charAt(0).toUpperCase() + str.slice(1) + "--"
})
  • 如果 全局过滤器和私有过滤器名字一致,此时按照 “就近原则”,调用的是 “私有过滤器”
  • 基本上都是用的全局过滤器

声明 格式化时间 的全局过滤器

// 1. 对 time 进行格式化处理,得到 YYYY-MM-DD
// 2. 把格式化的结果,return 出去
// 调用 day.js 文件
// 直接调用 day.js 得到的是当前的时间
// day.js(给定的日期) 得到指定的日期
Vue.filter('dataFormat',function(time){
	const dtStr = day.js(time).format('YYYY-MM-DD HH-mm-ss')
	return dtStr
})

3.3 连续调用多个过滤器

过滤器可以 串联地 进行调用,例如:

<!-- 把 message 的值,交给 filterA 进行处理 -->
<!-- 把 filterA 处理的结果,再交给 filterB 进行处理-->
<!-- 最终把 filterB 处理的结果,作为最终的值渲染到页面上 -->
{{ message | filterA | filterB }}

3.4 过滤器传参

过滤器的本质是 JavaScript 函数,因此可以接收参数,格式如下:

<!-- arg1 和 arg2 是传递给 filterA 的参数 -->
<p>{{ message | filterA(arg1,arg2) }}</p>

// 过滤器处理函数的形参列表中:
//   第一个参数:永远都是“管道符”前面待处理的值
//   从第二个参数开始,才是调用过滤器时传递过来的 arg1 和 arg2 参数
Vue.filter('filterA',(msg,arg1,arg2)=>{
	// 过滤器的代码逻辑...
})

3.5 过滤器的兼容性

过滤器仅在 vue2.x 和 1.x 中受支持,在 vue3.x 的版本中 剔除了过滤器 相关的功能。

在企业级项目开发中:

  • 如果使用的是 2.x 版本的 vue,则依然可以使用过滤器相关的功能
  • 如果项目已经升级到了 3.x 版本的 vue,官方建议使用 计算属性方法 代替被剔除的过滤器功能

具体的迁移指南,请参考 vue3.x 的官方文档给出的说明:https://v3.vuejs.org/guide/migration/filters.html#migration-strategy

4. 侦听器

4.1 什么是侦听器

watch 侦听器 允许开发者监视数据的变化,从而 针对数据的变化做特定的操作。

语法格式如下:

const vm = new Vue({
	el: "#app",
	data: {username: ''},
	watch: {
		// 监听 username 值的变化
		// newVal 是 “变化后的新值”,oldVal 是“变化之前的旧值”
		username(newVal,oldVal){
            if (newVal === '') return
			//console.log(newVal,oldVal)
			// 1. 调用 jQuery 中的 Ajax 发起请求,判断 newVal 是否被占用
			$.get('https://www.escook.cn/api/finduser' + newVal,function(result){
                consolt.log(result)
            })
    }
  }
})
  • 所有的侦听器,都应该被定义到 watch 节点下
  • 侦听器本质上是一个函数,要侦听哪个数据的变化,就把数据作为方法名即可
  • 新值在前,旧值在后
  • 应用场景:判断用户名是否被占用

4.2 侦听器的格式

方法格式的侦听器

  • 缺点1:无法在刚进入页面的时候,自动触发!!!
  • 缺点2:如果侦听的是一个对象,如果对象的属性发生了变化,不会触发侦听器!!!

对象格式的侦听器

好处:可以通过 immediate 选项,让侦听器自动触发!!!
示例代码如下:

const vm = new Vue({
	el: "#app",
	data: {username: 'admin'},
	watch: {
        // 定义对象格式的侦听器
        username: {
            // 侦听器的处理函数
            handler(newVal,oldVal){
                console.log(newVal,oldVal)
            },
            // immediate 选项的默认值为 false
            // immediate 的作用是,控制侦听器是否自动触发一次!
            immediate: true
        }
    }
})

4.3 深度侦听

const vm = new Vue({
	el: "#app",
	data: {
        info:{
            username: 'admin'
        }
    },
	watch: {
        // 定义对象格式的侦听器
        info: {
            // 侦听器的处理函数
            handler(newVal,oldVal){
                console.log(newVal,oldVal)
            },
            // 开启深度监听,只要对象中任何一个属性变化了,都会触发 对象的侦听器
            deep: true
        }
    }
})

4.4 只想监听单个属性的变化

const vm = new Vue({
	el: "#app",
	data: {
        info:{
            username: 'admin'
        }
    },
	watch: {
        // 定义对象格式的侦听器
        // 如果要侦听的是对象的子属性变化,则必须包裹一层单引号
        'info.username': {
            handler(newVal){
            	console.log(newVal)
            }
        }
    }
})

5. 计算属性

5.1 什么是计算属性

计算属性指的是 通过一系列运算 之后,最终得到一个 属性值。

这个动态计算出来的属性值 可以被模板结构或 methods 方法使用。示例代码如下:

var vm = new Vue({
	el: '#app',
	data: {
		r: 0, g: 0, b: 0
  },
	computed: {
		rgb() { return 'rgb(${this.r,${this.g},${this.b})' }
  },
	methods: {
		show() {console.log(this.rgb)}
  }
})
  • 模板字符串
  • :style 代表动态绑定一个样式对象,它的值是一个 { } 样式对象
  • 所有的计算属性,都要定义到 computed 节点之下
  • 计算属性在定义的时候,要定义成”方法格式“
  • 声明的时候 是一个方法格式,用的时候则是 属性格式

好处:

  • 实现了代码的复用
  • 只要计算属性中,依赖的数据源变化了,则计算属性会自动重新求值!

6. axios

6.1 什么是 axios

专注于 数据库请求 的库。
Vue、React 课程中都会用到 axios 来请求数据。
中文官网地址:[http://ww.axios-js.com/]
英文官网地址:[https://www.npmjs.com/package/axios]

6.2 基础用法如下:

axios({
	method: '请求的类型',
	url: '请求的 URL 地址'
}).then((result)=>{
	// .then 用来指定请求成功之后的回调函数
	// 形参中的 result 是请求成功之后的结果
})
  1. 调用 axios 方法得到的返回值是 Promise

  2. axios 在请求到数据之后,在真正的数据之外,套了一层壳

    {
    	config: {},
    	data: {真实的数据},
    	headers: {},
    	request: {},
    	status: xxx,
    	statusTest: ''
    }
    

6.3 传参

  • params: { } // URL中的查询参数
  • data: { } // 请求体参数

6.4 基本使用

  1. 发起 Get 请求

    axios({
    	// 请求方式
    	method: 'GET',
    	// 请求的地址
    	url: 'http://www.lfdkfk/api/getCats',
    	// URL 中的查询参数
    	params: {
    		id: 1
    	}
    }).then((result)=>{
    	consol.log(result)
    })
    
  2. 发起 Post 请求

    axios({
    	// 请求方式
    	method: 'POST',
    	// 请求的地址
    	url: 'http://www.lfdkfk/api/getCats',
    	// URL 中的查询参数
    	data: {
    		name: 'zs',
    		age: 20
    	}
    }).then((result)=>{
    	consol.log(result)
    })
    

6.5 async 和 await 使用

  • 如果调用某个方法的返回值是 Promise 实例,则前面可以添加 await !
  • await 只能用在被 async “修饰” 的方法中

6.6 解构赋值

  1. 调用 axios 之后,使用 async 和 await 进行简化

  2. 使用解构赋值,从 axios 封装的大对象中,把 data 属性解构出来

  3. 把解构出来的 data 属性,使用 冒号 进行重命名,一般都重命名为 { data: res }

    async loadMoviesList() {
    	// 结构赋值的时候, 使用 : 进行重命名
    	const { data: res } = await axios({
    		method: 'GET',
    		url: 'http://www.fakdfalfk/api/getMovies'
    	})
    }
    

6.7 基于 axios.get 和 axios.post 发起请求

  1. get 请求

    async loadMoviesList(){
    	const { data: res } = await axios.get('http://www.fjdkfj/api/getMovies',{
    	params: { id: 1 }
      })
    	console.log(res.data)
    }
    
    
  2. post 请求

    async loadMoviesList(){
      const { data: res } = await axios.post('http://www.fjdkfj/api/getMovies',{
    	name: 'zs',
    	age: 20
      })
        console.log(res.data)
    }
    

7. vue-cli

7.1 什么是单页面应用程序

单页面应用程序(Single Page Application)简称 SPA,顾名思义,指的是 一个Web 网站中只有唯一的一个HTML页面,所有的功能与交互都在这唯一的一个页面内完成。

7.2 什么是 vue-cli

vue-cli 是 Vue.js 开发的标准工具。它简化了程序员基于 webpack 创建工程化的 Vue 项目的过程。
引用 vue-cli 官网上的一句话:
程序员可以 专注在撰写应用上,而不必 花好几天 去 纠结 webpack 配置的问题。
中文官网:https://cli.vuejs.org/zh/

7.3 安装和使用

vue-cli 是 npm 上的一个 全局包,使用 npm install 命令,即可方便的把它安装到自己的电脑上:

npm install -g @vue/cli

vue 项目中 src 目录的构成:

assets文件夹:存放项目中用到的静态资源文件,例如:css 样式表、图片资源
components文件夹:程序员封装的、可复用的组件,都要放到 components 目录下
main.js 是项目的入口文件,整个项目的运行,要先执行 main.js
App.vue 是项目的根组件

7.4 vue 项目运行流程

在工程化项目中,vue 要做的事情很单纯:通过 main.js 把 App.vue 渲染到 index.html 的指定区域中。
其中:

  1. App.vue 用来编写待渲染的 模板结构
  2. index.html 中需要预留一个 el 区域
  3. main.js 把 App.vue 渲染到了 index.html 所预留的区域中

8. vue 组件

8.1 什么是组件化开发

组件化开发指的是:根据封装的思想,把页面上可重用的 UI 结构封装为组件,从而方便项目的开发和维护。

vue 是一个 支持组件化开发 的前端框架。

vue 中规定:组件的后缀名是 .vue。之前接触到的 App.vue 文件本质上就是一个 vue 的组件。

8.2 vue 组件的三个组成部分

每个 .vue 组件都由 3 部分构成,分别是:

  • template -> 组件的模板结构
  • script -> 组件的 JavaScript 行为
  • style -> 组件的样式

注意:默认导出,这是固有写法!

注意:data 数据源

注意:.vue 组件中的 data 不能像之前一样,不能指向对象

注意:组件中的 data 必须是一个函数

// 默认导出,这是固有写法!
export default {
	// data 数据源
	// .vue 组件中的 data 不能像之前一样,不能指向对象
	// 组件中的 data 必须是一个函数
	data() {
		// 这个 return 出去的 { }中,可以定义数据
		return{
			username: 'admin'
		}
	}
}

8.3 在组件中定义 methods 方法

<template>
    <div>
        <h3>这是用户自定义的 Test.vue --- {{ username }}</h3>
        <button @click = "changeName">修改用户名</button>
    </div>
</template>

<script>
// 默认导出,这是固有写法!
export default {
	// data 数据源
	// .vue 组件中的 data 不能像之前一样,不能指向对象
	// 组件中的 data 必须是一个函数
	data() {
		// 这个 return 出去的 { }中,可以定义数据
		return{
			username: 'admin'
		}
	},
    methods: {
        changeName() {
            // 在组件中,this 就表示当前组件的实例对象
            console.log(this);
            this.username = '爽歪歪';
        }
    },
    // 当前组件中的侦听器
    watch: {  },
    // 当前组件中的计算属性
    computed: { },
    // 当前组件中的过滤器
    filters: {  }
}
</script>

注意:在组件中,this 就表示当前组件的实例对象

8.4 启用 less 语法 以及 唯一根节点

上来首先就在 template 中定义 一个 div 标签

<template>
	<div></div>
</template>

想要用 less 语法,需要在 style 标签中 加入 lang = "less"

<style lang = "less">

</style>

8.5 组件之间的关系

组件在被封装好之后,彼此之间是相互独立的,不存在父子关系。
在使用组件的时候,根据彼此之间的嵌套关系,形成了 父子关系、兄弟关系。

8.6 在项目中使用 组件的三个步骤

步骤一:使用 import 语法 导入需要的组件
步骤二:使用 components 节点注册组件
步骤三:以 标签形式 使用刚才注册的组件
示例如下:

<template>
	<div>
        <!-- 3. 使用组件 -->
        <Left></Left>
    </div>
</template>



<script>
    // 1. 导入需要的vue组件
    import Left from '@/components/Left.vue'
    
    export default: {
        // 2. 注册组件
        components: {
            Left;   //(全写应该是一个键值对:Left:'Left')
        }
    }
</script>

注意:@ 指的是 ./src

在 webpack.config.js 中

module.exports = {
    resolve: {
        alias: {
            @:path.join(__dirname,'./src')
        }
    }
}

8.7 在 VScode 中配置 @ 路径提示的插件

步骤一:需要装一个插件:Path Autocomplete

步骤二:设置 --> settings.json,加入两句话

  • // 导入文件时 是否携带文件的扩展名:“path-autocomplete.extensionOnImport”:true,

  • // 配置 @ 的路径提示:“path-autocomplete.pathMappings”:{ “@”: “${folder}/src”}

8.8 使用 Vue.component 全局注册组件

原因:通过 components 注册的组件是 私有子组件

例如:在 组件A 的 components 节点下,注册了 组件F。则 组件F 只能用在 组件A 中,不能被用在 组件C 中。

思考问题:

  1. 为什么 F 不能用在 组件C 中?
  2. 怎样 才能在 组件C 中使用 F ?

在 vue 项目的 main.js 入后文件中,通过 Vue.component() 方法,可以注册全局组件。示例代码如下:

// 1. 导入需要全局注册的组件
import Count from '@/components/Count.vue'

// 2. 调用 Vue中的 component方法
// 参数1:字符串格式,表示组件的“注册名称”
// 参数2:需要被全局注册的那个组件
Vue.component('MyCount',Count);

8.9 auto close tag 自动闭合标签的插件

三个经常用的插件:

  1. vetur
  2. vue3 Snippets
  3. Auto Close Tag

9. 动态组件

9.1 什么是动态组件?

动态组件指的是动态切换组件的显示与隐藏。

9.2 如何实现动态组件渲染

vue 提供了一个内置的 组件,专门用来实现动态组件的渲染。实例如下:

data() {
	// 1. 当前要渲染的组件名称
	return { comName: 'Left' }
}

<!-- 2.通过 is 属性,动态指定要渲染的组件 -->
<component :is ="comName"></component>

<!-- 3. 点击按钮,动态切换组件的名称 -->
<button @click="comName = 'Left'">展示Left组件</button>
<button @click="comName = 'Right'">展示Right组件</button>


第一个大写 直接 shit + 字母 Sift

10. 路由

10.1 什么是路由

路由 就是对应关系。

10.2 SPA 与前端路由

SPA:单页面应用程序。

10.3 什么是前端路由

Hash 地址 与 组件 之间的 对应关系。

10.4 前端路由的工作方式

  1. 用户点击了页面上的链接
  2. 导致了 URL 地址栏中的 Hash值 发生了变化
  3. 前端路由监听到了 Hash 地址的变化
  4. 前端路由把当前 Hash地址对应的组件 渲染到浏览器中

10.5 vue-router 的基本使用

10.5.1 什么是 vue-router

vue-router 是 vue.js 官方给出的 路由解决方案。它只能结合 vue 项目进行使用,能够轻松的管理 SPA 项目中组件的切换。

vue-router 的官方文档地址:[https://router.vuejs.org//zh/]

10.5.2 vue-router 安装和配置的步骤
  1. 安装 vue-router包
  2. 创建路由模块
  3. 导入并挂载路由模块
  4. 声明路由链接和占位符
10.5.3 在项目中安装 vue-router

在 vue2 的项目中,安装 vue-router 的命令如下:

npm i vue-router@3.5.2 -S
10.5.4 创建路由模块

在 src 源代码目录下,新建 router/index.js 路由模块,并初始化如下的代码:

// 1. 导入 Vue 和 VueRouter 的包
import Vue from 'vue'
import VueRouter from 'vue-router'

// 2. 调用 Vue.use() 函数,把 VueRouter 安装为 Vue 的插件
Vue.use(VueRouter)

// 3. 创建路由的实例对象
const router = new VueRouter({
	// routes 是一个数组,作用:定义“hash地址”与“组件”之间的对应关系
	// 路由规则
	routes:[
		{path: "/home",component: Home},
		{path: "/about",component: About},
		{path: "/movie",component: Movie}
    ]
})

// 4. 向外共享路由的实例对象
export default router

小记:在进行模块化导入的时候,如果给定的是文件夹,默认导入的是这个文件夹下,名字叫 index.js 文件

当安装和配置了 vue-router 后,就可以用 router-link 来代替普通的 a 链接了

原来:< a href = “#/home” > 首页

现在:< router-link to= “/home”>首页

10.5.5 router-view
  • 只要在项目中安装和配置了 vue-router,就可以使用 router-view 这个组件了
  • 作用很单纯,占位符
10.5.6 路由重定向

路由重定向 指的是:用户在访问 地址 A 的时候,强制用户跳转 到地址 C ,从而展示特定的组件页面。通过路由规则的 redirect属性,指定一个新的路由地址,可以很方便的设置路由的重定向:

const router = new VueRouter({
	// 在 routes 数组中,声明路由的匹配规则
	routes: [
		{path: '/',redirect: '/home'}
		{path: '/home',component: Home}
		{path: '/movie',component: Movie}
		{path: '/about',component: About}
	]
})
10.5.7 嵌套路由

通过路由实现 组件的嵌套展示,叫做嵌套路由。

  1. 模板内容中又有 子级路由链接
  2. 点击 子级路由链接 显示 子级模板内容

通过 children 属性声明 子路由规则

在 src/router/index.js 路由模块中,导入需要的组件,并使用 children属性 声明子路由规则:

import Tab1 from '@/component/tabs/Tab1.vue'
import Tab2 from '@/component/tabs/Tab2.vue'

const router = new VueRouter({
	routes: [
		{ // about 页面的路由规则(父级路由规则)
			path: '/about',
			component: About,
			children: [ // 1.通过children属性,嵌套声明子路由规则
				{path: 'tab1',component: Tab1}//2.访问/about/tab1时,展示Tab1组件
				{path: 'tab2',component: Tab2}//2.访问/about/tab2时,展示Tab2组件
			]
		}
	]
})

注意:children 路由下,path 路径不要加 /

默认子路由,如果 children 数组中,某个路由规则的 path 值为空字符串,则这条路由规则,叫做 ”默认子路由“ === redirect : “” ,示例如下:

{path: ’ ', component: Tab1} === redirect: ‘/about/tab1’

10.5.8 动态路由匹配

问题:路由规则的复用性差。

动态路由指的是:把 Hash 地址中 可变的部分 定义为 参数项,从而 提高路由规则的复用性。

在 vue-router 中使用 英文的冒号 : 来定义路由的参数项。示例代码如下:

// 路由中的动态参数以 : 进行声明,冒号后面的是动态参数名称
{ path: '/movie/:id', component: Movie }

// 将以下 3 个路由规则,合并成了一个,提高了路由规则的复用性
{ path: '/movie/1', component: Movie }
{ path: '/movie/2', component: Movie }
{ path: '/movie/3', component: Movie }
10.5.9 $route 和 $router

this.$route 是路由的 “参数对象”

this.$router 是路由的 “导航对象”

10.5.10 为路由规则开启 props 传参
// 可以为路由规则开启 props 传参,从而方便的拿到 动态参数的值
{ path: '/movie/:mid', component: Movie, props: true }


export default {
	name: 'Movie',
	// 接收 props 数据
	props: ['mid']
}
10.5.11 路径参数 和 查询参数

注意1:在 hash 地址中,/ 后面的参数项,叫做 ”路径参数“

在路由 ”参数对象“ 中,需要使用 this.$route.params 来访问路径参数

注意2:在 hash 地址中,? 后面的参数项,叫做 ”查询参数“

在路由 ”参数对象“ 中,需要使用 this.$route.query 来访问查询参数

10.5.12 path 和 fullPath

注意3:在 this.$route 中,path 只是经过部分,fullPath 是完整的地址

10.5.13 声明式导航 & 编程式导航

在浏览器中,点击链接 实现导航的方式,叫做 声明式导航。例如:

  • 普通网页中点击链接、vue 项目中点击都属于声明式导航

在浏览器中,调用 API方法 实现导航的方式,叫做 编程式导航。例如:

  • 普通网页中调用 location.href 跳转到新页面的方式,属于编程式导航
10.5.14 vue-router 中的编程式导航 API

vue-router 提供了许多编程式导航的 API,其中最常用的导航 API 分别是:

  1. this.$router.push('hash地址')

    作用:跳转到指定hash地址,并增加一条历史记录

  2. this.$router.replace('hash地址')

    作用:跳转都指定hash地址,并替换到当前的历史记录

  3. this.$router.go(数值n)

    作用:调用 this.$router.go()方法,可以在浏览历史中前进和后退。示例代码如下:

    <template>
      <h3>MyMovie组件 --- {{id}}</h3>
      <button @click="goBack">后退</button>
    </template>
    
    <script>
      export default{
          // props: ['id'],
          methods: {
              goBack(){this.$router.go(-1)} //后退到之前的组件页面,后退一层
          }
      }
    </script>
    

在实际开发中,一般只会前进和后退一层页面。因此 vue-router 提供了如下两个便捷方法:

$router.back(): 在历史记录中,后退到上一个页面
$router.forward():在历史记录中,前进到下一个页面

可以简写到行内:

<button @click="this.$router.back()">后退</button>
<button @click="this.$router.forward()">前进</button>

11.导航守卫

11.1 目的

目的:可以控制路由的访问权限。

11.2 全局前置守卫

每次发生路由的 导航跳转 时,都会触发 全局前置守卫。因此,在全局前置守卫中,程序员可以对每个路由进行 访问权限 的控制:

// 创建路由实例对象
const router = new VueRouter({...})

// 调用路由实例对象的 beforeEash 方法,即可声明 “全局前置守卫”
// 每次发生路由导航跳转的时候,都会自动触动 fn 这个 “回调函数”
router.beforeEach(fn)

11.3 守卫方法的三个形参

全局前置守卫的回调函数中接收 3 个形参,格式为:

// 创建路由实例对象
const router = new VueRouter({...})

// 全局前置守卫
router.beforeEach((to,from,next)=>{
	// to 是将要访问的路由的信息对象
	// from 是将要离开的路由的信息对象
	// next 是一个函数,调用 next() 表示放行,允许这次路由导航

	// 分析:
	// 1. 要拿到用户将要访问的 hash 地址
	// 2. 判断 hash 地址是否等于 /main
	// 2.1 如果等于 /main,证明需要登陆之后,才能访问成功
	// 2.2 如果不等于 /main,则不需要登陆,直接放行 next()
	// 3. 如果访问的地址是 /main,则需要读取 localstorage 中的 token 值
	// 3.1 如果有 token 则放行
	// 3.2 如果没有 token 则强制跳转到 /login 登陆页面
})

11.4 next 函数的 3 种调用方式

当前用户 拥有 后台主页的访问权限,直接放行:next()

当前用户 没有 后台主页的访问权限,强制其跳转到登陆页面:next(’/login’)

当前用户 没有 后台主页的访问权限,不允许跳转到后台主页:next(false)

12. Props

12.1 什么是 props

props 是组件的 自定义属性,在 封装通用组件 的时候,合理地使用 props 可以极大的 提高组件的复用性!

语法格式如下:

<script>
    export default {
        // 组件的自定义属性
        props: ['自定义属性A','自定义属性A','其它自定义属性...'],
        
        
        // 组件的私有数据
        data() {
            return {
                
            }
        }
    }
</script>

示例:

Count.vue

<template>
	<div>
        <h5>Count 组件</h5>
        <p>count的值是:{{ init }}</p>
        <button @click="count += 1"> +1 </button>
    </div>
</template>
<script>
    // props 是自定义属性,允许使用者通过自定义属性,为当前组件指定初始值
    // 自定义属性的名字,是封装者自定义的 {只要名称合法就行}
    props: ['init'],
    
    data() {
        return {
            count: 0
        }
    }
</script>

Left.vue

<template>
	<div>
        <h3>Left 组件</h3>
        <hr/>
        
        <Count init="6"></Count>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                
            }
        }
    }
</script>

Right.vue

<template>
	<div>
        <h3>Right 组件</h3>
        <hr/>
        
        <Count init="9"></Count>
    </div>
</template>

<script>
    export default {
        data() {
            return {
               count: 0 
            }
        }
    }
</script>

12.2 结合 v-bind 使用自定义属性

组件的封装者 vs 组件的使用者

在 v-bind 中写的是 js 表达式

<Count init="9"></Count> // 此时 9 是字符串

<Count :init="9"></Count>// 此时 9 是数字

12.3 props 是只读的

props 中的数据,可以直接在模板结构中被使用。

<template>
	<div>
        <h5>Count 组件</h5>
        <p>count的值是:{{ init }}</p>
        <button @click="init += 1"> +1 </button> // 这种写法是错误的!!!
    </div>
</template>
<script>
    // props 是自定义属性,允许使用者通过自定义属性,为当前组件指定初始值
    // 自定义属性的名字,是封装者自定义的 {只要名称合法就行}
    // props 中的数据,可以直接在模板结构中被使用
    // 注意:props是只读的,不要直接修改 props 的值,否则终端会报错!
    props: ['init'],
    
    data() {
        return {
            count: 0
        }
    }
</script>

vue规定:组件中封装的自定义属性是 只读的,程序员 不能直接修改 props 的值。否则会直接报错。

问题:如何修改 props 属性值?

方法:要想修改 props 的值,可以把 props 的值转存到 data 中,因为 data 中的数据都是 可读写的。

<template>
	<div>
        <h5>Count 组件</h5>
        <p>count的值是:{{ count }}</p>
        <button @click="count += 1"> +1 </button> // 这种写法是正确的。。。
    </div>
</template>
<script>
    // props 是自定义属性,允许使用者通过自定义属性,为当前组件指定初始值
    // 自定义属性的名字,是封装者自定义的 {只要名称合法就行}
    // props 中的数据,可以直接在模板结构中被使用
    // 注意:props是只读的,不要直接修改 props 的值,否则终端会报错!
    props: ['init'],
    
    data() {
        return {
            count: this.init
        }
    }
</script>

12.4 props 的 default 默认值

在声明自定义属性时,可以通过 default 来 定义属性的默认值。示例代码如下:

<script>
    export default {
        props: {
            init: {
                // 用default 属性定义属性的默认值
                default: 0
            }
        }
    }
</script>

将 props 指向一个对象:

<script>
    export default {
        // props: ['init']
        props: {
            // 自定义属性 A:{ /* 配置选项 */},
            // 自定义属性 B:{ /* 配置选项 */},
            // 自定义属性 C:{ /* 配置选项 */},
            init: {
                // 如果外界使用 Count 组件的时候,没有传递 init,则默认 init为0
                default: 0
            }
        }
    }
</script>

12.5 props 的 type 值类型

在声明自定义属性时,可以通过 type 来 定义属性的值类型。示例代码如下:

<script>
    export default {
        // props: ['init']
        props: {
            init: {
                // 用 default 属性定义属性的默认值
                default: 0,
                // 用 type 属性定义属性的值类型
                // 如果传递过来的值不符合此类型,则会在终端报错
                type: Number
            }
        }
    }
</script>

12.6 props 的 required 必填项

必填项校验,如果没传定义的属性,则会报错。

<script>
    export default {
        // props: ['init']
        props: {
            init: {
                // 用 default 属性定义属性的默认值
                default: 0,
                // 用 type 属性定义属性的值类型
                // 如果传递过来的值不符合此类型,则会在终端报错
                type: Number,
                required: true
            }
        }
    }
</script>

13. 组件之间样式冲突

13.1 组件之间的样式冲突问题

默认情况下,写在 .vue 组件中的样式会全局生效,因此很容易造成 多个组件之间的样式冲突问题。

导致组件之间样式冲突的根本原因是:

  1. 单页面应用程序中,所有组件的 DOM 结构,都是基于 唯一的 index.html 页面进行呈现的
  2. 每个组件中的样式,都会 影响整个 index.html 页面中的 DOM 元素

**思考:**如何解决样式冲突问题?

方法:通过scoped:自动为每一个标签生成 data-v-001

13.2 使用 deep 修改子组件中的样式

思考:如何在 父组件中 修改 子组件 样式?

方法:通过 deep

应用场景:当使用第三方组件库的时候,如果有修改 第三方组件默认样式的需求,需要用到 /deep/

<style class="less" scoped>
    // h5[data-v-001]
    // [data-v-001] h5
    
    /deep/ h5 {
        
    }
</style>

14. 组件之间的数据共享

14.1组件之间的关系

在项目开发中,组件之间的 最常见的关系 分为以下两种:

  1. 父子关系
  2. 兄弟关系

14.2 数据共享

14.2.1 父组件向子组件数据共享

父组件向子组件共享数据需要使用 自定义属性。示例代码如下:

父组件:

<template>
	<div>
        <Son :msg="message" :user="userInfo"></Son>
    </div>
</template>

<script>
    export default{
        data() {
        return {
            message: 'hello vue.js',
            userinfo: { name:'zs', age: 20 }
        }
   	  }
    }
</script>

子组件:

<template>
	<div>
        <h5>Son 组件</h5>
        <p>父组件传递过来的 msg 值是: {{ msg }}</p>
        <p>父组件传递过来的 user 值是: {{ user }}</p>
    </div>
</template>

<script>
    props: ['msg','user']
</script>
14.2.2 不要修改 props 的值

不建议修改 props数组中 值

想要修改,需要转存一份。

14.2.3 子向父传值

子组件 向 父组件共享数据使用 自定义事件。示例代码如下:

子组件:

<script>
    export default {
        data() {
            return {
                count: 0
            }
        },
        method: {
            add() {
                this.count += 1;
                // 修改数据时,通过 $emit() 触发自定义事件
                this.$emit('numchange',this.count)
                
            }
        }
    }
</script>

父组件:

<template>
	<div>
        <Son @numchange="getNewCount"></Son>
    </div>
</template>

<script>
    export default {
        data() {
            return {
            	countFromSon: 0
        	}
        },
        method: {
            getNewCount(val) {
                this.countFromSon = val
            }
        }
    }
</script>

15. ref引用

vue 优势:MVVM。数据驱动视图。
假设:在 vue 中,需要操作 DOM 了,需要拿到页面上某个 DOM 元素的引用,此时该怎么办?

15.1 什么是 ref 引用

ref 用来辅助开发者在 不依赖于 jQuery 的情况下,获取 DOM 元素或组件的引用。

每个 vue 的组件实例上,都包含一个 $refs 对象,里面存储着对应的 DOM 元素或组件的引用。默认情况下,组件的 $refs 指向一个空对象。示例如下:

父组件:

<template>
	<div>
        <h1 ref="myh12">App 根组件</h1>
        <button @click="showThis">打印 this</button>
        <button @click="onReset">重置 Left 组件的 count 值为 0</button>
        <hr/>
        
    	<div class="box">
            <!-- 渲染 Left 组件和 Right 组件-->
            <Left ref="comeLeft"> </Left>
    	</div>
    </div>
</template>

<script>
    import Left from '@/component/Left.vue'
    
    export default {
        methods: {
            showThis() {
                // this 是当前 App 组件的实例对象
                console.log(this)
                this.$refs.myh12.style.color = 'red'
                
            },
            onReset() {
                // this.$refs.comLeft.resetCount = 0
                this.$refs.comLeft.count = 0
            }
        }
    }
</script>

子组件:

<template>
	<div class="left-container">
        <h3>Left 组件 --- {{ count }}</h3>
        <button @click="count += 1">+1</button>
        <button @click="resetCount">重置</button>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                count: 0
            }
        },
        methods: {
            resetCount() {
                this.count = 0
            }
        }
    }
</script>

16. 了解 this.$nextTick(cb) 方法

组件的 $nextTick(cb) 方法,会把 cb 回调 推迟到下一个 DOM 更新周期之后执行。通俗的理解就是:等组件的 DOM 更新完成之后,再执行 cb 回调函数。从而能保证 cb 回调函数可以操作到最新的 DOM 元素。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值