Vue--组件和VueCli(新)
学习资料
本篇博客是第二次学习vue笔记,学习课程为B站尚硅谷禹老师的vue2+vue3课程
笔记中文字和代码都是自己理解后的详细总结,可能有表述啰嗦的地方,但是难点容易理解回忆,图片来自视频课截图
组件化编程
什么是组件
组件是实现应用中局部功能代码和资源的集合
组件可以嵌套
组件有什么好处
复用编码,简化项目编码,提高运行效率
传统方法编写应用与使用组件编写应用
区别模块化
比如说一个组件里需要实现很多个功能,需要些很多js代码,那么这个js文件很多很复杂,此时把要写的Js代码拆分成多个js文件,每个文件实现一些模块的功能,这个叫做模块化
组件的两种编写形式
非单文件组件
一个文件中包含有多个组件(几乎不用)
单文件组件(常用 )
一个文件中只包含有一个组件(条理清晰,代码好维护)
非单文件组件组件使用步骤
创建组件->注册组件->使用组件
创建组件
注意templat格式规范,里面必须要有一个大盒子包起来
1 | const 组件名 = Vue.extend({ |
创建vm的配置项和创建组件的配置项几乎一样
- 组件定义时不写**el **
组件不用规定为谁服务,因为最终所有的组件都要被一个vm管理,由vm决定为谁服务 - data要写成普通函数的形式
避免组件被复用时,数据存在引用关系1
2
3
4
5
6data(){
return {
属性1:value1;
属性2:value2
}
} - 使用template可以配置组件结构
1
2
3
4template:`
<div>
</div>
`
注册组件(局部注册和全局注册)
全局注册
Vue.component('组件名',组件值)
所有的vm都能够使用组件
局部注册(用的多)
在vm里面的components:{}
中注册组件
1 | new Vue({ |
使用组件
把组件名作为标签直接使用
下图的注册是局部注册
组件注意点
组件命名规范
- 一个单词:
首字母大写(用的多)
首字母小写 - 多个单词:
(1)全部小写加-,如<my-cat></my-cat>
components:{ 'my-cat ' : cat }
(2) 大驼峰命名法(在脚手架环境中)
直接引用vue.js不可以用这种写法 - 不要用和标签之类同名的组件名
- 组件创建时,可以用name配置项指定组件在开发者工具中呈现的名字
一般用于第三方组件库和大型项目
组件标签
- <组件名></组件名>
- <组件名/> 必须在使用脚手架的环境中用
一个简写方式
const school = Vue.extend(options)
可以简写为const school = options
组件嵌套(非单文件组件)
把子组件注册到父组件里面,注意子组件的定义要放在前面,不然会找不到
单文件组件(重点)
给单个.vue文件起名原则
建议用Hometown.vue或者MyCat.vue这样的命名格式,有助于和开发者工具呼应
单文件结构标签
为了迎合html,css,js,有课这三个结构和标签
1 | <template> |
组件暴露和引用
在script中的内容要用export暴露出去,这样才能够让别的文件引用
建议在最后写export default 组件名
来暴露
图片2的Vue.extende()可以省略
图片2里面要加name:’文件名’,这样最好
在App.vue中要引入和注册组件,那么在<script>
中添加
1 | import Hometown from './Hometowen' |
vm(main.js入口文件)和index.html
index.html,作为容器,注意顺序
(以上内容要放在脚手架里跑)
Vue脚手架–Vue CLI
认识脚手架
Vue CLI:CLI(命令行接口工具)
一个工具让.vue文件运行起来,是Vue官方提供的标准化开发工具。
脚手架一般用最新版本,脚手架可以向下兼容低版本的Vue,不要让Vue向下兼容脚手架
用脚手架安装和创建项目
- 第一次执行要全局安装脚手架
npm install -g @vue/cli
2.创建项目
切换到要创建项目的目录,然后用命令创建项目vue create 项目名
项目名要回避关键字
一般很快就好了,会出现Successful - 启动项目
npm run serve
启动成功后会出现两个地址,第一个是自己本地用,第二个如果别人想用可以用这个访问
ctrl+c暂停服务再加ctrl+c
分析脚手架结构
项目文件(脚手架结构)
- .gitignore
git的忽略文件,不想接受git管理的放进去 - babel.config.js
ES6转=>ES5的配置文件,用默认配置的就可以,想再加从官网看 - package.json
一些配置文件,里面的”script”是指令的简写
“bulid”用于在vue写完之后要转化成.html,js,jcss文件给后端的时候用,是最后的一次编译 - package-lock.json
包管理版本控制文件 - README
markdown笔记 - src-main.js
这个是最重要的文件,在运行npm run serve
之后马上运行这个文件,是整个项目的入口文件
引入App.vue;关闭vue的生产提示
Vue.config.productionTip = false
创建Vue实例对象vm
将App组件放入容器中```render:h=>h(App)`
7. App.vue
里面自动生成的很多不用,可以自己弄个干净的App.vue用于以后这个文件的替换
8. assets文件夹
放静态资源
9. cpmponents
除App.vue之外的所有组件全部放里面
10. public文件夹
里面有index.html,和图标,有一些默认配置
render函数
只会在这里出现一次,后面不会在需要
vue帮你调用的一个函数
修改脚手架的默认配置
- 怎么改
public,src,main.js不可以改
在官网-上面导航栏-配置参考,里面出现的都可以改 - vue.config.js文件
这个文件可以对脚手架进行个性化定制,看官方文档有修改说明(导航栏-配置参考-vue.config.js)
vue.config.js最终vue会把它的配置给webpack进行合并,如果你有那么就会把它里面的配置替换掉 - 导出查看脚手架配置文件指令
一个终端指令,可以把脚手架的所有配置输出成一个.js文件(只能用来看,但不能直接在这个生成的文件里改配置)vue inspect > output.js
脚手架重要属性
ref属性
在组件里面的this指向的是vc(组件实例对象)
给html标签添加ref代替id
在vue中,用ref替代id,给哪个组件加ref,那么在vc中就会收集哪个元素,这样获取的时候直接用this.$refs.名
即可获取真实的对应DOM元素
看下面例子对比
1 | 原本id="name" |
给组件加ref
比如有子组件School,在template中使用这个组件,给它添加了ref</School ref="sch ">
this.refs.sch
这样获取到的是School组件的实例对象,而不是真实的DOM结构(如果这里用id和document.getElementById,那么获取到的是真实的DOM元素)
小结
- 被用来给元素或子组件注册引用信息(id的替代者)
- 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象vc
- 使用方式:
打标识:<h1 ref="xxx">.....</h1>或<School ref="xxx"></School>
获取:this.$refs.xxx
props配置
如果一个子组件要使用多次,每个子组件要不同的数据,那么该怎么办呢
这里的逻辑类似微信转账,不仅要传递数据,还要对方确认接受数据,接受到的数据在组件实例VC上存着
规定传递数据类型
- 简单声明接受(用的最多)
props:['name','age','sex']
- 简单声明接受如何传递数字
在使用组件传递数据的时候,都要用key=”vvalue”d的形式,但是这时的value会默认是字符串形参,如果想要传数字,那么不能写age="18"
要写成:age="18"
这里用到了v-bind动态绑定 - 接受的同时对数据类型进行限制
1
2
3
4
5props:{
name:String,
age:Number,
sex:String
} - 详细的接受规范(用得少)
三个配置项type,required,default,后两个一般不同时出现在一个属性中1
2
3
4
5
6
7
8
9
10
11
12
13
14props:{
name:{
type:String,
required: true //是必须有的
},
age:{
type:Number,
default:18 //默认值
},
sex:{
type:String,
required: true //是必须有的
}
}
注意事项
- props收到的数据不允许更改
props是只读的,传入的数据值不能改(别人给你的转账你不能该金额),Vue底层会监视你对props的修改,发现会警告 - 要修改props传入的数据怎么做
复制一份props的内容到data中,然后去修改data中复制来的数据
如果data里有属性值,传入的数据也有属性值,那么props接受的数据是优先被接收放到vc上的,然后再去data里面配置数据,那么在data里面定义新的属性名,把对传入的数据操作后的结果作为属性值,把这个值放到组件上进行展示即可 - key,ref这种关键内容不能作为数据名进行传递
mixin混入配置项(.js)
本质:复用配置,多组件共享一个配置
单独用一个.js文件定义,不要混合在其他地方
混合与组件数据冲突
(如data数据,mathods方法)如果本身有混合也有,那么用本身的;如果本身没有混合有,那么用混合的
混合与组件都有生命周期
如果混合和组件都有生命周期钩子,那么都要,但是混合的生命周期钩子使用顺序在前
使用方法
- 定义混合
1
2
3
4
5{
data(){.....},
methods:{.....}
...
} - 使用混入
2.1. 全局混入:Vue.minxin(混合名,混合名2)
2.2. 局部混入:mixins:[‘混合名’,’混合名2’]
插件(本质是对象)
用于增强vue,本质是包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
要先定义并开启插件,然后再使用vue,所以要放在创建vm上面应用插件(调用插件)
什么作用
添加比如:全局过滤器、全局自定义指令、全局混入、给vue原型上添加方法
使用方法
建议放在src文件里建(plugins.js),不要混合在别处写
插件不是唯一的,可以应用多个插件
视频小结
scoped属性 (解决样式冲突)
脚手架中编辑样式的小技巧
问题:在组件中写的样式最终都会被汇总到一起,会有类名冲突的可能,在App.vue中后引入的组件的样式会覆盖掉前面引入的同类名的样式
解决办法:
给组件的script标签添加scoped属性,变成<script scoped>
即可
注意App.vue组件中不适用,因为App.vue中写样式就代表几乎所有的都要用
如何在vue中使用less
在style标签上加lang="less"
,不写默认是css
要先断开vue服务,安装less-loader,如果安装失败,可能是兼容性问题,给less-loader降一个版本安装
先查看所有的less版本view less-loader versions
然后安装,如npm i less-loader@7
安装7开头的里面最新的版本
浏览器本地存储(js内容,非vue)
localStorage
浏览器关闭数据依然存在,只有手动清除才会清除
F12–Application-Storage–Local Storage
浏览器本地存储,里面可以看到浏览器保存的本地数据缓存
右边的圆叉是清楚缓存的意思
保存数据
要在这里存储数据,里面的key和value都要是字符串形式localStorage.setItem('key','value')
如果要存一个对象,如let p ={name:雾刃,age:23}
localStorage.setItem('person',JSON.stringify(p))
这样存进去的是对象字符串
读取数据
读取基本的key:value:
localStorage.getItem('key')
如果要读取的是对象字符串:const result = localStorage.getItem('对象key')
console.log(JSON.parse(result))
删除单个数据
localStorage.removeItem('key')
清空缓存
````localStorage.clear()``
注意
如果读取的数据不存在,返回null
##sessionStorgae
浏览器关闭,数据就会清除
session:会话
F12–Application-Storage–Session Storage
语法和loaclStorage一样,把上面的loacl替换成session即可
组件的自定义事件(重点)
内置的js事件是给html用的,如keyup;这里的自定义事件是给组件用的
组件的自定义事件是一种组件间的通行方式,适用于子组件-->父组件
在父组件里面给子组件绑定自定义事件,由子组件触发,事件的回调是在父组件上的方法里的,这样才能收到数据
不适用于兄弟之间传递数据!
组件的自定义事件--三种方法实现子给父传递数据:props、组件的自定义事件、ref实现
props方法实现
先回顾props方法实现子组件给父组件传递参数:
props补充(两个图,子组件给父组件传递数据,要通过父组件给子组件提供的方法)
自定义事件--@或v-on实现
父组件给子组件的组件标签上绑定函数goodmorning,如<Student v-on:goodmorning="letItGo"/>
因为v-on在组件标签上,所以是给Student这个组件的实例对象vc上绑定goodmorning这个事件,然后在父组件的methods上添加demo(){函数}
这个goodmorning事件怎么触发呢?给谁绑定就谁来触发,所以找Student实例对象,在这里面借助$emit
来触发goodmorning事件
具体到底该怎么做?
在子组件上给按钮绑定点击事件letItGo,在methods中实现letItGo,在letItGo中通过this.$emit('goodmorning')
来触发父亲绑在组件实例身上的这个goodmorning事件
1 | Student.vue |
在父组件中methods里用letItGo方法接收参数
1 | App.vue |
自定义事件--ref实现(灵活性强)
1 | Studen.vue |
1 | App.vue |
三者小差距
如果有子要传递给父亲多个参数,建议父亲用自定义参数接受...params
如方法名(name,…params){
console.log(‘收到了子组件传递的数据:’name,params)
}
其中name接受的是子组件传递的第一个参数,params数组接收的是子组件传递的其他参数
自定义组件更简单一点
,ref灵活性强,靠钩子函数,还可以有延迟的功能
接刚才子传父,要只能传递一次该怎么做(一次性事件)
自定义事件
@或v-on写法:在前面的@事件名后加.once
ref写法:把前面的$on
改成$once
上面三种子传父数据的视频例子代码
讲解前面的文字理解已经很清晰了,上面的理解了下面的就能看懂
(找资料,自定义事件)
1 | App.vue |
1 | Student.vue |
给组件实例解绑自定义事件
给谁绑定的自定义事件找谁触发,解绑也一样,在组件实例vc上调用函数解绑
- 解绑一个自定义事件:在被绑定的子组件上调用函数
this. $off(
事件名`)~解绑 - 解绑多个自定义事件:
this.$off(['事件名1','事件名2'])
- 暴力解绑所有自定义事件:
this.off()
销毁当前组件实例
- 销毁当前组件实例:
this.$destroy()
销毁后所有这个组件实例的自定义事件全部不奏效了
注意原生的事件不会被销毁
注意点和小结
在父组件上展示子组件传递过来的数据
想用插值表达式直接展示获取的数据,在data里面定义数据数据名,在父组件methons里给子组件提供的方法里面添加代码,数据名=传递的数据
下面的有点长但仔细读还是好懂的:
注意位置:尤其在用ref时,不要为了省代码在钩子函数里面进行赋值,因为钩子函数里面的this指向的可能是绑定事件对应的子组件,在使用箭头函数的情况下由于箭头函数没有自己的this,所以往外找找到父亲的此时回调函数里的this可以获取到子组件传递回父组件的数据然后赋值。为了避免出错,还是在methods里用this获取父组件收到的数据复制给数据然后再展示
(这也是vue2只允许有一个父亲App.vue的原因之一)
小结(视频课小结截图)
全局事件总线 $bus
可以实现任意组件间的通信
理解全局事件总线
bus:总线。全局事件总线相当于一个能和各个组件建立联系的一个中间站,可以和各个组件之间连线,来实现任意组件间的通信
最规范的写法理解:要想各个组件都能用到,那么就要绑定在vm上,在vm的生命周期beforeCreate时期通过钩子函数创建总线,这样后续的vm和vc都可用this.$bus来连接到总线
有弹幕这样说:原型上有个属性$bus
,它的属性值为vm,这样每个vc都有$bus
,通过this.$bus
访问到这个vm
先发起,再提供数据。
组件A想要接受数据,那么A要自己(在A中,methods里)给$bus绑定自定义事件,让事件的回调留在A组件上,这样A才能收到传过来的数据。
提供数据的组件B通过this.$bus.$emit('A绑定的自定义事件名',要传递的数据)
来把数据传递给A
在A收到数据后,A组件要在beforeDestroy钩子上通过this.$bus.$off('自定义事件名')
解绑当前组件所用到的事件
总线在使用后需要销毁(用完要断开连接)
安装全局事件总线
Vue.prototypr.$bus=this
$bus及时当前应用的vm
1 | main.js文件 |
使用事件总线
接收数据:
A想要接收数据,要自己(在组件A上)给总线$bus
绑定自定义事件,这样事件的回调还留在A组件自身接收收到的数据
1 | A.vue |
提供数据
B想要给A提供数据,要调用A绑在总线$bus身上的自定义事件
通过this.$bus.$emit('A绑定的自定义事件名',要传递的数据)
来把数据传递给A
销毁事件
在A收到数据后,A组件要在beforeDestroy钩子上通过this.$bus.$off('自定义事件名')
解绑当前组件所用到的事件
一定要写自定义事件名,不然vc就被销毁了
消息订阅与发布
实现各个组件之间的通信
理解
类似报纸的订阅与发布,需要数据的人订阅消息,提供订阅名和接收消息的回调函数,发布消息的人根据订阅名把数据传给订阅者的回调函数
实现订阅与发布
一种组件间通信的方式,适用于任意组件间通信
使用第三方库完成pubsub-js(在任意框架都可以用)
安装pubsub:npm i pubsub-js
引入:import pubsub from 'pubsub-js'
接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身
提供数据: pubsub.publish(‘xxx’,数据)
.最好在beforeDestroy钩子中,用 Pubsub.unsubscribe(pid)
去<span style="color:red">取消订阅。</span>
vue封装的过度与动画
动画transition
想让谁有动画效果,就把谁用transition
标签包裹,在css中用特定的样式类名写,如果没有给transition标签定义name,那么默认:.v-enter-active(来)
和v-leave-active(去)
@keyframes 动画名``
如果transition有name属性,那么属性名的.v要变成.name
给transition标签增加appear属性让一上来就有来的效果
过度
集成第三方库 animate.css
animate.style
1.先准备好样式:
元素进入的样式:v-enter:进入的起点;v-enter-active:进入过程中;v-enter-to:进入的终点
元素离开的样式:v-leave:离开的起点;v-leave-active:离开过程中;v-leave-to:离开的终点;
2.使用<transition>
包裹要过度的元素,并配置name属性:
1 | <transition name="hello"> <h1 v-show="isShow">你好啊!</h1> |
- 若有多个元素需要过度,则需要使用:
<transition-group>
且每个元素都要指定 key 值
Vue脚手架配置代理
写在vue.config.js文件中
官方文档代码
vuecli官方文档有代码,直接CV使用
1 | devServer:{ |
解读:
/api
:请求前缀(在端口号后面第一个//中间的地址);如果是/api(可以自定义)那么会走代理指定地址target
的5050,没有就不走。- 代理服务器配置:
pathRewrite{'^/api':''}
这个不能丢,丢了就找不到5050里面的资源了,让5050的地址资源没有前面的API前缀,顺利找到请求的资源 wa:true
用于支持websocketchangeOrigin:ture;
//用于控制请求头中的host值
slot插槽
默认插槽
一个组件内一共只写一个
理解:页面A当中要使用组件B,想要在组件B里面放一个图片,这时A使用B的完整标签并把想要放的图片放进去<组件B名><img></组件B名>
,但是这个图片具体放在哪里需要会到组件B上用插槽标签来表示<slot></slot>
,插槽里面的汉字在A页面没有传递具体的结构时会展示,有具体结构时会被替代
slot里拿到的是app.vue里想传递的解析完之后的,如果css写在app.vue中,那么是标签解析完后带着样式一起放进slot里面的,如果把css写在组件B中,样式也可以展示
具名插槽
具有名字的插槽,组件结构中需要多个slot时候
使用slot属性,能指名道姓地把A中的元素放到B中的插槽里
在页面A要传递的结构上添加slot属性,在组件B的slot上添加name,和a上slot属性的属性值对应
别忘了用tmplate
如果想要放多个标签组成的div到插槽中,不建议用div包裹,使用<templat slot="插槽名">
或<template v-slot=插槽名>
包裹,这样结构更好
注意v-slot只能用在template上面,不能用在div上
作用域插槽
作用域插槽也可以有名字,但没必要
想让使用者A告诉B想使用怎样的结构展示数据,数据在B里面
数据不再放在页面A上面,而是放到了组件B里面,但是根据数据生成的结构是不同的
使用者A要用template标签+scope属性
案例
Todo-list案例--组件化编码流程(未完成)
实现对list清单的添加,选择,全选,删除功能。类似黑马的(小黑记事本)小例子
实现思路
分析能够拆分成几个组件
组件定义:实现局部界面功能的代码与资源的集合对组件的拆分要落实到功能点上
如果觉得对拆分的组件起名很困难,那么可能组件拆分不合理
(1)最大的盒子===App组件
(2)text输入框===添加组件(Add或Header)(这里有个坑哦,Header命名不合法哦)
(3)展示清单列表===内容组件(Todos或List)
(4)底下全选部分===全选组件(Fooer)
(5) 想更到位,List里的todo应该拆分成小组件===(Todo或Item)
实现静态组件
建各个组件文件,给各个组件添加名字,在App.vue中引入和注册
注意不要在App.vue中引入Item组件,因为Item是List的子组件,在List组件里引入注册就好了
只考虑样式,使用组件实现静态页面的效果,不包含动态数据,不考虑交互效果
记得要调整缩进,快捷键shift+tab
大家都在用的样式放在App.vue里面,其他的样式各自给各自,记得后面的要加在scoped
展示动态数据
把数据存到对应的容器里
谁展示数据,就把数据给谁--List展示数据
每一个todo包含:
判断完成没有:done或completed
id一般用字符串
页面展示通过组件+v-for
同时父组件要给子组件传递数据
子组件根据传过来的数据判断多选框是否勾选
看资料总结吧,这部分视频没仔细看
数据由父组件管理,子组件操作父组件的数据通过调用父组件下发的方法
上部分是不完善版本的TODOLIST
注意数据名,数据类型,哪个数据保存在哪个组件里
- 数据存储:
在js中存一堆数据一般有两种选择:数组[]或对象{}
在此处每一个要做的事建议用数组包对象的形式存储[{属性如:id name 标识做否},{},{}] - 数据保存在那个组件:
简单粗暴:谁用数据就放在谁里面
在脚手架中修改代码保存后,会自动重新编译(ctrl+s)后重新编译
在vscode中开启终端
建议安装插件 Vetur –Pine Wu
脚手架里面组件可以用自闭合标签
找不到模块可能是路径写错了
如果在App中引入爆红,可能是引入的组件名不合法
vue鼓励语义化的多单词的大驼峰的组件名
注意代码规范性,语义化要高,注解要多写
其他
vue项目中常用的两个ajax库
vue插件库 vue-resourece
类似axios库,但是这个库年久失修了,了解,最重要的还是axios
先安装,然后在main.js中引入插件使用插件