1、淘宝镜像
1: 解释一下 npm 为什么要配置淘宝镜像原因:因为node.js 默认使用的是国外的网站 。国内访问有一个跨国内局域网的操作。所以就会有时候很慢。这就跟为什么网站的静态资源有些会使用CDN 加速一样的淘宝镜像是什么?就是npm 很多的插件淘宝已经下载好了放在公共的网站上 我们需要的时候去淘宝网上下载 和 国外的是一样 这样使用是提升了我们的下载速度。所以淘宝镜像其实是一个国外插件的 国内版本2:安装命令npm config set registry https://registry.npm.taobao.org3:查看是否安装成功 npm info express4:使用命令 npm install -g cnpm --registry=https://registry.npm.taobao.orgcnpm install <插件名>
3、安装vue的调试工具
1、插件已经下载好,直接拖着往谷歌浏览器的扩展程序里面,记得是开发者模式(教学案例)
1、理解什么是Vue
0:官网https://cn.vuejs.org/guide/introduction.htmlhttps://cdn.jsdelivr.net/npm/vue@2 压缩版https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js 生产版
1、Vue.js是目前最火的框架,是前端的主流框架之一,和Angular。js和React.js
并称为三大主流框架
2、Vue.js是一套构建用户界面的框架,只关注图层,不仅易于上手,HIA方便与第三方库或既有项目整合(有配套的第三方类库,可以整合起来做大型项目的开发
3、使用vue往html页面中填充数据,非常的方便。框架都是现成的解决方案,按照框架的规范,去便携自己的业务功能
4、主要就是学习vue的指令、组件、路由、vuex
5、vue的特性:1、数据驱动视图2、双向数据绑定
2、如何学习Vue
1、能够使用Vue的指令完成页面结构的渲染
2、能够使用Vue的调试工具辅助Vue的开发
3、了解什么是过滤器和侦听器,能够在实际开发中解决问题
4、什么是计算属性以及计算属性的用法
5、axios的基本用法,使用axios发起ajax请求
6、vue-cli,脚手架的安装和使用,生成工程化的Vue项目
7、组件的注册与使用,掌握vue单文件组件的基本用法
8、组件的props自定义属性
9、解决组件样式冲突
10、学习组件的生命周期,掌握组件声明周期的执行顺序和应用场景
11、组件之间的通讯(数据共享),组件之间通讯的三种方式
12、学习ref应用DOM元素和组件实例,能够使用ref获取页面上的DOM、或组件的引用
13、$nxtTick的基本使用,能够知道$nxtTick的应用场景并合理的使用
14、学习动态组件的使用,能够使用keep-alive实现组件的缓存
15、自定义指令
16、学习ESLint的使用,能够了解ESLint的语法规则
17、学习使用(默认插槽、具名插槽、作用域插槽),能够使用插槽提高组件的复用性
18、学习路由的基本配置与使用,能够在项目中安装和配置路由
19、路由重定向
20、嵌套路由、动态路由
21、编程式导航、路由导航守卫,能够使用路由实现单页面程序的开发。使用导航收尾控制路由的访问权限
22、学习Vant,掌握Vant组件库的基本使用,知道如何封装axios请求模块
3、数据驱动视图
1、在vue的页面中,vue会监听数据的变化,从而自动重新渲染页面的结构页面结构<-vue(监听数据的变化,数据发生改变)<-页面发生变化好处:当页面数据发生变化时,页面会自动重新渲染,只需要管理好数据注意:数据驱动视图是单向的数据绑定总结:数据的变化会驱动视图自动更新,
3-1、数据代理
1、数据代理:通过一个对象代理另一个对象中属性的操作2、vue中采用数据代理Object.defineProperty中的setter和getter进行数据代理和数据的响应
3-2、VueComponent
1、整个项目只会有一个Vue实例对象vm,其他的都是VueComponent实例对象,2、VueComponent的实例对象,简称为vc,也称为组件实例对象,Vue的实例对象只有一个,称为vm3、VueComponent可以通过Vue.extend()方法创建个很多个vc。在项目里面的组件实例对象就是通过这种方式创建的。就是vc4、vm和vc很多东西都一样,但是vc可以有很多个,vm只能有一个,而且vm可以设置el指定渲染的容器,vc不行。
4、双向数据绑定
1、填写表单的时候,双向绑定可以在不操作DOM的前提下,自动把用户填写的内容同步到数据中。页面结构<->vue(监听数据的变化,数据发生改变)<->页面发生变化form表单负责采集数据,ajax负责提交数据用户不需要手动操作dom元素,来获取表单数据页面上表单采集的数据发生变化的时候,会被vue自动获取到,并更新到js数据中。
4-MVVM核心原理(数据驱动和双向绑定的原理)
1、MVVM是vue实现数据驱动视图和双向数据绑定的核心原理。MVVM指的 是Model、View、ViewModel,把每个页面都拆分成了这三个部分。Model表示当前页面渲染时所以来的数据源View表示当前页面所渲染的DOM解构ViewModel表示Vue的实例,是MVVM的核心。就是vue
2、ViewModel作为MVVM的核心,是把当前页面的数据源和页面的结构连接在了一起。view 《--(自动更新,监听DOM变化)--》ViewMOdel《---(监听数据变化,自动同步)--》Model当数据源发生变化是,会被ViewModel监听到,VM会根据最新的数据源自动更新页面的结构。当表单的值发生变化时,也会被VM监听到,VM会把变化过的最新的值自动同del数据源中
5、Vue的版本
1.0版本基本被淘汰,
2.x版本是目前企业级项目开发中的主流版本
3.x的与2020年-09发布,现在已经是默认版本了,但是还没有普遍使用
vue的作者:尤雨溪,是中国人开发的前端框架
react和angular都是外国人开发
比较简单
6、Vue的基本使用
1、导入vue.js的script脚本文件
2、在页面中声明一个将要被vue所控制的DOM区域
3、创建一个vue实例
4、实例里面选择渲染的区域,定义要渲染的数据变量,<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><!-- 1、引入vue的js文件,有vue这个构造函数 --><script src="../lib/vue.js"></script>
</head><body><!-- div控制页面,需要被vue控制 --><!-- 数据渲染:插值语法,可以把数据渲染到页面 --><div id="app">{{username}}</div><script>// 2、创建一个vue实例对象const vm = new Vue({// 3、el属性是固定的写法,表示vm实例要控制页面上的// 哪一个区域,接收的值是一个选择器el:'#app',// data是数据,所有用到的边浪在data里面定义// 然后渲染到页面上去// 这里是对象形式data:{username:'xiaohong'}})</script></body></html>
el指向的选择器选择的div就是view视图区域,data指向的对象就是MOdel数据源,new Vue是构造函数,创造了一个vm实例对象,就是viewModel。
7、配置Chrome浏览器的vue-devtools
1、插件已经下载好。可以直接使用
8、Vue的指令和过滤器
1、指令是VUe为开发者提供的模板语法,辅助开发者渲染页面的基本结构
2、指令按照不同的用途,分为六大类1、内容渲染指令2、属性绑定指令3、事件绑定指令4、双向绑定指令5、条件渲染指令6、列表渲染指令
8-1、内容渲染指令
1、内容渲染指令用来辅助开发者渲染DOM元素的文本内容,常用的内容渲染指令有3个1、v-text:会覆盖元素内部原有的内容,实际开发用的不多2、{{}}:插值表达式,不会覆盖默认文本,解决v-text的问题,可以在括号里面加点空格,内容占位符,只能用在内容节点,不能用在元素的属性节点。还3、v-html:其他两种只能渲染纯文本内容,该指令能把包含html标签的字符串渲染为页面的html元素,
2、总结:v-html渲染html标签,v-text和{{}}渲染纯文本,但是v-text会覆盖原本的内容,用的最多的是{{}}<!-- 1、插值语法 --><!-- 纯文本 --><div>{{username}}你好</div><!-- 2、v-text --><div v-text="username"> 你好</div><!-- 3、v-html --><div v-html="username">你好</div><!-- 渲染html标签 --><div v-html="ht"></div>
8-2、属性绑定指令(v-bind)
1、插值表达式只能用在内容节点中,不能用在元素节点中
2、v-bind: 给元素的属性动态绑定属性值,可以省略v-bind,保留 :<input type="text" placeholder="{{info}}"><!-- 在这里就表示给默认值绑定info --><input type="text" v-bind:placeholder="info" ><img v-bind:src="photo" alt=""><!-- 简写方式:省略v-bind --><img :src="photo" alt="">
3、注意:如果要用v-bind进行字符拼接,记得给字符串加上''
4、v-bind里面是js语句,
使用javascript表达式
1、在vue提供的模板渲染语法中,除了支持简单的数据值之外,还可以可以进行javascript表达式的运算<!-- 内容绑定指令 --><!-- 1、加法 --><div>{{ num +6 }}</div><!-- 2、三元表达式 --><div>{{ 5 > 4 ? 6 : 10}}</div><!-- 3、字符串运算 --><div>{{str.split("").reverse().join("")}}</div><!-- 4、属性绑定指令 --><!-- 字符串拼接 --><div :id="'list-'+'h'"></div>
8-3、事件绑定指令
1、v-on事件绑定:为DOM元素绑定事件监听,语法格式 v-on:事件名称="事件函数的名字"<button v-on:click="add">按钮</button>
2、绑定事件并传参:绑定方法的时候可以加小括号,可以不加,如果要传递参数,就加小括号<div id="app"><div>{{ num }}</div><button v-on:click="add(5)">按我+5</button></div><script>const vm = new Vue({el: "#app",data:function(){return {num: 5,}},methods: {add(n){this.num+=n}},})</script>
3、v-on的简写形式:@语法格式 @事件名称="事件函数的名字"
4、其他事件把原生事件的on去掉kyeup click
5、如果没有传递参数,那么我们默认可以接收到一个事件对象:e
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="../lib/vue.js"></script>
</head><body><div id="app"><button @click="add">按我输出事件对象</button></div><script>const vm = new Vue({el: "#app",data:function(){return {num: 5,}},methods: {add(e){console.log(e);}},})</script>
</body></html>
6、可以通过这个事件对象获取到绑定事件的元素,然后对该元素进行修改<div id="app"> <button @click="add">按我输出事件对象</button></div><script>const vm = new Vue({el: "#app",data:function(){return {num: 5,}},methods: {// 如果没有传递参数,那么我们默认可以接收到一个事件对象:e// 可以通过这个事件对象获取到绑定事件的元素,然后对该元素进行修改add(e){e.target.style.backgroundColor="red"e.target.style.fontSize="50px"}},})</script>
7、但是这样写太复杂了,所以vue给我们提供了一个内置变量:$event,就是原生的事件对象通过绑定函数的时候传递进去,函数就会接收到这个事件对象,固定写法<button @click="add(1,$event)">按我输出事件对象</button>
8、事件修饰符:阻止默认事件的发生以前:在函数里面写e.preventDefault()现在:在绑定事件的后面写 .prevent1、<a href="https://www.baidu.com" @click="run">阻止跳转</a><br>run(e){e.preventDefault();console.log("阻止成功");},2、<a href="https://www.baidu.com" @click.prevent="run">事件修饰符阻止跳转</a>jump(){console.log("阻止成功");}
9、因为调用e.preventDefault和e.stopPropagation是常见需求,所以vue提供了事件修饰符的概念,来帮助程序员更方便的对事件的触发进行控制。常见的5个事件修饰符如下:.prevent:阻止默认行为.stop:阻止事件冒泡.once:只触发一次.self:只有在触发对象是当前元素自身触发时触发事件处理函数.caputre:以捕获模式触发当前的事件处理函数
10、按键修饰符:在监听键盘事件的时候,我们经常需要判断详细的按键,可以为键盘相关的时间添加按键修饰符,例如:<!-- 在key表示是”enter的时候,调用 .--><input type="text" @keyup.enter="ll($event)" > <!-- 在key表示是”esc"的时候,调用 .--><input type="text" @keyup.esc="gg($event)" >
8-4、双向绑定指令
1、vue提供了v-model双向数据绑定指令,快速获取表单的数据
2、双向绑定之后,vue的数据会随着表单的改变发生改变<input type="text" v-model="username"><div>{{username}}</div>
3、v-model指令只能和表单元素进行使用1、input输入框2、select3、textrea
4、为了方便对用户输入的内容进行处理,vue为v-model提供了3个修饰符.number:将用户的输入值转为数值类型<input type="text" v-model.number="n">+ <input type="text" v-model="s">={{n+s}}.trim:自动过滤用户的收尾空白字符<input type="text" v-model="search" @keyup.enter="ff"><input type="text" v-model.trim="search" @keyup.enter="ff">.lazy:在change时而非input时更新,在中间更新的时候不会改变,用的很少
8-5、条件渲染指令
1、条件渲染指令用来控制DOM的显示与隐藏。有两个条件渲染指令:v-ifv-show<!-- v-if控制是否显示:满足条件 --><span v-if="s==6">6</span><span v-if="s==5">5</span><br><br><!-- v-show控制是否显示 --><span v-show="s==6">6</span><span v-show="s==5">5</span>
2、v-if 是通过让元素下树,隐藏该元素。动态的添加或移除元素,而v-show是通过style样式的display来隐藏或显示元素,如果要频繁的切换元素的显示形态,用v-show更好,如果有些元素不需要被展示,那么就用v-if。
3、 在实际开发中,不用考虑性能问题,直接使用v-if
4、还有一个v-else-if、v-else指令,v-else-if必须个v-if搭配使用,不然不会被识别
插件
1、vue 3 sinppets:
2、vetur:
3、yyr
8-6、列表渲染指令
1、v-for:列表渲染指令,基于一个数组来循环渲染一个列表结构,v-for需要用到iteminitems形式的特殊语法items是循环的数组item是循环数组的每一项元素<li v-for="item in arr">{{item}}</li>arr:["xiao","hong","lan","ming"]
2、谁在循环就给谁加v-for。
3、v-for还支持一个可选的第二参数,即当前项的索引,语法格式为(item,index) in items. <!-- 3、索引。(item,index) in items. --><ul><li v-for="(item,index) in arr2">索引{{index}}{{item.name}}</li></ul>4、官方建议,如果用到了v-for指令,那么一定要绑定一个 :key 属性,可以把index作为key值。必须是字符串或者数字类型,而且key值不允许重复,不然会报错,最好是把id值作为key值,因为key值要求具有唯一性<!-- 4、 :key属性 --><ul><li v-for="(item,index) in arr2" :key="index">索引{{index}}{{item.name}}</li></ul>
5、56-62跳过
9、过滤器
9-1、了解过滤器
1、过滤器(Filters):用于文本的格式化,可以用在两个地方,插值表达式和v-bind属性绑定,只能在vue3里面使用
2、过滤器应该被添加在javascript表达式的尾部,由管道符进行调用,管道符就是竖线 |
3、过滤器函数必须被定义在filters这个节点下面,这个节点对象和data平级,过滤器本质是一个函数,自己定义。过滤器中一定要有一个返回值。主要是为了进行文本的格式化,所以过滤器函数的传递的参数都是管道符前面那个值<span>{{ msg | capi }}</span>
<script>// 过滤器函数必须被定义在filters这个节点下面,// 这个节点对象和data平级,filters:{// 过滤器本质是一个函数,自己定义。过滤器中一定要有一个返回值capi(val){// 主要是为了进行文本的格式化//在进行文本的首字母大写return val.charAt(0).toUpperCase()+val.slice(1);}},
</script>
4、注意点:1、要定义到filters节点下,本质是一个函数2、在过滤器函数中,一定要有return,也就是返回值
9-2、全局过滤器和私有过滤器
1、定义在vue中的filters是私有过滤器,只能在当前的vue实例中使用<body><div id="app"><span>{{ msg | capi }}</span></div><div id="app2"><span>//使用不了这个capi过滤器,因为是定义在vm里面的,属于私有过滤器{{ msg | capi }}</span></div><script>const vm = new Vue({el: '#app',data: {msg: "hello world",arr: []},// 过滤器函数必须被定义在filters这个节点下面,// 这个节点对象和data平级,filters: {// 过滤器本质是一个函数,自己定义。过滤器中一定要有一个返回值capi(val) {// 主要是为了进行文本的格式化return val.charAt(0).toUpperCase() + val.slice(1);}},methods: {add() {this}},})const vm2 = new Vue({el: "#app2",data: {msg: "hello world",arr: []},})</script></body>
2、被定义在vm实例里面的过滤器只能在当前所控制的el区域使用,如果希望在多个vue实例之间共享过滤器,则可以按照下面面的格式定义全局过滤器Vue.filter()方法接收两个参数,1):是全局过滤器的名字2):全局过滤器的处理函数<body><div id="app"><span>{{ msg | capi }}</span></div><div id="app2"><span>{{ msg | capi }}</span></div><script>// 首先,这个全局过滤器应该定义在vm实例前面,// 然后使用Vue。filter定义全局过滤器Vue.filter('capi', (val) => {return val.charAt(0).toUpperCase() + val.slice(1)})const vm = new Vue({el: "#app",data: {msg: "hello"}})const vm2 = new Vue({el: "#app2",data: {msg: "hello world",arr: []},})</script>
</body>
3、如果全局过滤器和私有过滤器名字冲突,按照就近原则,优先使用私有过滤器
4、可以连续的使用多个过滤器{{ msg | capi | capi2 }}表示递增使用,后面一个过滤器使用前面一个过滤器使用后的结果
5、因为过滤器是函数,可以接收参数,但要注意,接收参数的时候要从第二个位置开始,因为第一个是接收的管道符的文本
6、vue3是没有过滤器的7、yyr
10、侦听器
10-1、侦听器了解
1、侦听器:watch,监听数据的变化,针对数据的变化做特定的操作,侦听器本质上也是一个函数,监听谁就去watch里面定义一个和变量名字一样的函数,并做出响应。watch和data、methods是平级关系,表示监听数据的变化<body><div id="app"><div>{{num}}</div><button @click="num++">num++</button></div><script>const vm = new Vue({el: "#app",data: {num:5},// 监听器,监视数值的变化watch:{num(){console.log("num发生变化");}}})</script>
</body>
2、侦听器的函数里面可以有两个参数,分别是变量的新值和旧值watch:{num(newval,oldval){console.log("num发生变化");console.log(oldval);console.log(newval);}}
3、侦听器的格式分为:1)、方法格式的侦听器缺点:无法在刚进入页面的时候,自动触发如果侦听的是一个对象,对象的属性发生变化不会触发监听2)、对象格式的侦听器优点:可以通过immediate选项让侦听器自动触发一次可以通过deep选项深度监听<script>watch:{// 对象格式的侦听器// 有一个handler的处理函数num:{handler(){console.log("num发生变化");},// 默认值是false// ,控制监听器是否触动触发一次immediate:true},}</script>
4、最好使用方法格式的,简单一点
10-2、深度监听
1、 对象格式的监听器可以通过deep:true这个属性监听对象的属性的改变,任何一个对象的属性发生改变都会触发这个监听器。而这是方法格式的监听器是做不到的<body><div id="app"><input type="text" v-model="student.name"></div><script>const vm = new Vue({el: "#app",data: {student:{name:"小红",age:18,score:99}},watch:{// 对象格式的监听器可以通过deep:true这个属性// 监听对象的属性的改变student:{handler(){console.log("student发生变化");},deep:true},}})</script>
</body>
2、方法格式监听对象的子属性的变化,必须包裹一层单引号。'student.name'(){console.log("'student.name'发生变化");}
11、计算属性
11-1、了解计算属性
1、计算属性是指通过一系列的运算后,最终得到一个属性值。这个动态计算出来的属性值可以被模板结构或methods方法使用
2、computed和el,data都是平级,都是属于vm这个实例对象的。是以对象的形式书写的。所有的计算属性都要定义到computed节点下面,计算属性在定义的时候,要定义成”方法格式”
3、使用说明:1、这个计算属性是计算某个具体的变量,是一个函数方法,我们要把它定义在computed里面。2、这个函数方法有一个返回值,3、直接使用这个函数,把他当做一个变量来使用,它的返回值就是计算的那个变量的值<body><div id="app">{{gaibian }}</div><script>const vm = new Vue({el: "#app",data: {num: 5},// 计算属性computed: {gaibian() {return this.num * 5}}})</script>
</body>
4、声明的时候是方法格式,使用的时候是变量格式好处:1)、实现代码的复用,2)、只要计算属性中的数据源发改变,使用到的计算属性也会改变
模板字符串
模板字符串语法:es5写法:需要使用大量的“”(双引号)和 + 来拼接才能得到我们需要的模版实例:"He is <b>" + person.name + "</b> and we wish to know his" + person.age + ".That is all" es6写法:用`(反引号)标识,用${}将变量括起来实例:`He is <b> ${person.name} </b> and we wish to know his ${person.age} .that is all`就是说,用``反引号将整句话包裹进去,然后把变量用${}包裹{{`He is ${age}`}}<br><br>{{ `${name} 已经 ${age} ,她的身高 ${h}` }}<!-- 属性渲染 --><div :style="`background:rgb(${r},${g},${b})`"></div>
12、axios
1、axios是一个专注于数据请求的库,就是简化封装了ajax和promise的一个库,vue和react都会用这个
<body><div id="app"><button @click="fn">按我获取数据</button>{{res}}</div><script>const vm = new Vue({el: "#app",data: {res:{}},methods: {async fn() {const p = await axios.get('http://182.92.193.159:5050/allcmc')this.res=p.data }},})</script>
</body>
2、axios请求数据时,可以通过传递的参数获取自己想要的数据,传递参数使用data:{}const res = await axios.get("http://www.zt-it.com:5000/student", {params:{}})
3、axios的方法:axios.get() ,axios.post(),axios.delete(),axios.put()
13、Vue-cli
13-1、单页面应用程序
1、单页面就是一个Web网站里面只有一个唯一的一个html页面,素有的功能与交互都在这个唯一的一个页面内完成。
2、vue-cli是vue.js开发的标准工具,简化了程序员基于webpack创建工程化的vue项目的过程
3、中文官网地址:https://cli.vuejs.org/zh/
4、vue-cli是npm上的一个全局包,可以使用npm install命令安装
5、通过 vue create 项目的名称 就可以创建项目,最后一个表示让你自己手动选择需要的环境,然后进入下一步,*表示已经选择,第一项必须选择,表示vue的版本。按下空格键选择。eslint规定格式很严格,最好别选,bavel选择在独立的配置文件中
13-2、项目文件结构
git: 是一个为git客户端增加git工具,用于存储自己的版本库(或者叫.svn根据自己的配置会有不同名字的版本库)
|- biuld: vue2.0的配置,项目打包时候的配置文件(现如今的vue项目,可使用vue.config.js进行打包配置)
|- node_modules: node的一些基础依赖包,可能还有拓展的安装的别的插件(npm install下载的依赖包,主要是根据package.json获取对应的依赖包)
|- public: 存放一些主要的打包文件,如index.html等等,可以放置一些需要在index.html配置的文件|- src:项目的主文件夹(vue是SPA单页面应用,可以看做是一个主页面的应用里面的内容组件详情可看vue 代码格式解析)|- assets: 资源文件,用于存放一些静态文件,如字体、图片、css样式之类的|- components: vue主要内容的公共组件,可以进行复用|- router: 设置路由,指定路由对应的组件|- route: main.js中的router是通过router文件映射,而router下的index.js是项目链接的关键,通过设置路径将views中的vue文件关联起来|- main.js:项目的主js,全局使用的各种变量、js、插件都在此定义和引入;整个项目先加载src里的main.js,通过里面的app元素生成vue对象,再将router里面的路由加载进去,结果在app的vue中呈现|- app.vue: 项目的入口文件|- store:放置vuex需要的状态关联文件,设置公共的state等,是公共数据管理器,关联页面都可随时访问数据,是一个专为vue.js应用开发的状态管理模式,集中式存储管理应用的所有组件的状态|- test: 测试文件目录|- .editorconfig: 是用来帮助开发者定义和维护代码风格(行尾结束符、缩进风格等)editorconfig配置文件网
|- .env: 全局默认配置文件,无论什么环境都会加载合并.env.development:开发环境下的配置文件
.env.development: 开发环境下的配置文件
npm run serve(或者npm run dev 主要看 package.json) 会合并 .env 文件
.env.production: 生产环境下的配置文件
npm run build 会合并 .env 文件
|- .eslintignore: 指定忽略的文件,不需要eslint校验文件; eslint校验对不符合规范代码报错
|- .eslintrc.js: eslintrc的配置文件,vue项目自带的文件,各个eslint配置项的作用;ESlint是一个检查代码的工具
|- .gitignore: 可以避免在提交代码时把我们不想上传的文件提交到git中; LICENSE:开源协议的说明
|- package.json: 记录作者、项目入口、项目描述、项目依赖等相关信息
|- pnpm-lock.yaml: 记录详细的依赖版本
|- postcss.config.js:插件,利用js插件对CSS进行转换
|- prettier.config.js: 配置文件,保持代码风格统一
|- README.md: 项目用的到的所有插件的json格式
|- stylelint.config.js:让CSS样式代码在编辑、保存、提交git的时候按规范进行检查及美化
|- tsconfig.json: 配置文件
13-2-1、项目外部文件
1、.gitignore:不接受git管理的文件或文件夹
2、babel.config.js:babel的控制文件。
3、package.json:配置的各种信息,依赖、各种信息。build:构建,最后一次编译,编译成html、jslint:进行语法检查
4、package-lock.json:包版本控制文件。
13-2-2、src
1、assets:存放项目的静态资源文件夹,比如:css样式表、图片资源
2、components:程序员封装的、可复用的组件。
3、main.js是项目的入口文件,整个项目的运行,要先执行main.js
4、app.vue 项目的主页,被main.js渲染到public的index.html文件里面
13-2-3、main.js构成:项目最先运行,渲染App组件
1、导入vue,得到vue构造函数import Vue from 'vue'2、导入App.vue这个根组件,要把模板解构渲染到html页面中这个组件是所有组件的父组件。受vm管理import App from './App.vue'3、关闭vue的生产提示Vue.config.productionTip = false4、创建Vue的实例对象new Vue({//把render函数指定的组件渲染到html文件中//mounet是挂载,相当于:el:“#app”render: h => h(App),}).$mount('#app')
// 引入残缺版的vue,残缺版的vue不能自己渲染页面
// 只有完整版的vue能够渲染,
// vue由两部分组成:核心(生命周期、路由)+模板解析器
// 节省空间,残缺版去掉了模板解析器,通过render函数
// 去渲染页面
import Vue from 'vue'
import App from './App.vue'Vue.config.productionTip = falsenew Vue({//render:渲染// h是一个函数,
// h去渲染元素render: h => h(App),}).$mount('#app')
yyr
651908398
13-2-4、App.vue
1、所有组件的根组件
2、整个项目只有一个vm实例,就在app.vue创建。
3、用来编写待渲染的模板结构,index.html中预留一个el区域,让main.js把app.vue渲染到了index.html预留的区域中
13-2-5、index.html配置
<!DOCTYPE html>
<html lang=""><head><meta charset="utf-8"><!-- 针对IE浏览器的一个特殊配置,让IE浏览器以最高的渲染级别渲染页面--><meta http-equiv="X-UA-Compatible" content="IE=edge"><!-- 开启移动端的理想视口 --><meta name="viewport" content="width=device-width,initial-scale=1.0"><!-- 配置页签图标 ,<%= BASE_URL %>:路径的写法:相当于 ./ --><link rel="icon" href="<%= BASE_URL %>favicon.ico"><!-- 配置网页的标题。找到package.json的name属性 --><title><%= htmlWebpackPlugin.options.title %></title></head><body><!-- noscript:如果浏览器不支持js,这里面的元素就会被渲染 --><noscript><strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><!-- 容器 --><div id="app"></div><!-- built files will be auto injected --></body>
</html>
13-2-6、改变入口文件
1、 https://cli.vuejs.org/zh/config/#pages
2、 创建一个vue.config.js文件,然后再去官网的配置参考里面找到pages,选择代码
粘贴到创建的文件里面,去掉多余的module.exports = {pages: {index: {// page 的入口entry: 'src/index/peiqi.js',}}}
13-2-7、关掉语法检查
1、 https://cli.vuejs.org/zh/config/#pages
2、 创建一个vue.config.js文件,然后再去官网的配置参考里面找到lintOnSave,把配置拿过 lintOnSave:false module.exports = {pages: {index: {// page 的入口entry: 'src/index/peiqi.js',}},lintOnSave:false}
13-2-8、vue单文件
1、组件化开发:根据封装的思想,把页面上可重用的UI结构封装为组件,方便项目的开发和维 护
2、vue是一个支持组件化开发的前端框架,组件的后缀名是.vue,
3、vue文件的组成部分,组件是对UI结构的复用1、template:组件的模板结构,2、script:组件的javascript行为3、style:组件的样式
4、export defalut:默认导出,有引入就要有导出
5、组件中的data必须定义为函数类型,返回一个对象,因为每个组件都有属于自己的数据,避免数组重复,所以每个组件的数据通过data这个函数得到自己的数据
6、可以安装Vetur可以使用快捷键<得到vue文件的模板
7、组件必须只能由一个根节点。
13-3、组件之间的关系
1、组件在被封装好以后,没有引入关系的时候,是相互独立的,不存在父子关系
2、如果在使用组件的时候,根据彼此的嵌套关系,形成了父子关系、兄弟关系
3、父组件引入子组件的步骤1:使用import语法导入需要的组件2、使用compoents节点注册组件 键值一样可以简写3、以标签的形式使用刚才注册的组件
4、通过components注册是私有子组件
5、使用 <右键可以直接生成vue组件
6、组件分为私有组件和全局祖册组件
13-3-1、使用@代替src的方法
1、下载一个插件 Path Autocomplete
2、选择 齿轮-设置-打开设置
3、复制代码到最前面//导入文件时是否携带文件的扩展名"path-autocomplete.extensionOnImport":true,//配置@的路径提示"path-autocomplete.pathMappings":{"@":"${folder}/src"}
4、然后就可以引入了
import Self from '@/components/Self.vue'
(案例:two)
13-3-2、注册全局组件
1、注册一次,全局都可以使用
2、在vue项目的main.js入口文件中,通过Vue.component()方法,可以注册全局组件// 导入需要全局注册的组件import Self from '@/components/Self.vue'// 参数1:字符串格式,表示组件的”注册名称“// 参数2:需要背全局注册的那个组件Vue.component('MySelf',Self)
3、注册完以后就可以通过注册名称直接引入这个组件了
main.js文件
// 引入残缺版的vue,残缺版的vue不能自己渲染页面
// 只有完整版的vue能够渲染,
// vue由两部分组成:核心(生命周期、路由)+模板解析器
// 节省空间,残缺版去掉了模板解析器,通过render函数
// 去渲染页面import Vue from 'vue'
import App from './App.vue'Vue.config.productionTip = false// 导入需要全局注册的组件
import Self from '@/components/Self.vue'// 参数1:字符串格式,表示组件的”注册名称“
// 参数2:需要背全局注册的那个组件
Vue.component('MySelf',Self)new Vue({render:h=> h(App)}).$mount('#app')
14、组件之间的通信(分享数据)
14-1、props(父组件给子组件传递数据->自定义属性)
1、props:是组件的自定义属性,在封装通用组件的时候,合理的使用props可以极大地提高组件的复用性(自我总结:就是说每个组件(vue文件)都有这个属性。但如果这些文件的初始值不一样,而且被映射到一个文件上面,就可以使用props)
(被引入的组件是子组件,引入组件的是父组件。在父组件里面把属性传给子组件,子组件使用 props接收)2、props的语法格式:props:["自定义属性1","自定义属性2"]是一个数组,和data等平级关系,里面的属性用字符串包裹3、子组件使用props接收父组件的步骤:(父组件是App.vue,子组件是father.vue)1、在引入组件的时候,在父组件里面使用子组件的标签对里传值 <Father :count="count"></Father>2、在子组件里面接收props:['count']3、使用这个属性 注意:子组件的这个属性改变不会影响到父组件的属性发生改变4、 props可以传递具体的值,也可以传变量,是自定义属性。在传值的时候为当前组件指定初始值。这个自定义属性是封装者自己定义的。可以极大地提高组件的复用性5、props传递变量的三种方式1、传递的是字符串<Son count="9"></Son>2、传递的是数值<Son :count="9" ></Son>3、传递的是变量<Son :count="count" ></Son>因为 :代表v-bind,里面是js语句,相当于count=96、props的数据,可以直接在模板结构中被使用,并且,子组件不要修改props接收到的值,会报错。7、vue规定,组件中封装的自定义属性是只读的,程序员不能直接修改props的值,不然会直接报错。8、可以把props值传给datanum:this.count9、props的default值,来定义属性的默认值。写成对象的形式,一般是在组件没有传递该属性时候,则默认值生效props:{count:{default:5}}10、props的type值类型,设置属性的类型,传入的值必须是该类型props:{count:{default:5,type:Number}}11、props的required:必填,要求必须传递该属性的值props:{count:{default:5,required:true}}12、简答类型复制的是值,复杂类型的是引用地址。13、yyr
14-2、子组件向父组件传递数据(使用自定义事件)
1、子组件可以通过自定义时间向父组件传递数据。1、在子组件中自定义一个事件,使用 this.$emit('btn-click', item)的语法,emit指代发射事件,btn-click是我们自定义的事件名,item是子组件中的数据。 注意::vue官方推荐你始终使用 kebab-case格式的事件名。2、在父组件中使用v-on监听在子组件中我们自定义的数组,并为其在父组件中定义一个接收监听的事件3、在父组件中接收数据
<button @click="add">点我传送数据给父组件App</button>methods: {add(){this.$emit('num',this.message)}},
<Son @num="add"></Son>methods: {add(n){console.log(n);}},
14-3、兄弟组件之间的数据共享(EventBus:全局事件总线,可实现任意组件通信)
1、创建一个eventBus.js模块,并向外共享一个Vue的实例对象2、在数据发送方,调用bus.$emit("事件名称",要发送的数据)方法触发自定义事件3、在数据接收方,调用bus.$on("事件名称",事件处理函数)方法注册一个自定义事件
1、自定义一个eventBus.jsimport Vue from 'vue'export default new Vue()
2、在数据发送方,引入这个文件。再定义一个事件,然后通过这个事件调用bus.$emit("事件名称",要发送的数据)方法触发自定义事件<template><div><!-- 数据发送方 --><button @click="send">发送数据</button></div>
</template><script>
import bus from '@/components/eventBus.js'
export default {data() {return {msg:"好好学习,天天向上"}},methods: {send(){bus.$emit("num",this.msg)}},}
</script>
3、在数据接收方,使用create生命周期函数调用bus.$on("事件名称",事件处理函数)方法注册一个自定义事件
<template><div><div>接收方{{str}}</div></div>
</template><script>
import bus from '@/components/eventBus.js'
export default {data() {return {str:""}},created() {bus.$on("num",val=>{this.str=val})},}
</script>
14-4、vuex(状态管理)
vuex官方解释
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
14-4-1 、vuex的概念
1、概念:专门在vue中实现集中式状态(数据)管理的一个插件 Vue.use()。对vue应用中的多个组件的共享状态进行集中式状态 数据 管理(读/写)。也是一种组件间通信的方式,且适合用于任意组件间的通信
14-4-2、什么时候使用vuex(共享)
1、多个组件依赖于统一状态(多个组件需要用到同一个数据,就可以让vuex来管理这个护具)2、来自不同组件的行为需要变更同一状态(需要改变这同一个数据)
14-4-3、vuex工作原理图
每一个 Vuex 应用的核心就是 store,里面又包括:1. State(状态):用于数据的存储(对象类型数据),是store中唯一数据源2. Actions(行为):类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步事件3. Mutations(转变):类似函数,改变state数据的唯一途径,且不能用于处理异步事件。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方4. Getter(数据加工):如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关计算5. Module:类似于命名空间,用于项目中将各个模块的状态分开定义和操作,便于维护由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块。
vuex工作原理说明
1、,actions、mutations,state2、actions:动作、行为3、mutations:维修,加工4、state:状态,把数据交给vuex的state对象进行保管。5、dispatch:分发,派遣。
14-4-4、vuex的搭建环境
1、安装vuexnpm i vuex@32、在main.js里面设置vue.use(Vuex)import Vuex from 'vuex'//就可以配置store项Vue.use(Vuex)3、在src里面创建一个文件夹store,创建一个index.js用于创建vuex中最核心的store,在js文件里面创建三个对象 // 准备actions-用于响应组件中的动作const actions={}// 准备mutations-用于操作数据const mutations={}// 准备dtate-用于存储数据const state={}然后创建一个store对象来管理这几个对象因为store是通过Vuex的Store创建的。所以我们要引入Vuex// 引入Vuex创建storeimport Vuex from 'vuex'然后创建storeconst store =new Vuex.Store({actions,mutations,state})// 向外暴露,因为主要是要的是store,所以暴露的是store
export default store4、在main.js引入这个store,所有的组件对象能看见这个 store// 引入storeimport store from './store'//配置new Vue({el:"#app",store,//render:渲染// h是一个函数,
// h去渲染元素render:h=> h(App)})5、报错,现这样错误的原因是在创建store实例之前,没有调Vue.use(Vuex),但这个时候会有人说,已经调用了Vue.use(Vuex),还是会出现这样的错误。究其原因是因为Vue脚手架会解析文件中的所有import语句,然后把所有import语句按照编写代码的顺序全都汇总在最上方,之后才会解析文件中的其它代码,这就会使得Vue.use(Vuex)在store实例之后执行。import引入最高级,会优先执行import的js,所以先创建store实例会报错。6、解决:在store.js,引入Vue后,在使用Vue.use(Vuex)import Vue from 'vue'Vue.use(Vuex)6、2022年7月,vue3成为了默认版本, 现在npm i vue,安装的就是vue3,vue3成为默认版本,vuex也更新到了4。4只能在vue3中使用,现在使用npm i vuex安装的是4版本
我们项目使用的是2版本,使用vuex4就会报错。所以我们要安装3版本
store.js
// 引入Vuex创建store
import Vuex from 'vuex'// 准备actions-用于响应组件中的动作
const actions={}// 准备mutations-用于操作数据
const mutations={}// 准备dtate-用于存储数据
const state={}// 创建store
// 因为store是管理// const store =new Vuex.Store({
// actions,
// mutations,
// state// })// 向外暴露,因为主要是要的是store
// export default store// 简写,创建并暴露store
export default new Vuex.Store({actions,mutations,state})
main.js
// 引入残缺版的vue,残缺版的vue不能自己渲染页面
// 只有完整版的vue能够渲染,
// vue由两部分组成:核心(生命周期、路由)+模板解析器
// 节省空间,残缺版去掉了模板解析器,通过render函数
// 去渲染页面
import Vue from 'vue'
import App from './App.vue'
// 引入vuex
import Vuex from 'vuex'
// 引入store
import store from './store'Vue.use(Vuex)Vue.config.productionTip = falsenew Vue({store,render:h=> h(App)
}).$mount('#app')
解决报错
store.js
// 引入Vuex创建store
import Vuex from 'vuex'
// 引入vue
import Vue from 'vue'// 准备actions-用于响应组件中的动作
const actions={}// 准备mutations-用于操作数据
const mutations={}// 准备dtate-用于存储数据
const state={}Vue.use(Vuex)// 创建store
// 因为store是管理// const store =new Vuex.Store({
// actions,
// mutations,
// state// })// 向外暴露,因为主要是要的是store
// export default store// 简写,创建并暴露store
export default new Vuex.Store({actions,mutations,state})
main.js
// 引入残缺版的vue,残缺版的vue不能自己渲染页面
// 只有完整版的vue能够渲染,
// vue由两部分组成:核心(生命周期、路由)+模板解析器
// 节省空间,残缺版去掉了模板解析器,通过render函数
// 去渲染页面
import Vue from 'vue'
import App from './App.vue'
// 引入vuex
import Vuex from 'vuex'
// 引入store
import store from './store'Vue.config.productionTip = falsenew Vue({el:"#app",store,//render:渲染// h是一个函数,
// h去渲染元素render:h=> h(App)})
// .$mount('#app')
14-4-5、vuex工作流程
1、state管理数据,所以把想让vuex管理的数据保存到state中。2、当我们想改变state保管的数据的状态的时候。就使用action保管的函数方法,使用dispatch方法将执行那个函数方法拍给action执行。this.$store.dispatch('函数方法',参与运算的数据参数)this.$store.dispatch('Jia',this.num)3、action函数里面响应这个方法,所以需要在action里面定义这个函数方法,使用对象格式,也可以简写,这个函数方法可以接收到两个参数,一个是context,这个上下文对象就包括了commit方法,可以函数方法名(context,n){函数体}4、action的这个函数方法可以接收到两个参数,一个是context,这个上下文对象就包括了commit方法,可以使用这个context对象调用commit方法,由 actions 提交一个 mutation。记住!!!这个函数方法名改为大写,为了区分mutation和action写的函数函数方法名(context,n){context.commit(‘函数方法名’,n){}5、在mutation里面准备定义这个函数,也有两个参数,a是state,b是传递的参数数据就可以通过a.数据和数据进行处理mutation={大写的函数方法名(a,b){}}
6、展示state里面的数据的写法$store.state.数据名7、actions决定业务逻辑是否调用mutation的函数,包括发送异步请求8、如果函数不需要什么业务逻辑,可以直接mutation对接,直接调用commit调用mutation里面的函数this.$store.commit('大写的函数方法名',参数数据)9、组件中地区vuex的数据,$stroe.state.sum 10、组件中使用actions的数据:$store.dispatch('action中的方法名',数据)$store.commit('mutation中的方法名',数据)(如果没有网络请求或起亚业务逻辑,可以绕过actions,直接commit)
工作流程
https://blog.csdn.net/JHY97/article/details/124045131?ops_request_misc=&request_id=&biz_id=102&utm_term=vuex%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E5%9B%BE&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-124045131.142^v87^control_2,239^v2^insert_chatgpt&spm=1018.2226.3001.4187
14-4-6、vuex的getters
1、getters其实就是store的计算属性,对state里面的状态进行过滤处理,用法与组件自身的计算属性一模一样。2、使用,和actions一样定义,然后和计算属性一样在里面定义方法,方法返回一个数值const getters={}然后把getters放到store里面export default newVVuex.Store({actions,mutations,state,getters}3、当state中的数据需要经过加工后再使用时,可以使用getters加工
14-4-7、vuex的mapState
1、mapState是什么用于帮助我们映射state中的数据为计算属性因为我们可以在组件的计算属性的方法里面,直接返回state里面的数据,而this.$store.state.数据 。如果返回state数据的函数方法太多,太麻 烦。mapState可以帮我们生成这种函数方法使用:先在需要映射的组件里面引入这个组件import {mapState} from 'vuex'在computed里面使用mapState生成函数方法mapState({方法名:"state里面的数据"})如果方法过多,我们可以解构的形式...mapState({方法名:"state里面的数据",方法名2:"state里面的数据2"})简写,把数据名用字符串括起来放在数组里面...mapState(['数据名1','数据名2'])2、mapGetters方法:用于帮助我们映射getters中的数据为计算属性和mapstate用法一致3、mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含 $store.commit(xxx)的函数和mapstate用法一致的话,会出错。传入的是鼠标事件,因为生成的函数没有参数,而mutation定义的参数里面是有value的,而默认是有一个事件对象,所以这个事件对象会在被作为value值传给mutations的value值...mapMutations({方法名1:"mutations里面的方法1",方法名2:"mutations里面的方法12"})解决方法:在调用的时候,把这个数传过去方法名1(n)4、mapActions方法:用于帮助我们生成与actions对话的方法,即:包含 $store.dispatch(xxx)函数和mapMuatations用法一致
14-4-8、vuex模块化
1、因为会有不用的功能,比如订单模块,用户模块,可以把这些模块分成不同的对象,统一配置actions,state,mutations,const 对象1={const actions={},const state={},const mutations={},const getters={}},const 对象2={const actions={},const state={},const mutations={},const getters={}}2、暴露store的时候,去掉actions,state,mutations,使用modules放置定义的对象,这里的a,b是别名export default new Vuex.Store({modules:{a:配置对象1,b:配置对象2}})3、简写,这样写的话,可以输出this.$store看一下export default new Vuex.Store({modules:{配置对象1,配置对象2}})4、计算属性使用的时候,这是将mapstate方法将a,b生成计算属性,将store的state下面的a,b作为计算属性的方法,返回这两个数据,因为它们是两个对象,所以可以使用a.属性名,b.属性名。...mapState(['a','b'])5、直接从配置对象里面拿到数据,表示从别名1里面拿去数据,但是只是这样肯定会报错,还需要给配置对象设置一个namespaced:true属性...mapState(‘别名1’,['a','b'])const 对象1={namespaced:true,const actions={},const state={},const mutations={},const getters={}},6、方法也是一样...mapMutations(‘别名1’,{方法名1:"mutations里面的方法1",方法名2:"mutations里面的方法1"})就可以调用这个方法,记得传参7、如果是直接调用commit方法,要找到具体的是哪一个配置对象的方法this.$store.commit('配置别名/配置方法名',传入的参数)8、获取配置对象的getters的方法this.$store.getters['配置别名/配置方法名']9、如果是直接调用dispatch方法,要找到具体的是哪一个配置对象的方法this.$store.dispatch('配置别名/配置方法名',传入的参数)10、模块化语法减少代码耦合,更好维护代码。让各种数据分类更加明确
14-4-9、vuex的详细用法
1、开启命名空间后,组件中读取state的数据1—自己直接读取this/$store.state.配置名.数据名2-借助mapState读取...mapState('配置别名',['数据名1','数据名2'])2、开启命名空间后,组件中读取getters的数据1—自己直接读取this.$store.getters['配置别名/配置方法名']2-借助mapGetters读取...mapGetters('配置别名',['方法名1','方法名2'])3、开启命名空间后,组件中调用dispatch1—自己直接dispatchthis.$store.dispatch('配置别名/配置方法名',传入的参数)2-借助mapActions生成方法,方法调用需要传递参数...mapActions('配置别名',['方法名1','方法名2'])或者...mapActions('配置别名',{组件定义的方法名:'配置对象的方法名'})4、开启命名空间后,组件中调用commit1—自己直接committhis.$store.commit('配置别名/配置方法名',传入的参数)2-借助mapMutations生成方法,方法调用需要传递参数...mapMutations('配置别名',['方法名1','方法名2'])或者...mapMutations('配置别名',{组件定义的方法名:'配置对象的方法名'})
14-5、消息订阅
个人省略
15、组件之间的样式冲突问题
1、默认情况下,写在.vue组件中的样式会全局生效,因此会很容易造成多个组件之间的样式冲突问题。原因是因为1、单页面应用程序,多有组件的DOM结构,都是基于唯一的index.html进行呈现2、每个组件中的样式,都会影响整个index.html中的DOM元素
2、解决样式冲突问题在style里面加上scoped,vue会自动为该组件的元素生成私有属性<style lang="less" scoped></style>
3、如果想在父组件里面改变子组件的样式,而其他引入了子组件的不会发生改变,那么,不仅要在该父组件定义scoped,还要在改变的样式前面加上一个前缀,这样的话就会变成一个后代选择器。/deep/ div{width: 200px;height: 200px;background-color: blue;}
16、生命周期
16-1、简单介绍
官网:每一个vue实例从创建到销毁的过程,就是这个vue实例的生命周期。在这个过程中,他经历了从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、卸载等一系列过程。
1、生命周期:是一个vue组件从 创建 ->运行->销毁 的整个阶段,强调的是一个时间段2、生命周期函数:是vue提供的内置函数,会伴随着组件的生命周期,自动按次序执行3、生命周期强调的是时间段,生命周期函数强调的是时间点4、组件创建阶段: beforeCreate(组件还没开始创建之前)、created(内存里面创建好,还没被渲染)、beforeMount(将要渲染的时候)、mounted(渲染好的时候,刚好看到组件的时候)5、组件运行阶段:beforeupdate(组件更新前)、updated6、created最重要,因为我们异步请求数据就是在这个周期函数里面
1、创建期间的生命周期函数:1)beforeCreate:实例刚在内存中被创建出来此时还未初始化完毕data和methods2)created:实例已经在内存中创建完毕此时 data和methods已经创建完毕 但此时还未开始编译模板3)beforeMount:此时已经完成模板的编译但是还未挂载到页面中4)mounted:此时已将编译好的模板挂载到了页面指定的容器中显示
2、运行期间的生命周期函数:1)beforeUpdate:状态更新之前执行此函数此时data中的状态值是最新的 但界面上显示的数据还是旧的因为此时还未开始重新渲染DOM节点2)updated:实例更新完毕之后调用此函数此时data中的状态值和界面上显示的数据都已完成了更新 界面已被重新渲染好了
3、销毁期间的生命周期函数:1)beforeDestroy:实例销毁前调用在这 实例仍然完全可用2)destroyed:Vue实例销毁后调用调用后 Vue实例指示的所有东西都会解除绑定 所有的事件监听器会被移除 所有的子实例 也会被销毁
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ISgI4l6Z-1686141820663)(C:\Users\Direct\Desktop\常用前端框架及工具\拓展学习资料\生命周期函数.png)]
组件创建阶段
<template><div id="app"><h3></h3></div>
</template><script>export default {name: "App",components: {},data() {return {count:5}},beforeCreate(){console.log(this.count);},created(){//异步请求数据使用该函数console.log(this.count);console.log(document.querySelector("h3"));// data和methods已经创建完毕 但此时还未开始编译模板,所以不能操作dom// document.querySelector("h3").innerText="Hello"},beforeMount(){//还没有渲染// document.querySelector("h3").innerText="Hello"},mounted(){//编译好已经挂载到页面上,最早操作dom元素document.querySelector("h3").innerText="Hello"}};
</script>
组件运行阶段
<template><div id="app"><h3>生命周期</h3><h4>{{ count }}</h4><button @click="count++">count++</button></div>
</template><script>export default {name: "App",components: {},data() {return {count:5}},beforeUpdate(){// data中的状态值是最新的 但界面上显示的数据还是旧的console.log(this.count);console.log( "h4的值"+document.querySelector("h4").innerHTML);},updated() {//数据和模板结构完成同步//为了操作大哦最新的dom结构,必须写到upDate声明周期函数console.log(this.count);console.log( "h4的值"+document.querySelector("h4").innerHTML);},};</script>
17、ref引用(Vue用来操作DOM元素的)
1、ref是用来辅助开发者在不依赖jquery的情况下,获取DOM元素或组件的引用2、每个vue的组件实例上,都包含一个$refs对象,里面存储着对应的DOM元素激活组件的引用。默认情况下,组件的$refs指向一个空对象3、给一个Dom元素定义一个ref属性,然后取一个名字,就可以通过$refs.名字对这个DOM元素进行操作4、如果想要使用ref引用页面上的组件实例,还可以给组件使用ref。然后通过this.$refs.组件的ref的名字.fn(),就可以运行该组件的方法
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="../lib/vue.js"></script>
</head><body><div id="app"><span ref="s">使用ref操作dom元素</span><button @click="fn">输出this</button></div><script>const vm = new Vue({el:"#app",methods: {fn(){console.log(this.$refs.s);}},})</script>
</body></html>
根组件引用Ref组件过后,通过ref属性使用他的方法
<template><div id="app"><button @click="fn">App:按我输出组件r的方法</button><br><br><Ref ref="r"></Ref></div></template><script>
import Ref from '@/view/Ref.vue'export default {name: "App",components: {Ref},data() {return {}},methods:{fn(){this.$refs.r.fn()}}};</script>
17-1、this.$nextTick()方法
1、this.$nextTick()方法主要是用在随数据改变而改变的dom应用场景中,vue中数据和dom渲染由于是异步的,所以,要让dom结构随数据改变这样的操作都应该放进this.$nextTick()的回调函数中。2、created()中使用的方法时,dom还没有渲染,如果此时在该钩子函数中进行dom赋值数据(或者其它dom操作)时无异于徒劳,
所以,此时this.$nextTick()就会被大量使用,而与created()对应的是mounted()的钩子函数则是在dom完全渲染后才开始渲染数据,
所以在mounted()中操作dom基本不会存在渲染问题。3、就是数据发生改变了,但是页面还没有反应过来,就需要使用这个this.$nextTick(),等待数据渲染后应用在dom里面,需要dom重新渲染的时候就需要用到这个方法。把回调推迟到下一个DOM更新周期之后执行
this.$nextTick(()=>{函数体
})
18、动态组件
1、动态组件指的是动态切换组件的显示和隐藏2、vue提供了一个内置的<component>组件,专门用来实现动态组件的渲染,作用:组件的占位符,is属性的值:表示要渲染的组件的名字。而且,is属性的值,应该是组件在components节点下的注册名称。也就是必须是引入的组件,注册过后,才能使用。3、可以把这个<component>看做一个组件的占位符。但是直接使用会报错,未知的元素错误,因为这个元素还没有被定义。4、在component组件里面使用is属性选择要渲染的组件<component is="Hello"></component><component is="Hi"></component>5、对于飘红线显示错误的情况,使用v-bind绑定is属性,然后使用反引号括起来组件名字<component :is="`Hello`"></component><component :is="`Hi`"></component>6、组件的切换,会不断的创建和销毁,字符串的值用单引号括起来,is属性绑定str<div id="app"><nav>App根组件<button @click="str = 'Hello'">切换为Hello组件</button><button @click="str = 'Hi'">切换为Hi组件</button> </nav><component :is="str"></component></div>7、使用keep-alive保持让组件隐藏的时候不会被销毁,直接使用<keep-alive></keep-alive>标签将切换的动态组件括起来<div id="app"><nav>App根组件<button @click="str = 'Hello'">切换为Hello组件</button><button @click="str = 'Hi'">切换为Hi组件</button> </nav><keep-alive><component :is="str"></component></keep-alive></div>8、打开vue调试工具,在切换inactive表示被缓存了,没有被销毁9、如果想在组件被缓存的时候做什么,在组件被激活的时候做什么,有对应的生命周期函数当组件被缓存的时候,会自动触发组件的deactivated生命周期函数当组件被激活的时候,会自动触发组件的activated生命周期函数
created() {console.log("Hello组件已经创建");},destroyed() {console.log("Hello组件已经销毁");},deactivated() {console.log("Hello组件缓存");},activated (){console.log("Hello组件激活");}10、组件第一次被创建的时候,会激活created,也会激活activated生命周期,组件被激活的时候只会触发activated,不再触发created。11、keep-alive的include属性:在component会把component包裹的组件都缓存起来。可以使用include属性用来指定。至于名称相匹配的组件会被缓存,多个组件名之间使用,就是说用它来指定哪些组件需要被缓存,多个组件名之间用,分隔。不被包含在里面的都不会被缓存,记住这个include指定的组件名是在组件里面的定义的name属性//只有Hello组件可以被缓存<keep-alive include="Hello"><component :is="str"></component></keep-alive>12、exclude属性:默认哪些组件不会被缓存,不能和include同时使用 13、在组件提供了name属性后,组件的名称就是name属性的值。如果在“声明组件”的时候,没有为组件指定name名称,则组件的名称默认就是“注册时候的名称”,14、注册名称以标签的形式使用,把注册好的组件渲染和使用到页面结构中name名称为了在调试工具里面看到组件名称,以及结合《keep-alive》实现组件缓存功能
Hello子组件
<template><div>Hello组件</div>
</template><script>
export default {created() {console.log("Hello组件已经创建");},destroyed() {console.log("Hello组件已经销毁");},deactivated() {console.log("Hello组件缓存");},activated (){console.log("Hello组件激活");}
}
</script><style lang="less" scoped>
div{width: 100%;height: 400px;position: absolute;top:58px;background-color: rgb(248, 245, 49);
}</style>
父组件
<template><div id="app"><nav>App根组件<button @click="str = 'Hello'">切换为Hello组件</button><button @click="str = 'Hi'">切换为Hi组件</button></nav><component :is="str"></component></div></template><script>import Hello from './components/Hello.vue'
import Hi from './components/Hi.vue'export default {name: "App",components: {Hello,Hi,},data() {return {str:""}}};</script>
<style lang="less" scoped>
* {padding: 0;margin: 0;
}nav {width: 100%;height: 50px;background-color: #eee;
}
</style>
Hi子组件
<template><div>Hi组件</div>
</template><script>
export default {}
</script><style lang="less" scoped>
div {width: 100%;height: 400px;background-color: orange;
}
</style>
19、插槽
19-1、插槽的基本用法
1、插槽(slot)是vue为组件的封装这提供的能力,允许开发者在封装组件的时候,把不确定、希望由用户指定的部分定义为插槽。2、简单来说就是在使用注册过的组件时,如果要往那个标签对里面插入什么元素,但是不会显示出来,就可以往子组件里面写一个插槽,这样这个组件标签对里面写的东西就可以显示出来了3、用户使用什么,插槽就渲染什么4、vue官方规定,每一个插槽都应该有一个name名称,如果没有定义会有一个default的默认名称<slot name="p"></slot>5、如果插槽定义了name属性,那么我们要使用 v-slot:插槽的名字,去指定是哪一个插槽,而且要注意的是,这个被指定要使用插槽的元素要使用template包裹。例如:根组件引用了Hello组件,在标签对里面使用了一个p标签,然后,在hello组件里面定义了一个name属性为p的插槽,然后根组件就需要将这个p标签用template包裹起来。然后在template里面定义v-slot:pHello组件<slot name="p"></slot>App组件<Hello><template v-slot:p><p >你好,这是插槽内容</p></template></Hello>6、注意:1、如果要把内容填充到指定名称的插槽中,需要使用v-slot2、v-slot值只能用在template身上,而且渲染的页面是看不见这个template元素的,只会看见被渲染的元素3、v-slot:插槽的名字4、插槽指令v-slot的简写形式是: #,就是一个#号
1、比如,在APP根组件里面引入了Hello组件,然后声明注册后以标签对的形式使用,在里面定义了一个p标签,但不会显示内容,只有在Hello里面定义一个slot插槽,接收到这个p标签,才能显示内容
普通的定义插槽
根组件
<template><div id="app"><nav>App根组件<Hello><p>你好,这是插槽内容</p></Hello></nav></div></template><script>import Hello from './components/Hello.vue'
import Hi from './components/Hi.vue'export default {name: "App",components: {Hello,Hi,},data() {return {str:""}}};</script>
<style lang="less" scoped>
* {padding: 0;margin: 0;
}nav {width: 100%;height: 50px;background-color: #eee;
}
</style>
Hello组件
<template><div>Hello组件<slot></slot></div>
</template><script>
export default {}
</script><style lang="less" scoped>
div{width: 100%;height: 400px;position: absolute;top:58px;background-color: rgb(248, 245, 49);
}</style>
有名字的插槽
Hello组件
<template><div>Hello组件<slot name="p"></slot></div>
</template><script>
export default {}
</script><style lang="less" scoped>
div{width: 100%;height: 400px;position: absolute;top:58px;background-color: rgb(248, 245, 49);
}</style>
App组件
<template><div id="app"><nav>App根组件<Hello><template v-slot:p><p >你好,这是插槽内容</p></template></Hello></nav></div></template><script>import Hello from './components/Hello.vue'
import Hi from './components/Hi.vue'export default {name: "App",components: {Hello,Hi,},data() {return {str:""}}};</script>
<style lang="less" scoped>
* {padding: 0;margin: 0;
}nav {width: 100%;height: 50px;background-color: #eee;
}
</style>
19-2、具名插槽和作用域插槽
1、带名字的插槽就是具名插槽,2、slot插槽可以定义属性,在template里面用v-slot接收子组件:<slot name="p" msg="好好学习,天天向上"></slot>根组件<Hello><template #p="obj"><p >你好,这是插槽内容</p>{{ obj }}</template></Hello>3、在封装组件时,为预留的slot提供属性对象的值,这种用法叫做作用域插槽4、这种作用域插槽也是具名插槽,用v-slot接收,v-slot可以用#来进行简写。数据对象可以用=来接收。对象的名字用scope定义<Hello><template #p="scope"><p >你好,这是插槽内容</p>{{ obj }}</template></Hello>5、作用域插槽可以使用解构接收数据对象
写法:可以直接使用这个msg#p="{msg}"也可以通过scope直接接收所有数据#p="scope"{{scope.msg}}
20、自定义指令
1、vue官方提供了v-text、v-for、v-model等常用的指令,还允许开发者自定义指令2、vue的自定义指令分为两类:1)、私有自定义指令2)、全局自定义指令3、私有自定义指令:在每个vue组件中,可以在directives(自定义指令节点)节点下声明私有自定义指令就在组件实例里面定义,和methods、data等平级,这个指令是对象形式,定义的指令 也是对象形式// 这是自定义指令的节点directives:{// 定义一个color的指令,指向一个配置对象color:{// 当这个指令绑定到元素的时候,会马上触发bind函数// bind函数会接收一个el参数,这个el参数就是绑定的dom元素bind(el){console.log(el);}}}4、例如,定义一个color的指令,可以在绑定元素的时候,把元素的背景颜色渲染为绿色// 这是自定义指令的节点directives:{// 定义一个color的指令,指向一个配置对象color:{// 当这个指令绑定到元素的时候,会马上触发bind函数// bind函数会接收一个el参数,这个el参数就是绑定的dom元素// 可以利用这个el参数对Dom对象做操作,将背景颜色渲染为绿色bind(el){el.style.backgroundColor="green"}}}5、这种定义私有指令的时候,不用使用v-开头来定义,但是使用的时候必须使用v-开头,例如<div class="box" v-color>这是一个红色的盒子</div>6、自定义指令接收实际参数,会有一个binding对象。binding对象里面有一个value,可以接收到传入的数据,而且,,如果传入的数据时字符串格式的话,要记得给字符串加上单引号。不带引号传入的是一个变量。写法:<div class="box" v-color="'yellow'">这是带有参数的自定义指令</div>定义私有指令的写法directives:{ color:{bind(el,binding){el.style.backgroundColor=binding.value}}}7、expreion:是一个表达式,就是这个=后面的表达式。代表用户写的东西。8、bind函数的缺点,只会在第一次绑定元素的时候执行,而且只执行一次,而如果页面数据更新,是无法改变的,二update函数会在每次Dom更新的时候调用。updated() {console.log(this.str);},9、凡是使用到了这个指令的元素,都会触发这个update函数10、update只会在数据更新的时候生效,不会在第一次的时候生效11、函数简写:如果bind和update函数中的逻辑完全相同,则对象格式的自定义指令可以写成函数格式:color(el,binding){ el.style.backgroundColor=binding.value}12、私有自定义指令只能在当前定义的组件使用,不能在其他组件使用13、全局共享的自定义指令需要在main.js 通过“vue.directive()”进行声明像定义全局过滤器一样,以对象形式写两个函数方法Vue.directive('c',{binding(el,binding){el.style.color=binding.value},update(){el.style.color=binding.value}
})14、如果逻辑一样,可以以函数形式写代码Vue.directive('c',function(el,binding){el.style.color=binding.value})
main.js
// 引入残缺版的vue,残缺版的vue不能自己渲染页面
// 只有完整版的vue能够渲染,
// vue由两部分组成:核心(生命周期、路由)+模板解析器
// 节省空间,残缺版去掉了模板解析器,通过render函数
// 去渲染页面
import Vue from 'vue'
import App from './App.vue'Vue.config.productionTip = falseVue.directive('c',function(el,binding){
el.style.color=binding.value})new Vue({el:"#app",render:h=> h(App)})
// .$mount('#app')
bind对象和它的缺点
<template><div id="app"><nav>App根组件<div class="box" v-bgc>这是一个红色的盒子</div><!-- 直接传入一个颜色值 --><div class="box" v-color="'yellow'">这是带有参数的自定义指令</div><button @click="str='yellowgreen'">改变str的颜色</button><div class="box" v-color="str">这是使用变量的带参数的自定义指令,看清楚bind函数只执行一次</div><div class="box" v-color="str">这是使用变量的带参数的自定义指令,看update的更新</div></nav></div></template><script>import Hello from './components/Hello.vue'import Hi from './components/Hi.vue'export default {name: "App",components: {Hello,Hi,},data() {return {str:"pink"}},// 这是自定义指令的节点directives:{// 定义一个color的指令,指向一个配置对象bgc:{// 当这个指令绑定到元素的时候,会马上触发bind函数// bind函数会接收一个el参数,这个el参数就是绑定的dom元素// 可以利用这个el参数对Dom对象做操作bind(el){el.style.backgroundColor="green"}},color:{bind(el,binding){el.style.backgroundColor=binding.value}}},//生命周期函数,看见这个str已经改变,但是因为bind而不会更新页面updated() {console.log(this.str);},};</script><style lang="less" scoped>* {padding: 0;margin: 0;}nav {width: 100%;height: 50px;background-color: #eee;}.box{width: 200px;height: 200px;background-color: red;}</style>
update的优点
<template><div id="app"><nav>App根组件<button @click="str='yellowgreen'">改变str的颜色</button><div class="box" v-color="str">这是使用变量的带参数的自定义指令,看update的更新</div></nav></div></template><script>import Hello from './components/Hello.vue'
import Hi from './components/Hi.vue'export default {name: "App",components: {Hello,Hi,},data() {return {str:"pink"}},// 这是自定义指令的节点directives:{// 定义一个color的指令,指向一个配置对象bgc:{// 当这个指令绑定到元素的时候,会马上触发bind函数// bind函数会接收一个el参数,这个el参数就是绑定的dom元素// 可以利用这个el参数对Dom对象做操作bind(el){el.style.backgroundColor="green"},},color:{bind(el,binding){el.style.backgroundColor=binding.value},update(el,binding){el.style.backgroundColor=binding.value
}
}},updated() {console.log(this.str);},};</script>
<style lang="less" scoped>
* {padding: 0;margin: 0;
}nav {width: 100%;height: 50px;background-color: #eee;
}
.box{width: 200px;height: 200px;background-color: red;
}
</style>
21、路由
21-1、理解路由
1、路由就是对应关系,route2、路由器:router3、路由就是一组key-value的对应关系,多个路由需要经过路由器的管理4、路由就是为了实现单页面应用。5、项目由导航区和展示区组成
1、路由指的就是Hash地址与组件之间的关系2、#号代表锚链接,不会导致页面的刷新,会导致历史记录的变化3、普通的超链接:<a href="路径"></a> 是跳转到不同的页面锚点:<a href="位置"></a> 可以在同一个页面中不同的位置间跳转4、建立锚点目标,只需要给目标元素增加 id 或者 name 即可锚的名称可以是任何你喜欢的名字可以使用 id 属性来替代 name 属性,命名锚同样有效,推荐使用 id5、#往后都叫做hash地址,
锚链接
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>#锚链接</title><style>div{height: 800px;}#d1{background-color:red ;}#d2{background-color:rgb(26, 224, 108) ;}#d3{background-color:rgb(22, 56, 230) ;}#d4{background-color:rgb(231, 65, 143) ;}nav{position: fixed;top: 0;left:0;}</style>
</head>
<body><nav><a href="#d1">d1</a><a href="#d2">d2</a><a href="#d3">d3</a><a href="#d4">d4</a></nav> <div id="d1"></div> <div id="d2"></div> <div id="d3"></div> <div id="d4"></div>
</body>
</html>
21-2、路由的工作方式
1、点击页面上的路由连接后,url地址栏上的hash值发生改变,前端路由监听到了hash地址的变化,然后把当前hash地址对应的组件渲染到浏览器中2、在html页面中对应关系: a#d1 <-> div#d13、在vue中路由:path:"#/d1",compoment:#d1
21-3、简单的路由实现
1、window.onhashchange监听页面的hash值变化2、location.hash.substring(2)截取本地的hash值的字符串2位后的字符串3、使用动态组件决定显示那个页面,is属性绑定一个动态组件,切换组件
<template><div id="app"><nav><h2>App根组件</h2><a href="#/Home">首页</a> |<a href="#/Login">登录</a> |<a href="#/Regist">注册</a> |</nav><component :is="cname"></component></div>
</template><script>
import { nanoid } from 'nanoid'
import Hello from './components/Hello.vue'
import Home from './components/Home.vue'
import Login from './components/Login.vue'
import Regist from './components/Regist.vue'export default {name: "App",components: {Hello,Home,Login,Regist},data() {return {n: 5,id: 0,cname:'Home'}},created() {this.id = nanoid()window.οnhashchange=()=>{// console.log("hash值发生变化",location.hash);// console.log( location.hash.substring(2));this.cname=location.hash.substring(2)}},};</script>
<style lang="less" scoped>
* {padding: 0;margin: 0;
}nav {width: 100%;height: 50px;background-color: #eee;
}.box {width: 200px;height: 200px;background-color: red;
}
</style>
21-4、vue-router的使用
1、2022年2月7日以后,vue-router的默认版本,为4版本,4版本适用于vue33版本的vue-router适用2版本的vue。我们直接安装vue-router就会报错, 出现。Found:vue @2.。。。peer vue@“^3.0..所以一定要安装正确版本2、cmd安装vue--router的版本,指定3版本npm i vue-router@33、vue-router是一个插件库,需要use。import VueRouter from 'vue-router'Vue.use(VueRouter)4、创建一个router文件夹,用于创建整个应用的路由器,创建一个index.js文件。1)、引入路由vue-routerimport VueRouter from 'vur-router'2)、创建路由器const router=new VueRouter({ }) 3)、配置路径routes,path,表示显示的url路径的hash地址,component 表示那个hash地址显示对应的组件 // 创建一个路由器const router=new VueRouter({routes: [{path:'/hello',component:Hello}]
}) 4)、因为配置的component是组件上,所以我们还需要引入组件import Login from '@/components/Login.vue'import Regist from '@/components/Regist.vue'5)、暴露这个路由器export default router6)、简写export default new VueRouter({routes: [{path:'/hello',component:Hello}]
}) 7)、在main.js里面引入路由器import router from '@/router'8)、使用router-link标签跳转路径,这个标签实际上就是a标签<router-link to="/login">Login</router-link>9)、这个时候页面没有展示出来。需要向slot插槽一样,给要显示组件的地方需要用到 router-view占位。组件一个router-view标签,表示router显示的页面展示在这个位置<router-view></router-view>10、这些定义了hash路径的组件都叫做路由组件
router的index.html
// 用于创建整个应用的路由器
import VueRouter from 'vue-router'
// 引入组件
import Login from '@/components/Login.vue'
import Regist from '@/components/Regist.vue'// 创建一个路由器
export default new VueRouter({routes: [{path:'/login',component:Login},{path:'/regist',component:Regist}]})
main.js
// 引入残缺版的vue,残缺版的vue不能自己渲染页面
// 只有完整版的vue能够渲染,
// vue由两部分组成:核心(生命周期、路由)+模板解析器
// 节省空间,残缺版去掉了模板解析器,通过render函数
// 去渲染页面
import Vue from 'vue'
import App from './App.vue'import VueRouter from 'vue-router'
import router from '@/router'Vue.use(VueRouter)Vue.config.productionTip = falsenew Vue({el:"#app",router:router,render:h=> h(App)})
// .$mount('#app')
App引入router
<template><div id="app"><nav><h2>App根组件</h2></nav><div class="box"><router-link to="/login" >Login</router-link></div><div class="txt"><router-link to="/regist" >Regist</router-link></div><div class="tt"><router-view></router-view></div></div>
</template><script>export default {name: "App",components: {},data() {return {}},};</script>
<style lang="less" scoped>
* {padding: 0;margin: 0;
}nav {width: 100%;height: 50px;background-color: #eee;
}.box {width: 100px;height: 30px;text-align: center;border: 1px solid #a1a0a0;}
.txt{width: 100px;height: 30px;text-align: center;border: 1px solid #a1a0a0;border-top: 0;
}</style>
21-5、路由注意点
1、配置了hash路径的组件都叫做路由组件2、这些路由组件一般放在pages文件夹下面。3、$route:这个组件的路由信息,每个路由组件都有。 route是单个路由,存放 当前路径信息,携带的参数4、$router:整个应用的路由器。只有一个路由器。 管理整个路由系统,里面保 存所有的路径信息,能够实现路由的跳转5、通过切换。“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载
21-6、嵌套路由
1、一级路由,定义在routes对象中,是routes对象的属性,被定义为一级路 由。2、多级路由是一级路由的孩子。使用routes的children属性定义,children是一个数组,里面可以配置多个对象,对象的写法和以及路由是一样的。是被定义在一级路由为代表的路由组件里面的路由组件。children里面不用添加 /{path:'/regist',component:Regist,children:[{path:'home',component:Home}]},3、使用的时候,记得to属性加上完整路由。<router-link to="/regist/home">Home组件</router-link>
21-7、路由传参
1、路由跳转的时候可以传递参数,而跳转到的那个路由组件可以接收到值传递的这个参数值。<router-link to="/regist/home/hello?id=01"> {{ item.name }}</router-link>2、每个路由组件都有一个this.$route对象,有关于这个路由组件的很多多信息。<li>学生学号{{ $route.query.id}}</li>3、动态展示传递过去的参数,使用属性绑定v-bind绑定to属性,让字符串变成动态表达式,然后使用模板语法用 ` `括起来,把name属性=对象的id属性,使用${}。让这句话变成模板字符串。这是跳转路由携带query参数的to的字符串写法<router-link:to="`/regist/home/hello?id=${item.id}&name=${item.name}`"
> {{ item.name }}</router-link>4、跳转路由并携带query参数to的对象写法,path代表路径,表示你跳转的路由组件的地址,还有query参数,query是一个对象,里面装的就是要携带的参数,这样写的好处是简单明了<router-link :to="{path:'/regist/home/hello',query:{id:item.id,name:item.name}}">{{ item.name }}</router-link>
21-8、命名路由
1、name是什么呢?name 是配置路由时给 path 取的别名,方便使用。但要注意的是 “地址栏显示的路径始终是 path 的值”.可以简化代码,就在routes设置里面添加一个name属性。{name:'login',path:'/login',component:Login,},2、这个name属性可以简化代码。比如说路径跳转的时候我们使用path进行路径跳转。//在routes设置跳转的 路由的name属性{name:'login',path:'/login',component:Login,},//路由跳转:通过name属性跳转<router-link :to="{name:'hello',query:{id:item.id,name:item.name}}">{{ item.name }}</router-link>
21-9、params参数
字符串写法
1、在跳转前的组件通过to属性使用/传递参数,但是要在路径的path属性里面去声明这是接收参数。通过占位符来声明,跳转到的路由组件接收参数的写法也不一样。//传递固定格式的数据的写法<router-link :to="`/regist/home/hello/007/王老五`">{{ item.name}}</router-link>//传递动态数据的写法<router-link :to="`/regist/home/hello/${item.id}/${item.name}`">{{ item.name}}</router-link>2、在路由组件的路由设置里面通过占位符声明接收的参数。这些数据就会放在params对象里面。path:'hello/:id/:name',3、路由组件接收的参数的方式,通过params对象去接收:<li>学生学号{{ $route.params.id}}</li> 对象写法必须把path换成name就可以了。不能使用path,然后query对象的参数换成params对象设置传递的数据参数4、解决路由组件接收参数写死的情况,路由的props配置:,在路由里面设置,使用rpops参数去接收,1)//第一种写法,值为对象,{name:'hello',path:'hello/:id/:name',component:Hello,// props的第一种写法,值为对象,该对象// 所有key-value都以props形式传递给这个hello组件props:{a:1,str:"小红"}}路由组件通过props接收这个两个变量的值props:['a','str'],组件可以直接使用这两个数据,但是,这是写死的数据,不推荐使用<li>{{ a}}</li><li>{{ str }}</li>2)//第二种写法,值为布尔值,// props的第二种写法,值为布尔值,若布尔值为真// 就会把该路由收到的所有的params参数以props// 的形式转给该路由组件{name:'hello',path:'hello/:id/:name',component:Hello, // props的第二种写法,值为布尔值,若布尔值为真// 就会把该路由收到的所有的params参数以props/ 的形式转给该路由组件props:true} 引用路由组件的字符串写法<router-link :to="`/regist/home/hello/${item.id}/${item.name}`">{{ item.name}}</router-link> 路由组件通过props接收这个两个变量的值props:['id','name'],组件可以直接使用这两个数据,但是,这是写死的数据,不推荐使用<li>学生学号{{ id}}</li><li>学生姓名{{ name}}</li>对象写法<!-- 6、路由跳转携带params 参数,引用路由的组件对象写法写法--><router-link :to="{name:'hello',params:{id:item.id,name:item.name}}">{{ item.name}}</router-link>4)如果把路径删了,想转成query参数。通过props接收,不能使用props接收的数据,会告诉你属性未定义,只能通过query对象使用数据引用路由的组件设置跳转路由<!-- 7、跳转路由由query 接收props传递的数据 --><router-link :to="{name:'hello',query:{id:item.id,name:item.name}}"> {{ item.name }}</router-link>路由组件接收传递的参数的写法<li>学生学号{{ $route.query.id}}</li><li>学生姓名{{ $route.query.name}}</li>路由设置{name:'hello',// path:'hello/:id/:name',path:'hello',component:Hello,// 如果把路径删了,想转成query参数。通过props接收。props:true}5)props的第三种方法:值为函数。// props的第三种写法:值为函数,//值为函数的第一种写法// props(){// 这是写死的用法。这个props传递的数据既不在params//里面,也不在query里面// return {id:11,name:"小兰"}/ }//值为函数的第二种写法:// 传入route对象,就可以使用query里面的参数传递数据 props($route){// 这是写死的用法。这个props传递的数据既不在params// 里面,也不再query里面return {id:$route.query.id,name:$route.query.name}}//值为函数的第三种写法:// 解构query对象,使用里面的数据props({query}){return {id:query.id,name:query.name}}//值为函数的第四种写法:// 再解构赋值props({query:{id,name}}){return {id,name}}5、props的作用:让路由组件更方便的收到参数,既适用于params也适用于 query
21-10、params和query的不同
在Vue路由中,query和params都是用于向路由添加附加信息的方式。query通常用于传递查询字符串,而params则用于传递路由参数。query通过URL中的“?”传递附加信息,而params则在路由路径中传递,例如“/users/:id”。params可以使用$router.push()来更改,而query则使用$router.replace()。查询参数和路由参数在Vue的$route对象中都可以使用,但是路由参数更适用于表示唯一标识符,例如用户ID,而查询参数更适合用于分页或搜索过滤器等用途
21-11、路由跳转的两种导航方式
1、声明式导航,在浏览器中,点击链接实现导航的方式,叫做声明式导航。例如:普通网页中点击a链接,vue项目中点击<router-link>都属于声明式导航2、 编程式导航在浏览器中,调用API方法实现导航的方式,叫做编程式导航。例如:普通网页中调用location.href 跳转到新页面的方式,都属于编程式导航作用:不借助<router-link>实现路由跳转,让路由跳转更加灵活
21-12、router-link的replace属性
1、路径以push模式增加为历史记录,一条条路径重叠,不破坏任何一条路径。最新的页面在最上面2、replace属性直接替换当前路径页面,不会生成页面记录,写法,直接添加replace属性,在router-link里面。<router-link replaceto="/regist/home">Home组件</router-link>3、总结:replace属性的作用1)、作用:控制路由跳转时操作浏览器历史记录的模式2)、浏览器的历史记录有两种写入方式,分别为push和replace,push是追加历史记录,replace是替换当前记录,路由默认为push3)、开启replace模式的方法:在router-link里面添加replace属性。
21-13、编程式导航
1、在浏览器中,调用API方法实现导航的方式,叫做编程式导航。例如:普通网页中调用location.href 跳转到新页面的方式,都属于编程式导航2、使用路由器:$router的api方法跳转pushShow(m){this.$router.push({name:'hello',query:{id:m.id,name:m.name}})},replaceShow(m){this.$router.replace({name:'hello',query:{id:m.id,name:m.name}})}
3、使用路由器方法的前进后退:this.$router.backthis.$router.forward4、编程式导航的作用:不借助router-link实现路由跳转,让路由跳转更灵活
21-14、缓存路由组件
1、通过keep-alive:让不展示的组件保持挂载,不被销毁2、是在路由router-link里面指定,include属性指定哪个组件被挂载3、缓存多个组件的写法:include="['组件1','组件2']"
21-15、路由组件相关的生命周期
1、activated:激活时触发2、deactivated:失活时触发3、路由组件所独有的两个钩子,用于捕获路由组件的激活状态
21-16、全局路由守卫
1、路由守卫的作用:对路由进行权限控制,分类:全局守卫、独享守卫、组件内守卫。如果想实现登录注册后才能看见网站首页,就需要添加路由守卫2、第一步就是在路由组件里面选择不直接暴露router。而是直接定义一个router对象,const router=new VueRouter({
routes:[
{}
]
})//全局前置路由守卫,路由切换之前会调用
//初始化的时候调用
router.BeforeEach((to,from.next)=>{})3、to和from是去的路由组件和前一个路由组件,里面是路由组件的相关信息。next()表示放行,如果不放行,是不会执行到下一步,4、所以前置路由守卫一般是用来判断,是否登录注册过,才可以跳转页面,然后可以路由跳转到其他页面,to.name也可以if(to.path=='/login' || to.path =='/regist'){if(这里和数据库的会员数据做比对,一致的话就可以放行){next()}else{console.log("不能成功登录")}}5、meta:提供容器配置特殊的数据。称作路由原信息,配置程序员自己想配置的信息,可以用来作为验证路由守卫的信息。也可以用来做网页的title信息。const router=new VueRouter({
routes:[
{name:'hello',path:'/hello',component:Hello,meta:{isNext:true}}
]
})6、使用meta信息判定权限:
//判断是否需要鉴权if(to.meta.isNext){if(这里和数据库的会员数据做比对,一致的话就可以放行){next()}else{console.log("不能成功登录")}}7、全局后置路由守卫:初始化之后调用,每次切换之后调用,没有next,不需要放行。router.afterEach((to,from)=>{document.title=to.meta.title || '网站'})
21-17、独享路由守卫
1、某一个路由单独想用的守卫。2、想设置独享路由守卫,在设置路由里面设置beforeEnter。表示进入这个路由之前。进行规则的对比,只对该路由组件做测试。routes:[
{name:'hello',path:'/hello',component:Hello,meta:{isNext:true},beforeEnter((to,from,next)=>{})}
]3、独享守卫只有前置没有后置,可以喝全局后置守卫搭配使用。
21-18、组件内路由守卫
1、beforeRouteEnter,路由组件使用的函数,通过路由规则,进入该组件时被调用。beforeRouteEnter(to,from.next){}2、beforeRouteleave,路由组件使用的函数,通过路由规则,离开该组件时被调用。beforeRouteleave(to,from.next){}
21-19、history模式与hash模式
1、hash值最大的特点:hash值不会因为http请求作为路径数据发给服务器,是程序员自己设置的路径2、可以通过在路由器里面设置mode属性,选择路由是history模式还是hash模式,默认是hash模式const router=new VueRouter({mode:'history',routes:[]})3、开启history模式后不会再有hash值。需要新开页签4、hash兼容性好,history兼容性较差。5、npm的中间件:connect-history-api-fallback专门解决history模式404的问题。6、总结;hash模式:1、地址中带着#号,不美观2、如果以后将地址通过第三方手机app分享,如果app校验严格,则地址会被标记不合法3、兼容性较好history模式:1、地址干净、美观2、兼容性和hash模式相比略差3、应用部署上线时需要后端人员支持,解决刷新页面服务器404问题
21-20、路由重定向
暂时省略
21-21、路由懒加载
暂时省略
22、minxin:混入
22-1-1、什么是混入
1、mixins(混入),官方的描述是一种分发 Vue 组件中可复用功能的非常灵活的方式 mixins 是一个 js 对象,它可以包含我们组件中 script 项中的任意功能选项,如:data、components、methods、created、computed 等等。我们只要将公用的功能以对象的方式传入 mixins 选项中,当组件使用 mixins 对象时所有 mixins 对象的选项都将被混入该组件本身的选项中来,这样就可以提高代码的重用性,并易于后期的代码维护
22-1-2、怎么使用mixin
1、当我们存在多个组件中的数据或者功能很相近时,我们就可以利用 mixins 将公共部分提取出来,通过 mixins 封装函数,组件调用他们是不会改变函数作用域外部的。
2、一样的方法我们把它提取出来放在一个公共的地方
22-1-3、如何创建mixin
1、在 src 目录下创建一个 mixins 文件夹,在文件夹下新建一个myMixins,js 文件。 因为 mixins 是一个 js 对象,所以应该以对象的形式 来定义 myMixins,在对象中可以和vue 组件一样来定义 data、components、methods、created、computed 等属性, 并通过 export 导出该对象。export表示分别暴露,如果需要在组件里面使用该混合,需要在该组件引入,因为是分别暴露,所以,需要以对象的形式暴露:import {mixin} from '../mixin'然后,所以我们使用mixins配置项去接收,因为有多个的mixin,所以数组形式接收,只有一个混合也这样写mixins:[mixin]
2、组件有的东西以组件为主,组件没有的以混合为主
3、生命周期mountend都会实现
4、功能:就是可以把多个组件共用的配置提取成一个混入对象
22-2、案例
export const mixin={methods:{fn(){this.n++}}
}
<template><div>{{ n }}
<button @click="fn">按我+1</button></div>
</template><script>
import {mixin} from '../mixin'
export default {data(){return{n:2}},mixins:[mixin]}
</script>
22-3、定义全局混合
1、在main.js里面引入混合,然后使用Vue.mixin()就可以使用该混合里面的方法了import {mix} from './mixin'Vue.mixin(mix)
23、过渡与动画
1、过渡与动画的作用:在插入或移除DOM元素的时候,在核实的时候给元素添加样式类名2、有进入的样式和离开的样式3、进入v-enter:进入的起点v-enter-active:进入过程中v-enter-to:进入的终点4、离开v-leave:离开的起点v-leave-active:离开过程中v-leve-to:离开的终点5、进入的终点就是离开的起点6、使用transtion包裹想要过渡的元素,
23-1、动画
23-2-1、Vue动画的理解
1、设置来回切换的效果,vue用transtion包裹有动画效果的元素,设置进入的时候的的类名:v-enter-active,设置离开的时候的类名:v-leave-active。2、这个transtion还可以起名字,<transition name="tr"><nav v-show="flag">动画效果</nav></transition>3、如果给transtion起了名字,那么,v-enter-active就改成 transtion的名字-enter-active4、设置一开始就是动画效果,就给transtion设置一个appear属性,设置属性值为true,但是要通过v-bind进行绑定。不然的话是一个布尔值<transition name="tr" :appear="true"><nav v-show="flag">动画效果</nav></transition>5、transtion在vue解析的时候没有被解析,是给vue 设置动画的,动态给元素添加样式的动画效果
<template><div><button @click="flag=!flag">显示/隐藏</button><transition><nav v-show="flag">动画效果</nav></transition></div>
</template><script>
export default {data(){return {flag:1}}}
</script><style lang="less" scoped>
nav{width: 1000px;height: 100px;background-color: aquamarine;}
.v-enter-active{animation: trans 1s linear reverse;
}
.v-leave-active{animation: trans 1s linear ;
}@keyframes trans {from{transform: translateX(0%);}to{transform: translateX(-100%);}
}
</style>
23-2、过渡
1、vue提供了transtion的封装插件,在下列情形中,可以给任何元素和组件添加enter/leave过渡1、v-if2、v-show3、动态组件4、组件根节点过渡的类名
1、v-enter:进入的起点,在外边的盒子以左边坐标为开始,向右从-100%的位置开始2、v-enter-to:进入的终点,在里边的盒子以左边的坐标未开始,向左从0%的位置转3、v-leave:离开的起点,0%的位置开始转移4、v-leave-to:离开的终点,转移到-100%的位置5、给元素设置transtion。同样位置的一样的类名设置可以放在一起
<template><div><button @click="flag=!flag">显示/隐藏</button><transition ><nav v-show="flag">动画效果</nav></transition></div></template><script>export default {data(){return {flag:1}}}</script><style lang="less" scoped>nav{width: 1000px;height: 100px;transition: 2s linear;background-color: aquamarine;}.v-enter{transform: translateX(-100%);}.v-enter-to{transform: translateX(0%);}.v-leave{transform: translateX(0%);}.v-leave-to{transform: translateX(-100%);}</style>
22-2-1、多个元素过渡
1、 can only be used on a single element. Use <transition-group> for lists.transtion只能有一个元素,多个元素可以使用transtio-group2、transtion-group的元素必须有唯一的key值<transition-group name="tr" appear><nav v-if="flag" key="one">1</nav><nav v-if="flag" key="two">2</nav></transition-group>
22-3、动画库(使用第三方库写动画样式)
1、搜素npm.js官网,https://www.npmjs.com/2、在官网里面搜索animate.css,点击第一个https://www.npmjs.com/package/animate.css3、选择animate.stylehttps://animate.style/4、根据animate上面的步骤进行使用:1、安装,停止该项目,安装animate2、引入样式库import 'animate.css'3、复制粘贴类名,放在name属性上animate__animated animate__bounce4、给这个transtion指定进入和离开的类名,复制类名 字符串里面是自己喜欢的动画效果进入的类名:enter-active-class=””离开的类名:leave-active-class=””<transition-groupname="animate__animated animate__bounce" appearenter-active-class="animate__wobble"leave-active-class="animate__zoomOutDown"><nav v-if="flag" key="one">1</nav><nav v-if="flag" key="two">2</nav></transition-group>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1nGHkSMl-1686141820666)(C:\Users\Direct\Desktop\常用前端框架及工具\拓展学习资料\7-animate使用.PNG)]
23、Vue原理
23-1、MVVM
1、Vue坐着参考mvvm模型,m(model)代表模型,v(view)代表视图,模板,vm,视图模型,vue实例对象
23-2、数据代理
1、是否被枚举指的是是否可以被遍历出来2、数据代理:通过一个对象代理对另一个对象中属性的操作3、重点:Object.defineProperty,
24、配置代理
1、跨域,也就是违背了同源策略:主机名、协议名、端口号必须一致2、解决跨域的方法1.cors,后端人员添加特殊的响应头,2、jsonp,通过script标签,前端后端一起设置,只能设置get方法3、代理服务器,服务器和服务器之间传递数据不用ajax请求,使用的是http协议,而代理服务器的端口号和客户端的端口号这些是一致的,满足同源策略
服务器之间不受同源策略的影响3、代理服务器的几种方式:1、nginx2、借助vue-cli4、vue脚手架设置代理服务器的方式,在vue.config.js里面设置1、打开vuejs的官网,选择vue2文档,点击配置参考,选择devServer。procy,2、按照参考文档设置3、lintOnSave:false //关闭语法检查//举例module.exports = {devServer: {//这里是告诉代理服务器等会在哪个服务器请求数据,在这里就开启了一个//代理服务器,所以设置的是请求数据的服务器端口proxy: 'http://localhost:4000'}}4、在axios请求数据的时候改变端口号,只改变自己的端口号,不改变请求路径。然后重启项目,比如服务器端口号是4000,但我们设置了代理服务器,axios请求的路径本来是4000,但我们改成本机端口号80880axios.get('http://localhost:4000')改:axios.get('http://localhost:8080')5、两个小问题:1、只能配置一个代理服务器2、没办法控制走不走代理,因为如果文件的public有路径文件,会优先获取public里面的。6、解决以上两个问题的方法,看官网第二种方法module.exports = {devServer: {proxy: {//第一个代理///api叫做请求前缀,如果请求前缀是api就走代理服务器'/api': {//target是服务器的路径target: '<url>',//用于支持websocket:ws: true,//true表示隐瞒自己的端口号,//用于控制请求头中的host值changeOrigin: true},//第二个代理'/foo': {target: '<other_url>'}}}
}注意:在这里因为设置了请求前缀,我们的axios也要作出相应改变,在端口号的后面添加请求前缀,其他的不会改变axios.get('http://localhost:8080/api')但是因为axios请求的路径会完整的带给服务器去请求数据,所以我们要去设置一个配置。//重写路径,它是一个对象格式,里面是key、value形式,表示所有以api开头的路径将被替换为空字符串pathRewrite:{'/api':''}7、第二种方法的优点:可以配置多个代理,且可以灵活的控制请求是否走代理缺点:配置稍微繁琐,请求资源时必须添加前缀
25、axios
25-1、项目中使用
1、在vue里面使用axios需要先安装axios,npm i axios -S2、在组件中引入import axios from 'axios'3、调用方法 axios.get()
25-2、axios拦截器
暂时省略
26、nanoid
1、使用nanoid可以给数据生成id,2、先引入import {nanoid} from 'nanoid'后使用,直接使用this.id=nanoid()
27、Vue UI组件库
27-1、移动端组件库
1、Vant
2、Cube UI
3、Mint UI
27-2、PC端常用UI组件库
1、element UI
2、IView UI