1.组件的注意点
1.template只能有一个根元素
约束:.vue文件中的template中如果写了两个元素,则会报如下错误
解决:保证template中只有一个根元素即可
2.scoped解决样式冲突
1全局样式: 默认组件中的样式会作用到全局,任何一个组件中都会受到此样式的影响
2局部样式: 可以给组件加上scoped 属性,可以让样式只作用于当前组件
默认情况:写在组件中的样式会 全局生效 → 因此很容易造成多个组件之间的样式冲突问题。
解决:在组件style标签上增加scoped来解决
scoped原理
1当前组件内标签都被添加data-v-hash值 的属性 ,每个组件的hash值是不同的
2css选择器都被添加 [data-v-hash值] 的属性选择器
最终效果: 必须是当前组件的元素, 才会有这个自定义属性, 才会被这个样式作用到
3.data必须是一个函数
一个.vue组件的 data 选项必须是一个函数。否则会报错
这么要求的原因:保证每个组件实例,维护独立的一份数据对象,保证组件实例之间的数据相互隔离不受影响
每次创建新的组件实例,都会新执行一次data 函数,得到一个新对象。
2.组件通信
1.父子之间通信
1.用法
父向子传值步骤:
- 准备一个父组件 App.vue,一个子组件Son.vue
- 在App.vue中使用Son.vue让它们构成一个父子组件关系,在使用子组件的同时
-
- 通过
:自定义名字="需要传递的值"
将父组件中的数据传给子组件
- 通过
- 子组件内部通过props接收
props:['父组件中自定义名字']
- 子组件内部模板中直接使用 props接收的值
{{ 父组件中自定义名字 }}
✨✨ 注意点:父组件中的响应式数据改变,会自动同步到子组件
子组件利用 $emit 将自己的数据传递给父组件
子向父传值步骤:
- $emit触发事件,给父组件发送消息通知
- 父组件监听$emit触发的事件
- 提供处理函数,在函数的形参中获取传过来的参数
注意:上面代码其实是一个 父子通信的双向数据绑定
2.props校验
思考:组件的props数据类型可以乱传吗?不能
- 比如进度条百分数只能是数字
props校验:为组件的 prop 指定验证要求,不符合要求,控制台就会有错误提示 → 帮助开发者,快速发现错误
props校验的类型:
- 类型校验(常用)
- 非空校验
- 默认值
- 自定义校验
语法:
① 只校验类型【常用】
② 完整写法
// ✨✨✨注意点:属性的类型必须使用大写 Number,Boolean,String,Array,Object
- default和required一般不同时写(因为当时必填项时,肯定是有值的)
- default后面如果是简单类型的值,可以直接写默认。如果是复杂类型的值,则需要以函数的形式return一个默认值
3.props与data
共同点:一个组件中props和data,都可以给组件提供数据
区别:
- data 的数据是自己的 → 随便改
- prop 的数据是外部的 → 不能直接改,要遵循 单向数据流
单向数据流:父级props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的
特点:子组件修改prop数据不会影响到父组件的数据
约定:谁的数据,谁负责修改
2.跨层级通信
1.事件总线-EventBus(传递事件)
作用:事件总线event bus可以用在非父子组件之间,进行简易消息传递 (复杂场景→ Vuex)
需求:B组件向C组件进行传递数据
使用步骤:(媒婆传话)
- 创建一个都能访问到的事件总线 (空 Vue 实例) → utils/EventBus.js
- C 组件(接收方),监听 Bus 实例的事件
- B 组件(发送方),触发 Bus 实例的事件
2.provide与inject(传递数据)
作用:provide&inject可以实现组件的跨层级共享数据
provide&inject传递数据使用步骤:
- 父组件 provide 提供数据
- 子/孙组件 inject 取值使用
注意:
- provide提供的简单类型的数据不是响应式的,复杂类型数据是响应式。(推荐提供复杂类型数据)
- 子/孙组件通过inject获取的数据,不能在自身组件内修改
3.v-model原理
思考:默认情况下我们可以给组件用上 v-model进行双向数据绑定吗? 不能 -> 那么如何做?
解决方法:
- 用vue实现 v-model 的写法(原理)
- 用 v-bind:属性.sync 修饰符
1.v-model
v-model原理:v-model本质上是一个语法糖 -> 应用在输入框上,就是value属性 和 input事件 的合写
作用:v-model是双向数据绑定
① 数据变,视图跟着变 :value
② 视图变,数据跟着变 @input
说明:$event 用于在模板中,获取事件的形参 (这里的$event就是事件对象e)
说明:
不同的表单元素, v-model在底层的处理机制不一样。
- 给文本框,文本域 -> Vue框架底层是拆解成
value属性 + input事件
来实现 - 下拉框 -> Vue框架底层是拆解成
value属性 + change事件
来实现 - 给复选框,单选框 使用v-model ->Vue框架底层是拆解成
checked属性和change事件
来实现
javascript"><template><div id="main"><input type="text" v-model="value1" />{{ value1 }}<hr /><input type="text" :value="value2" @input="value2 = $event.target.value" />{{ value2 }}<hr /><MyTable v-model="value3"></MyTable></div>
</template><script>
import MyTable from "./components/MyTable.vue";export default {components: {MyTable,},data() {return {value1: "",value2: "",value3: "",};},
};
</script><style>
</style>
javascript"><template><div class="box"><input type="text" @input="change" />{{ value }}</div>
</template><script>
export default {props: {value: {type: String,},},methods: {change(e) {this.$emit("input", e.target.value);},},
};
</script><style scoped>
.box {width: 200px;height: 200px;border: 1px solid pink;
}
</style>
2.sync修饰符
作用:可以实现 子组件 与 父组件数据 的 双向绑定
.sync修饰符原理: :属性名 和 @update:属性名 的合写
本质上和v-model是一样的,也是一个父子组件通信的情况
3.ref与$refs
作用:利用 ref 和 $refs 可以用于 获取 dom 元素, 或 组件实例
ref和$refs特点:查找范围 → 当前组件内 (更精确稳定)
语法:
4.Vue异步更新 & $nextTick
Vue的异步更新特性
javascript"><template><div class="app"><span ref="span">{{ num }}</span><button @click="addone">+1</button></div>
</template><script>
export default {data() {return {num: 1,};},methods: {addone() {this.num++;this.num++;console.log(this.num);//打印3console.log(this.$refs.span.innerHTML) //❌还是拿到上一次的值1},},
};
</script><style>
</style>
Vue 在更新 DOM 时是异步执行的(异步渲染)
- 只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更
- 如果同一个 watcher 被多次触发,只会被推入到队列中一次。
- 在下一个的事件循环中(nextTick),Vue 刷新队列并执行实际 (已去重的) 任务(先进先执行)
上面代码中,当num的值改变时,由于dom更新是异步的,所以通过
this.$refs.span.innerHTML拿到的结果是不准确的。
如何解决?使用 $nextTick
$nextTick
$nextTick:等 DOM 更新后, 才会触发执行此方法里的函数体
语法:
- 回调函数写法: this.$nextTick(()=>{ })
- Promise写法: this.$nextTick().then(res=>{ })