复习笔记
时隔一年,再次学习VUE,发现了很多曾经没有留意到的用法,原来组件间通信除了常规的那几种,竟然还有好多我不知道的写法,原来v-model也能用来通信,真的收获了很多,正所谓温故而知新呐
1.项目用到的插件
- 进度条 NProgress
- 轮播图 Swiper
- 二维码 qrcode
- 懒加载 vue-lazyload
- 防抖节流 lodash
- 随机ID nanoid
- 表单验证 vee-validate
2.自定义插件plugins
里面可以封装的内容
- Vue.prototype.$bus 任何组件都可用
- Vue.directive
- Vue.component
MyPlugins.js
// VUE插件一定暴露一个对象
let myPlugins = {};
// 插件必须使用install进行定义
myPlugins.install=function(Vue,options){
第一个参数是Vue注入
第二个参数是传入的内容
举例:封装一个自定义指令(变大写)
Vue.directive(options.name,(element,attrs)=>{
element.innerHTML = attrs.value.toUpperCase()
})
}
export default myPlugins;
main.js
import myPlugins from '@/plugins/myPlugins'
安装插件
vue.use(myPlugins,{
name:'upper'
})
组件中使用
<template>
<div>
<h1 v-upper="msg"></h1>
</div>
</template>
<script>
data(){
return {
msg:'abc'
}
}
</script>
3.路由懒加载
优化性能,按需引入,当使用到目标路由时,才加载对应的组件
routes.js
{
path:"/home",
component:()=>import('@/pages/home'),
meta:{},
children:{}
}
4.项目打包
npm run build
-
打包后的js文件会被压缩加密,因此看不懂哪里报错
-
在打包后的disk中的js文件中,会发现多了一些map后缀的文件
-
map后缀文件的作用就是:如果运行时报错,可以精准的知道是哪行哪列报错
-
但是当项目准备打包时,已经不需要知道报错的信息了,因此打包后,把map文件删了
可以在Vue.config.json中配置,不产生map文件
productionSourceMap:false
后台通用系统
知识点归纳
1.组件间的通信方式(6种)
第一种:props
适用场景:父子组件通信
注意事项:
- 如果父组件给子组件传递数据(函数):本质其实是子组件给父组件传递数据
- 如果父组件给子组件传递数据(非函数):本质就是父组件给子组件传递数据
书写方式:3种
-
["todos"]
-
{type:Array}
-
{type:Array, default:[ ] }
路由的props:
书写形式 :布尔值,对象,函数
第二种:自定义事件
适用场景:子组件给父组件传递数据
$on和$emit
第三种:全局事件总线$bus
适用场景:万能
vue.prototype.$bus = this;
第四种:pubsub-js
适用场景:万能
在React框架中使用比较多。(发布与订阅)
第五种:Vuex
适用场景:万能
数据仓库
第六种:插槽slot
适用场景:父子组件通信(一般结构)
- 默认插槽
- 具名插槽
- 作用域插槽
第七种:V-Model
第八种:sync修饰符
相当于给对应的组件绑定了一个update:开头的自定义事件
:ABC.sync ==> update:ABC
第九种:$attrs以及$listeners
第十种:$children以及$parent
2.自定义组件的深入
原生DOM绑定原生事件
<button @click="abc"></button>
原生DOM绑定自定义事件
没有什么意义:因为原生的DOM不能够去调用$emit触发自定义事件
<button @myevent="abc"></button>
组件component绑定原生事件
-
原生事件会被当作自定义事件来看待
import Home from '@/page/home' <Home @click="abc"></Home> 当点击组件时,没有任何效果 -
如果想要绑定成原生的事件,就在事件后面.native
-
native就是原生的意思
-
这个原生的事件,其实是给子组件的根节点绑定了点击事件—利用了事件委派
import Home from '@/page/home' <Home @click.native="abc"></Home> 当点击组件里的内容时,就会调用abc函数
组件component绑定自定义事件
父组件中
import Home from '@/page/home'
<Home @myevent="abc"></Home>
当点击组件里的内容时,就会调用abc函数
methods:{
abc(params){
console.log('myevent事件被子组件出发了,携带的参数为',params)
}
}
子组件中
当点击子组件中的这个按钮时,就会触发父组件绑定的myevent这个自定义事件
$emit(’父组件自定义事件名称‘ ,参数)
<button @click="$emit('myevent','33112')"></button>
上述案例的执行结果
myevent事件被子组件出发了,携带的参数为33112
3.V-Model的深入
v-model也可以进行父子间的通信,实现数据的同步
实现方式:使用v-model结合原生的@input事件
- 原生DOM中有事件oninput,它经常结合表单元素一起使用,当表单元素发生变化时就会触发一次回调
- 在VUE2中,可以通过:value和input实现v-model的功能
父组件中
以下的两种写法都是等价的
- 第一种写法: V-model实现 (简化写法)
import Home from '@/page/home'
<Home v-model="msg"></Home>
data(){
return:{
msg:'中国'
}
}
- 第二种写法: 自定义事件 + : value实现
import Home from '@/page/home'
<Home :value="msg" @myevent="msg = $event" ></Home>
data(){
return:{
msg:'中国'
}
}
子组件中
<input type="text" :value="value" @input="$emit('myevent',$event.target.value)" > </input>
接受父亲通过props传进来的value
props:['value']
4.sync修饰符的深入
可以实现父子组件的数据同步
以下使用sync和不用sync的效果相同
- 当不使用sync修饰符时
父组件中
父组件通过props将abc传给子组件,还绑定了自定义事件myUpdateMoney
自定义事件myUpdateMoney的操作abc=$event的意思是把子组件传回来的值赋值给abc
现在的值为{{abc}}
<Home :abc="abc" @myUpdateMoney="abc=$event"></Home>
data() {
return {
abc:120
}
},
子组件中
<button @click="$emit('myUpdateMoney',abc-1)">花钱</button>
props: ['abc']
-
当使用sync修饰符时
-
给对应的组件传递props
-
给对应的组件绑定了一个update:开头的自定义事件
-
举例 的效果就是
- 给Home组件传递props为abc
- 给Home组件绑定了一个名为update:abc自定义事件
-
父组件中
现在的值为{{abc}}
<Home :abc.sync="abc"></Home>
data() {
return {
abc:120
}
},
子组件中
<button @click="$emit('update:abc',abc-1)">花钱</button>
props: ['abc']
5.$attrs和$listeners属性
$attrs
-
介绍:$attrs是组件身上的一个属性
-
作用:用于接受父组件传过来,但未被子组件接收的的props
-
注意:当子组件接收了某个props后,它将从$attrs中消失
-
使用场景:可以通过V-bind结合$attrs一键绑定所有传过来的数据
-
举例:封装一个element的按钮,让其可以带有提示效果
-
思路1:因为a标签的title具有提示的效果,所以可以在button外面包一个a便签,写上title
-
思路2:因为是封装,所以要增强其复用性,不能把属性写死,因此要父组件传过来绑定
-
思路3:这里的v-bind不能用:代替,要写全
父组件
<MyButton title="提示按钮" type="success" icon="el-icon-delete" size="mini"></MyButton>子组件
<template> <div> <a :title="title"> <el-button v-bind="$attrs"></el-button> </a> </div> </template> <script> export default{ name:'', props: ['title'], } </script>
-
$listeners
-
介绍:$listeners是组件身上的一个属性
-
作用:用于获取父组件给子组件传递的自定义事件
-
使用场景:可以通过v-on结合$listeners触发父组件的自定义事件
-
举例:父组件给子组件绑定一个事件,当点击子组件时,触发父组件绑定的这个事件
-
思路1:要通过v-on绑定listeners,以触发父组件的自定义事件
-
思路2:v-on不能简写为@
父组件
注意这里的click是自定义事件
<MyButton type="success" size="mini" @click="alert('触发')"></MyButton>子组件
<el-button v-on="$listeners"></el-button>
-
6.$children与$parent属性
ref与$refs
-
在vue组件中,可以通过ref获取到子组件的数据与方法
-
在html标签中用ref,在script的方法中用$refs
<button @click="reduce(100)">点我儿子涨工资</button> <Son ref="abc"></Son> <script> export default{ methods: { reduce(salary){ this.$refs.abc.money+=salary; } }, } </script>
$children
-
$children是组件实例身上的一个属性,可以获取当前组件的所有子组件
-
进而可以操作所有子组件身上的数据与方法,实现父子组件间通信
-
this.$children会将所有的子组件存放在一个数组中
-
尽量别用下标来获取子组件,因为不知道第0项是不是想要的那个子组件
<button @click="reduceAll(100)">点我孩子都涨工资</button> <Son></Son> <Daughter></Daughter> <script> export default{ methods: { reduceAll(salary){ this.$children.forEach(item=>{ item.money+=salary }) } }, } </script>
$parent
- $parent是组件实例身上的一个属性,可以获取当前组件的父组件
- 进而可以操作父组件身上的数据与方法,实现父子组件间通信
<button @click="reduce(100)">点我爸爸涨工资</button>
<script>
export default{
methods: {
reduce(salary){
this.$parent.money+=salary
}
},
}
</script>
7.混入mixin复习
主要放置组件重复的 JS 业务逻辑,以便于复用
myMixin.js
export default{
methods: {
add(a,b){
return a+b
}
}
}
使用该JS业务逻辑的组件
<script>
import myMixin from '@/mixin/myMixin.js'
export default{
mixins:[myMixin]
}
</script>
8.插槽的复习
- 默认插槽
- 具名插槽
- 作用域插槽:子组件的数据来自于父组件,子组件决定不了自身的外观与结构
父组件
- slot-scope用于接受子组件回传的数据,{todo,$index}是对应数据的解构
- 返回的数据中,会以slot-scope="todo"的值为key,值为返回的item对象
- 举例:{"todo",{id:1,text:'A'} } 因此数据要通过todo.todo.text获取
- 子组件无权决定结构和外观,都由父组件决定
<template>
<div>
<Children :todos="todos">
<template slot-scope="{todo,$index}">
<span :style="color='red'">{{todo.todo.text}}</span>
</template>
</Children>
</div>
</template>
<script>
export default {
data(){
return {
todos:[
{
id:1,text:'A'
},
{
id:2,text:'B'
}]
}
}
};
</script>
子组件
- : todo和: $index是将子组件的数据回传给父组件 这就是作用域插槽的语法格式
- todos为父组件通过props传递过来的数据
<template>
<div>
<ul>
<li v-for="(item, index) in todos" :key="index">
<slot :todo="item" :$index="index"></slot>
</li>
</ul>
</div>
</template>
<script>
export default {
props: ["todos"],
};
</script>
总结
在进一步学习Vue之后,我对其API有了更深入的理解,并发现了一些之前未曾注意到的用法和特性。通过学习,我掌握了更多的Vue技巧和最佳实践,进一步提升了自己的开发技能。
我发现Vue的生命周期钩子函数可以帮助我更好地理解组件的创建、更新和销毁过程,以及在不同阶段执行相应的操作,如在created钩子中进行数据初始化,在mounted钩子中进行DOM操作等。我也学到了如何合理使用计算属性和监听属性,以优化性能并简化代码。我还学习了如何使用Vue的动画过渡和动态组件,为我的应用程序增添了一些视觉效果和交互性。我也开始尝试使用Vue的异步组件和路由懒加载来优化应用的加载速度,提升用户体验。
通过深入学习Vue,我意识到组件间通信的重要性,并发现了更多灵活的通信方式,如使用事件总线、Vuex状态管理和provide/inject等。这些方法为我解决了组件间的数据传递和共享状态的问题。熟悉了Vue之后,我感到更加自信和有能力去构建复杂的前端应用程序。我也开始更多地关注Vue社区中的最新动态和开发技术,以不断提升自己,并与其他开发者分享我的经验和知识。
我将继续努力学习和探索Vue的更多特性和用法,以不断提升自己在前端开发领域的能力。