<template>
<div class="base-one">
BaseOne
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
/*
1.style中的样式 默认是作用到全局的
2.加上scoped可以让样式变成局部样式
组件都应该有独立的样式,推荐加scoped(原理)
-----------------------------------------------------
scoped原理:
1.给当前组件模板的所有元素,都会添加上一个自定义属性
data-v-hash值
data-v-5f6a9d56 用于区分开不通的组件
2.css选择器后面,被自动处理,添加上了属性选择器
div[data-v-5f6a9d56]
*/
div{
border: 3px solid blue;
margin: 30px;
}
</style>
<template>
<div class="base-one">
BaseTwo
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
div{
border: 3px solid red;
margin: 30px;
}
</style>
<template>
<div id="app">
<BaseOne></BaseOne>
<BaseTwo></BaseTwo>
</div>
</template>
<script>
import BaseOne from './components/BaseOne'
import BaseTwo from './components/BaseTwo'
export default {
name: 'App',
components: {
BaseOne,
BaseTwo
}
}
</script>
Vue.component('my-component', {
data: {
message: 'Hello, Vue!'
},
template: '{{ message }}'
})
Vue.component('my-component', {
data: function () {
return {
count: 0
}
},
template: '{{ count }}'
})
Vue.component('my-component', {
data() {
return {
message: 'Hello, Vue!'
}
},
template: '<div>{{ message }}</div>'
})
<template>
<div class="base-count">
<button @click="count--">-</button>
<span>{{ count }}</span>
<button @click="count++">+</button>
</div>
</template>
<script>
export default {
data: function () {
return {
count: 100,
}
},
}
</script>
<style>
.base-count {
margin: 20px;
}
</style>
<template>
<div class="app">
<baseCount></baseCount>
<baseCount></baseCount>
<baseCount></baseCount>
</div>
</template>
<script>
import baseCount from './components/BaseCount'
export default {
components: {
baseCount,
},
}
</script>
<style>
</style>
<template>
<div class="app" style="border: 3px solid #000; margin: 10px">
我是APP组件
<!-- 1.给组件标签,添加属性方式 赋值 -->
<Son :title="myTitle"></Son>
</div>
</template>
<script>
import Son from './components/Son.vue'
export default {
name: 'App',
data() {
return {
myTitle: '学前端',
}
},
components: {
Son,
},
}
</script>
<style>
</style>
<template>
<div class="son" style="border:3px solid #000;margin:10px">
<!-- 3.直接使用props的值 -->
我是Son组件 {{title}}
</div>
</template>
<script>
export default {
name: 'Son-Child',
// 2.通过props来接受
props:['title']
}
</script>
<style>
</style>
子组件利用 $emit 通知父组件,进行修改更新
子向父传值步骤
<template>
<div class="son" style="border: 3px solid #000; margin: 10px">
我是Son组件 {{ title }}
<button @click="changeFn">修改title</button>
</div>
</template>
<script>
export default {
name: 'Son-Child',
props: ['title'],
methods: {
changeFn() {
// 通过this.$emit() 向父组件发送通知
this.$emit('changTitle','son')
},
},
}
</script>
<style>
</style>
<template>
<div class="app" style="border: 3px solid #000; margin: 10px">
我是APP组件
<!-- 2.父组件对子组件的消息进行监听 -->
<Son :title="myTitle" @changTitle="handleChange"></Son>
</div>
</template>
<script>
import Son from './components/Son.vue'
export default {
name: 'App',
data() {
return {
myTitle: 'father',
}
},
components: {
Son,
},
methods: {
// 3.提供处理函数,提供逻辑
handleChange(newTitle) {
this.myTitle = newTitle
},
},
}
</script>
<style>
</style>
props: {
w: {
type: Number,
required: true,
default: 0,
validator(val) {
// console.log(val)
if (val >= 100 || val <= 0) {
console.error('传入的范围必须是0-100之间')
return false
} else {
return true
}
},
},
}
共同点:都可以给组件提供数据
区别
父组件代码
<template>
<div class="app">
<BaseCount :count="count" @changeCount="handleChange"></BaseCount>
</div>
</template>
<script>
import BaseCount from './components/BaseCount.vue'
export default {
components:{
BaseCount
},
data(){
return {
count:100
}
},
methods:{
handleChange(newVal){
this.count = newVal
}
}
}
</script>
<style>
</style>
<template>
<div class="base-count">
<button @click="handleSub">-</button>
<span>{{ count }}</span>
<button @click="handleAdd">+</button>
</div>
</template>
<script>
export default {
props: {
count: {
type: Number,
},
},
methods: {
handleSub() {
this.$emit('changeCount', this.count - 1)
},
handleAdd() {
this.$emit('changeCount', this.count + 1)
},
},
}
</script>
<style>
.base-count {
margin: 20px;
}
</style>
需求说明:
① 拆分基础组件
② 渲染待办任务
③ 添加任务
④ 删除任务
⑤ 底部合计 和 清空功能
⑥ 持久化存储
<template>
<!-- 主体区域 -->
<section id="app">
<TodoHeader @add="handleAdd"></TodoHeader>
<TodoBody :list="list" @del="handleDel"></TodoBody>
<TodoFoot :len="list.length" @clear="handleClear"></TodoFoot>
</section>
</template>
<script>
import TodoHeader from "@/components/TodoHeader";
import TodoBody from "@/components/TodoBody";
import TodoFoot from "@/components/TodoFoot";
// 渲染功能:
// 1.提供数据: 提供在公共的父组件 App.vue
// 2.通过父传子,将数据传递给TodoMain
// 3.利用 v-for渲染
// 添加功能:
// 1.手机表单数据 v-model
// 2.监听事件(回车+点击都要添加)
// 3.子传父,讲任务名称传递给父组件 App.vue
// 4.进行添加 unshift(自己的数据自己负责)
// 5.清空文本框输入的内容
// 6.对输入的空数据 进行判断
// 删除功能
// 1.监听事件(监听删除的点击) 携带id
// 2.子传父,讲删除的id传递给父组件的App.vue
// 3.进行删除filter(自己的数据 自己负责)
// 底部合计:父传子 传list.length 渲染
// 清空功能:子传父 通知父组件 → 父组件进行更新
// 持久化存储:watch深度监视list的变化 -> 往本地存储 ->进入页面优先读取本地数据
export default {
components:{
TodoHeader,
TodoBody,
TodoFoot
},
data () {
return {
//优先从本地存储读取
list: JSON.parse(localStorage.getItem('list')) || [
{id:1, name: "干饭"},
{id:2, name: "干饭"},
{id:3, name: "干饭"}
]
}
},
methods:{
handleAdd(newVal) {
//console.log(newVal)
this.list.unshift({
id: +new Date(),
name: newVal
}
)
},
handleDel(id) {
this.list=this.list.filter(item=> item.id!==id)
},
handleClear() {
this.list=[]
}
},
watch:{
list:{
deep: true,
handle(newValue) {
localStorage.setItem('list',JSON.stringify(newValue))
}
}
}
}
</script>
<style>
</style>
<template>
<!-- 输入框 -->
<header class="header">
<h1>小黑记事本</h1>
<input placeholder="请输入任务" class="new-todo" v-model="todoname" @keyup.enter="handleAdd"/>
<button class="add" @click="handleAdd">添加任务</button>
</header>
</template>
<script>
export default {
name: "TodoHeader",
data() {
return{
todoname: ''
}
},
methods:{
handleAdd() {
if(this.todoname.trim()===''){
alert("任务名称为空")
return
}
this.$emit("add",this.todoname)
this.todoname=''
}
}
}
</script>
<style scoped>
</style>
<template>
<!-- 列表区域 -->
<section class="main">
<ul v-for="(item,index) in list" :key="item.id" class="todo-list">
<li class="todo">
<div class="view">
<span class="index">{{index+1}}.</span> <label>{{item.name}}</label>
<button class="destroy" @click="handeleDel(item.id)"></button>
</div>
</li>
</ul>
</section>
</template>
<script>
export default {
name: "TodoBody",
props: {
list: {
type: Array
}
},
methods:{
handeleDel(id) {
this.$emit('del',id)
}
}
}
</script>
<style scoped>
</style>
<template>
<!-- 统计和清空 -->
<footer class="footer">
<!-- 统计 -->
<span class="todo-count">合 计:<strong> {{len}} </strong></span>
<!-- 清空 -->
<button class="clear-completed" @click="clear">
清空任务
</button>
</footer>
</template>
<script>
export default {
name: "TodoFoot",
props:{
len: Number
},
methods:{
clear() {
this.$emit('clear')
}
}
}
</script>
<style scoped>
</style>