无状态组件
没有管理任何状态,也没有监听任何传递给它的状态,也没有生命周期方法。实际上,它只是一个接受一些 prop 的函数。也可将组件标记为 functional,这意味它无状态 (没有响应式数据),也没有实例 (没有 this 上下文)
利用 v-model语法糖 实现无状态组件
v-model语法糖解析:
<input type="text" v-model="val">
||
<input type="text" :value="val" @input="val = $event.value">
add-book 组件(无状态组件)
- 注意修改默认语法糖使用: model { prop:'checked',event:'change'}
<template>
<div>
<input :value="val" @change="onInput" type="text" @keydown.enter="addBook">
<button @click="addBook">add book</button>
</div>
</template>
<script>
export default {
name: 'addBook',
props: ['val'],
model: {
prop: 'val', // 此处注意是 'prop'
event: 'change'
},
methods: {
onInput (e) {
this.$emit('change', e.target.value)
},
addBook () {
this.$emit('add-book')
}
}
}
</script>
book-list组件
<template>
<div>
<p v-if="this.list.length === 0">books is empty!</p>
<ul v-else>
<li :class="selBook === book.name?'active':''" v-for="book in list" :key="book.name" @click="selBook = book.name">{{ book.name }}¥{{ book.price }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'book-list',
props: {
list: {
type: Array,
default () {
return []
}
}
},
data () {
return {
selBook: ''
}
}
}
</script>
<style lang="scss" scoped>
li{
padding:5px 0;
}
.active{
background: #eee;
}
p{
padding: 40px 0;
}
</style>
index页面
<template>
<div>
<!-- title -->
<div class="title" :title="title">{{ title }}</div>
<!-- toolbar -->
<div>
<input type="text" v-model.number="price">
<button @click="patchPrice">change price</button>
</div>
<!-- add book 无状态组件-->
<add-book v-model="book" @add-book="addBook"></add-book>
<!-- 添加model: {
prop: 'val', // 此处注意是 'prop'
event: 'change'
}语法糖如下:
-->
<!-- <add-book :val="book" @change="book=$event" @add-book="addBook"></add-book> -->
<!-- 默认v-model 语法糖如下:-->
<!-- <add-book :value="book" @input="book=$event" @add-book="addBook"></add-book> -->
<!-- list -->
<book-list :list="list"></book-list>
<!-- total -->
<p>total: {{ total }}本</p>
</div>
</template>
<script>
import bookList from '@/views/ToDo/components/BookList.vue'
import addBook from '@/views/ToDo/components/AddBook.vue'
function getList () {
return new Promise((resolve) => {
setTimeout(() => {
resolve([{ name: 'bookA' }, { name: 'bookB' }])
}, 2000)
})
}
export default {
name: 'ToDo',
components: {
bookList,
addBook
},
data () {
return {
title: 'addBook',
list: [],
book: '',
price: 0,
}
},
computed: {
total () {
return this.list.length
}
},
async created () {
this.list = await getList()
this.patchPrice()
},
methods: {
addBook () {
this.list.push({ name: this.book })
this.book = ''
this.patchPrice()
},
patchPrice () {
this.list.forEach((iterm) => {
this.$set(iterm, 'price', this.price)
})
}
}
}
</script>
<style lang="scss" scoped>
.title{
margin: 50px auto;
}
li{
padding:5px 0;
}
.active{
background: #eee;
}
input{
height: 36px;
border: 1px solid #ddd;
}
button{
height: 36px;
}
p{
padding: 40px 0;
}
</style>
使用.async语法糖实现无状态组件
<comp :foo.sync="bar"></comp>
||
<comp :foo="bar" @update:foo="val => bar = val"></comp>
当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:
this.$emit('update:foo', newValue)