JSFiddle - React, Tailwind, and code Playground

by kurotanshi

HTML

<script src="https://unpkg.com/[email protected]/dist/vue.global.js"></script>
  <div id="app">

    <ul v-for="(book, idx) in books" class="book" :key="book.id">
      <li>{{ book.name }}</li>
      <li>{{ book.author }}</li>
      <li>{{ book.publishedAt }}</li>
    </ul>

    <hr>

    <!-- 直接將 v-for 的 book 物件作為 props 傳遞 -->
    <!-- 並監聽自訂的 update 事件 -->
    <my-component
      v-for="(book, idx) in books"
      :key="idx"      
      v-bind="book"
      @update="updateInfo"      
    ></my-component>
    
  </div>

SCSS

#app {
  display: block;
  padding: 1rem;
  padding-top: 2rem;
  font-size: 1rem;
}

.book {
  margin-bottom: 2rem;
}

.child-app {
  padding: 1rem;
  background-color: #ddd;
  margin-top: 1rem;
  line-height: 2;
}

li {
  list-style-type: square;
  list-style-position: inside;
}

input {
  width: 65%;
  font-size: 0.9rem;
  padding: 2px 3px;
}

JavaScript

const app = Vue.createApp({
  data() {
    return {
      books: [{
          id: '0001',
          name: '0 陷阱!0 誤解!8 天重新認識 JavaScript!',
          author: 'Kuro Hsu',
          publishedAt: '2019/09'
        },
        {
          id: '0002',
          name: '重新認識 Vue.js',
          author: 'Kuro Hsu',
          publishedAt: '2021/02'
        },
      ]
    }
  },
  methods: {
    updateInfo(val) {
      // 註:如果是 Vue 2.x 要透過 this.$set 來更新
      // 如: this.$set(this.books, idx, val);

      // Vue 3.x 則無此限制
      const idx = this.books.findIndex(d => d.id === val.id);
      this.books[idx] = val;
    }
  }
});

app.component('my-component', {
  template: `
    <div class="child-app">
      <div>書名: <input type="text" v-model="bookInfo.name"></div>
      <div>作者: <input type="text" v-model="bookInfo.author"></div>
      <div>出版日: <input type="text" v-model="bookInfo.publishedAt"></div>
    </div>`,
  props: ['id', 'name', 'author', 'publishedAt'],
  data() {
    return {
      bookInfo: {
        id: this.id,
        name: this.name,
        author: this.author,
        publishedAt: this.publishedAt
      }
    };
  },
  watch: {
    bookInfo: {
      // 注意! 由於 bookInfo 物件必須加上 deep: true 
      // 才能做物件的深層更新偵測 
      deep: true,
      handler(val) {
        this.$emit('update', val);
      },
    },
  }
});

app.mount('#app');