1-父组件向子组件通信
1.1-步骤
自定属性的方式实现数据传递
-
父组件中:
在子组件的调用标签上, 通过v-bind动态设置一个自定义属性,将父组件中需要传递的数据赋值给自定义属性
<!-- 父向子: 第一步 --> <List v-bind:dataList="list"/>
-
子组件中:
在子组件的配置对象中通过props属性节点来接收父组件通过自定义属性传递过来的数据
export default { // 父向子: 第二步(数组元素需要和自定义属性的名称保持一致) props:['dataList'], data(){ return { // 控制添加模态框的显示状态 isAdd:false } }, methods:{ } };
1.2-对props数据的类型进行校验
- 数据类型可选值:
String/Number/Boolean/Undefined/Null/Array/Object
-
写法1
export default { // 实现对props数据进行类型校验 props: { isAdd:Boolean } }
-
写法2
export default { props: { // 数据类型:[默认值] msg: [String, Number] } }
-
写法3
export default { props: { dataList: { // 数据类型 type: Array, // 如果是对象或者数组, 建议使用函数的方式返回默认值 default() { return [ { id: 4, title: "新添加", content: "新添加内容" } ]; } }, msg:{ // 数据类型 type:String, // 默认值 default:'你好' } } }
1.3-props数据和data数据的区别
- props数据
- props来自外部的数据
- 如果props数据类型是基本数据类型(String,Number,Boolean), 那么不能重写
- 如果props数据类型是引用数据类型(Array,Object), 那么可以重写
- data数据
- data数据是组件内部的数据
- data数据可读可写
1.4-注意事项
1. props数据的名字不要和data同名
2-子组件向父组件通信
- 通过自定义事件的方式实现子组件向父组件传递数据
2.1-步骤
-
父组件中:
在子组件的调用标签上通过v-on绑定一个自定义事件, 然后在父组件中的methods中定义一个方法, 充当自定义事件的处理函数
<!-- 注册自定义事件 --> <List v-bind:dataList="list" :msg="'hello'" @del="del"/>
del(id){ // console.log(id,'index.vue'); // 1-通过id查找索引 const index=this.list.findIndex(item=>item.id===id); // 通过splice方法删除数据元素 this.list.splice(index,1); }
-
在子组件中:
通过this.$emit('自定义事件的名称','需要传递数据')触发自定义事件
// 删除按钮的点击事件处理函数 del(id){ // 2-触发自定义事件, 并且传递数据 this.$emit('del',id); }
3-非父子组件之间通信
- 通过自定义事件实现非父子组件的数据通信
实现步骤
-
创建一个空的vue实例对象
vm
, 充当事件中心的角色/utils/vm.js
// 1-导入vue import Vue from 'vue'; // 创建一个空的vue实例, 充当事件中心的角色 export default new Vue();
-
在A组件中通过事件中心
vm.$emit()
触发自定义事件/pages/list.vue
// 编辑按钮的事件处理函数 edit(row){ // 显示alert组件 this.$emit('updateIsAdd',true); // 1-通过自定义事件传递待编辑的数据 vm.$emit('contentUpdate',row); }
-
在B组件中通过事件中心
vm.$on()
监听自定义事件的执行/pages/alert.vue
created(){ // 2-监听自定义事件 // vm.$on('自定义事件名称',事件处理函数); vm.$on('contentUpdate',(obj)=>{ // 更新表单数据模型 this.formData=obj; }) }
4-ref属性
-
虚拟DOM: 特殊的对象
const h1={ name:'h1', attributes:{ title:'属性值', style:{ color:'red' }, className:'.container' }, children:[ 'h1的内容' ] } const div={ name:'div', attributes:{ title:'属性值', style:{ color:'red', fontSize:'20px' }, className:'.container' }, children:[ '文本内容', h1 ] }
-
作用: 帮我们间接操作标签对象或者组件对象
4.1-ref属性操作标签
-
在目标元素(标签/组件)添加一个ref属性, ref属性的值必须保证唯一不重复
<h1 ref="h1">{{msg}}</h1>
-
在逻辑层通过
this.$refs.ref属性名
获取标签的虚拟dom
对象或者组件对象this.$refs.h1.style.color='red'; this.$refs.h1.style.border='1px solid red'; this.$refs.h1.style.backgroundColor='yellow';
4.2-ref属性操作组件
-
在组件调用标签上添加一个
ref
属性, 保证ref
属性值的唯一性<Box1 ref="box1"/>
-
在逻辑层通过
this.$refs.ref属性名
获取组件对象// 组件对象 console.log(this.$refs.box1); // 获取组件内部的数据 console.log(this.$refs.box1.msg); // 调用组件内部的方法 this.$refs.box1.setMsg('更新过的msg'); // 修改组件的视图(操作组件视图的虚拟dom必须通过$el属性) this.$refs.box1.$el.style.backgroundColor='green';
5-is属性
- 作用: 接收组件名称
- 使用范围
- component动态组件
- 普通html标签
6-vue项目中引入jquery
6.1-下载安装
npm i jquery -S
6.2-使用
import $ from 'jquery'
7-vue中使用swiper轮播图插件
7.1-下载安装
npm i swiper@3.4.2 -S
7.2-使用
-
导入swiper核心js
import Swiper from 'swiper'
-
导入样式文件
import 'dist/css/swiper.min.css'
-
初始化
<div class="swiper-container"> <div class="swiper-wrapper"> <div class="swiper-slide">Slide 1</div> <div class="swiper-slide">Slide 2</div> <div class="swiper-slide">Slide 3</div> </div> <!-- 如果需要分页器 --> <div class="swiper-pagination"></div> <!-- 如果需要导航按钮 --> <div class="swiper-button-prev"></div> <div class="swiper-button-next"></div> </div>
// 初始化 var swiper = new Swiper('.swiper-container', { pagination: '.swiper-pagination', paginationClickable: true, lopp:true, autoplay:1000 });
.swiper-container { 100%; height: 100%; }
8-插槽
- 插槽也是外部向组件内部传递数据的一种方式
- 传递的是标签结构
- 通过组件调用标签之间
8.1-匿名插槽
8.1.1-定义
<template>
<div class="cmt-container">
<h3>评论</h3>
<hr>
<!-- 占位 -->
<slot></slot>
</div>
</template>
<script>
export default {}
</script>
<style scoped>
.cmt-container{
600px;
height: 200px;
margin:40px auto;
line-height: 50px;
padding:10px;
background: lightyellow;
}
</style>
8.1.2-调用
<Comment>
<input type="text" placeholder="请输入评论内容" />
<hr />
<button>立即提交</button>
</Comment>
<hr />
<Comment>
<div>
<textarea placeholder="请输入评论内容" cols="30" rows="3"></textarea>
<hr />
<button>立即提交</button>
<button>清空</button>
</div>
</Comment>
8.2-具名插槽
8.2.1-定义
- slot: 充当占位符
<template>
<div class="panel-container">
<!-- 具名插槽 -->
<slot name="header"></slot>
<div>
<input type="text" placeholder="用户名"/>
</div>
<div>
<input type="text" placeholder="密码"/>
</div>
<slot name="footer"></slot>
</div>
</template>
<script>
export default {}
</script>
<style>
.panel-container{
600px;
height: 140px;
margin:60px auto;
background: lightyellow;
padding:10px;
line-height: 30px;
}
</style>
8.2.2-调用
- slot: 充当占位符
<Panel>
<div slot="header">
<h3>登录页面</h3>
</div>
<div slot="footer">
<button>立即登录</button>
<button>重置表单</button>
</div>
</Panel>
8.3-作用域插槽
8.3.1-定义
- slot插槽组件的2个作用:
- 1-占位符
- 2-分发数据
<template>
<div class="list-container">
<ul>
<li v-for="item in list" :key="item.id">
<!--
slot插槽组件的2个作用: 1-占位 2-分发数据
-->
<slot :row="item"></slot>
</li>
</ul>
</div>
</template>
<script>
export default {
data(){
return {
list:[
{
id:3,
name:'vue'
},
{
id:2,
name:'react'
},
{
id:1,
name:'angular'
}
]
}
}
}
</script>
<style>
.list-container{
400px;
height: 200px;
margin:20px auto;
background: #EEE;
}
.list-container li{
list-style: none;
padding:10px;
line-height: 30px;
border-bottom:1px dashed #999;
}
.list-container li label{
cursor: pointer
}
</style>
8.3.2-调用
-
老写法:
slot-scope
<List> <!--props为模板变量, 名字自己定义, 保存的是slot插槽组件上的自定义属性--> <!-- slot组件上的属性集合 --> <!-- slot-scope:老的写法 --> <template slot-scope="props"> <label> <input type="checkbox" /> {{props.row.id}}---{{props.row.name}} </label> </template> </List>
-
新写法:
v-slot
<List> <!-- v-slot: 最新写法 --> <template v-slot="obj"> <label> <input type="radio" name="lang"/> {{obj.row.id}}---{{obj.row.name}} </label> </template> </List>
9-组件样式添加作用域
- 在组件内的
style
标签之上添加一个scoped
属性, 即可实现让组件内的选择器只对当前组件的视图生效, 而不会影响到其他组件
<style scoped>
</style>
组件内样式添加作用域的原理
vue
会生成一个随机的字符串, 如data-v-02e4c64b
- 将
style
标签内的选择器改写为交集选择器,如.container[data-v-02e4c64b]
- 在调用选择器的标签上添加随机属性
<div class="container" data-v-02e4c64b></div>