写在组件中的样式会 全局生效 → 因此很容易造成多个组件之间的样式冲突问题。
全局样式: 默认组件中的样式会作用到全局,任何一个组件中都会受到此样式的影响
局部样式: 可以给组件加上scoped 属性,可以 让样式只作用于当前组件
scoped原理:
最终效果:必须是当前组件的元素,才会有这个自定义属性,才会被这个样式作用到。
一个组件的 data 选项必须是一个函数。目的是为了:保证每个组件实例,维护独立的一份数据对象。
每次创建新的组件实例,都会新执行一次data 函数,得到一个新对象。
<template>
<div class="baseCount">
<button v-on:click="count--" v-show="count >0">-</button>
<span>{{count}}</span>
<button @click="count++">+</button>
</div>
</template>
<script>
export default {
//data()函数与data:达成的效果一样
//data必须是一个函数 --->保证每个组件实例,维护独立的一个数据对象
data(){
console.log("1111")
return {count:999}
}
}
</script>
<style>
</style>
App.vue
<template>
<div class="app">
<BaseCount></BaseCount>
<BaseCount></BaseCount>
<BaseCount></BaseCount>
</div>
</template>
<script>
//导入相关组件
import BaseCount from './components/BaseCount.vue'
export default {
name: 'app',
components: {
BaseCount : BaseCount
}
}
</script>
<style>
</style>
组件通信:就是指组件与组件之间的数据传递
App.vue
<template>
<div class="app">
myData: {{myData}}
<!-- 父传子组件通信 -->
<!-- 1.给组件标签,添加属性方式,传指 -->
<BaseSon v-bind:title="myData"></BaseSon>
</div>
</template>
<script>
//导入子组件
import BaseSon from './components/BaseSon.vue'
export default {
name: 'app',
components: {
BaseSon : BaseSon
},
data(){
return {
myData : 'radan学习Vue知识'
}
}
}
</script>
<style scoped>
</style>
BaseSon.vue
<template>
<div class="son" >
<!-- 3.在子组件中渲染使用 -->
{{title}}
</div>
</template>
<script>
export default {
// 2.通过props进行接受
props:['title']
}
</script>
<style scoped>
div{
border: 3px solid pink;
margin: 10px;
width: 260px;
height: 60px;
}
</style>
通信步骤:
App.vue
<template>
<div class="app">
myData: {{myData}}
<!-- 2. 父组件要对子组件发送的消息进行监听 -->
<BaseSon v-bind:title="myData" @changeTitle="handleChange"></BaseSon>
</div>
</template>
<script>
import BaseSon from './components/BaseSon.vue'
export default {
name: 'app',
components: {
BaseSon : BaseSon
},
data(){
return {
myData : 'radan学习Vue知识'
}
},
methods:{
// 3. 提供处理函数
handleChange(newTitle){
// alert(newTitle)
this.myData=newTitle
}
}
}
</script>
<style scoped>
</style>
BaseSon.vue
<template>
<div class="son" >
我是Son组件
<button @click="changeFn()">修改父组件中的数据</button>
</div>
</template>
<script>
export default {
props:['title'],
methods:{
changeFn(){
// alert("你好")
// 1. 通过$emit,向父组件发生消息通知
this.$emit('changeTitle','randa不想学习')
}
}
}
</script>
<style scoped>
div{
border: 3px solid pink;
margin: 10px;
width: 260px;
height: 60px;
}
</style>
小黑记事本--------------组件版
<template>
<!-- 主体区域 -->
<section id="app">
<TodoHeader @addProject="addProject" ></TodoHeader>
<!-- 将list中的数据提供给todoMain组件 -->
<TodoMain :list="list" @changeDel="changeDel" ></TodoMain>
<TodoFooter :list="list" @delAll="delAll" v-show=" list.length>0"></TodoFooter>
</section>
</template>
<script>
import TodoFooter from './components/TodoFooter.vue'
import TodoHeader from './components/TodoHeader.vue'
import TodoMain from './components/TodoMain.vue'
//A:渲染功能:
// 1. 提供数据-->提供在公共的父组件中
// 2. 通过父传子,将数据传递给其他组件
// 3. 利用 v-for 渲染
/**
* B:添加功能
* 1.收集表单数据 --> v-model
* 2.监听事件(回车+点击 都要进行添加)
* 3.子传父将任务名称传递给父组件
* 4.进行添加 unshift(自己的数据自己负责)
*/
/**
* C:删除功能
* 1.监听事件(监听删除的点击)携带id
* 2.子传父,将删除的id传递给父组件App.vue
* 3.进行删除 filter(自己的数据自己负责)
*/
/**
* D:footer功能
* 1.底部合计:父传子list--->渲染
* 2.清空功能:子传父,父修改
* 3.持久化存储:watch深度监视list的变化-->往本地存储 --->进入页面优先读取本地信息
*/
export default {
components:{
TodoFooter:TodoFooter,
TodoHeader:TodoHeader,
TodoMain:TodoMain
},
data(){
return {
//优先读取本地信息
list:JSON.parse(localStorage.getItem('list')) || [
{id:1,name: '打篮球'},
{id:2,name: '打羽毛球'},
{id:3,name: '看电影'}
]
}
},
methods:{
changeDel(id)
{
//按照id删除数组中的元素
this.list = this.list.filter(item => (item.id != id))
},
addProject(value){
//向数组添加一个元素
this.list.unshift({
id : +new Date(),
name : value
})
},
delAll(){
//清空数组中的所有元素
this.list=[]
// alert(this.list)
}
},
watch:{
list:{
deep: true,
handler(newValue){
localStorage.setItem('list',JSON.stringify(newValue))
}
}
}
}
</script>
<style>
</style>
ToDoHeader.vue
<template>
<!-- 输入框 -->
<header class="header">
<h1>小黑记事本</h1>
<input placeholder="请输入任务" class="new-todo" v-model="inputInfo" />
<button class="add" @click="addProject">添加任务</button>
</header>
</template>
<script>
export default {
data(){
return{
inputInfo: '' //和表单的输入框进行数据绑定
}
},
methods:{
addProject(){
if(this.inputInfo.trim() === ''){
alert("添加的元素不能为空")
return
}
else{
this.$emit('addProject',this.inputInfo)
this.inputInfo=''
}
}
}
}
</script>
<style>
</style>
ToDOMain.vue
<template>
<!-- 列表区域 -->
<section class="main">
<ul class="todo-list" v-for="(item,index) in list" :key="item.id">
<li class="todo">
<div class="view">
<span class="index">{{index +1 }}</span> <label>{{item.name}}</label>
<button @click="del(item.id)" class="destroy"></button>
</div>
</li>
</ul>
</section>
</template>
<script>
export default {
props:{
list:Array
},
methods:{
del(value){
// console.log(value)
this.$emit('changeDel',value)
}
}
}
</script>
<style>
</style>
ToDoFooter.vue
<template>
<!-- 统计和清空 -->
<footer class="footer">
<!-- 统计 -->
<span class="todo-count">合 计:<strong> {{list.length}} </strong></span>
<!-- 清空 -->
<button class="clear-completed" @click="delAll">
清空任务
</button>
</footer>
</template>
<script>
export default {
props:{
list:Array
},
methods: {
delAll(){
//子传父
this.$emit('delAll')
}
}
}
</script>
<style>
</style>
定义:组件上注册的一些自定义属性
作用:向子组件传递数据
特点:
思考:组件的prop可以乱传?
作用:为组件的prop指定验证要求,不符合要求,控制台就会有错误提示。----->帮助开发者,快速发现错误。
校验语法:
数据类型校验:将props数组的形式改为对象的形式
//数据类型校验:将props数组的形式改为对象的形式
// props:['title']
props:{
title: String //String Boolean Array Object Function等等
},
//2.完整写法
props:{
title: {
type: String,//类型校验
required: true, //必传属性:父传子的属性没有传就会报错
default: 'hello radan',//默认值属性:当父组件组没有自定义属性绑定的时候,就会按照默认值进行处理
//自定义校验
validator(value){
console.log(value)
//对当前的title对应的value是否符合一定的条件
return true;
}
}
注意:validator(value)中的value形参就是父组件传递过来的值
prop&data中谁的数据谁负责
共同点:都可以给组件提供数据。
区别:
单向数据流:父级props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的
子组件修改props中的数据
App.vue
<template>
<div class="app">
<BaseCount :title="myData" @changeCount="changeFn"></BaseCount>
</div>
</template>
<script>
import BaseCount from './components/BaseCount.vue'
export default {
name: 'app',
components: {
BaseCount : BaseCount
},
data(){
return {
myData : 1
}
},
methods:{
changeFn(value){
// alert(value)
this.myData=value
}
}
}
</script>
<style scoped>
</style>
BaseCount.vue
<template>
<div class="baseCount">
<button v-on:click="countSub" v-show="title >0">-</button>
<span>{{title}}</span>
<button @click="countAdd">+</button>
</div>
</template>
<script>
export default {
// 1. data中的数据可以在当前组件中随便改
// data(){
// return {count:999}
// }
// 2. props中的数据的修改办法:
props:{
title:Number
},
methods:{
countAdd(){
this.$emit('changeCount',this.title+1)
},
countSub(){
this.$emit('changeCount',this.title-1)
}
// ,
// isTrue(value){
// console.log(value)
// if(value>0)
// {
// return true
// }
// }
}
}
</script>
<style>
</style>