vue中利用 v-model语法糖 || .async语法糖实现无状态化组件

2,882 阅读1分钟

无状态组件

没有管理任何状态,也没有监听任何传递给它的状态,也没有生命周期方法。实际上,它只是一个接受一些 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)