1. ホーム
  2. Web プログラミング
  3. ジャバスクリプト
  4. javascriptのクラスライブラリ

親子コンポーネント通信を解決する3つのVueスロット

2022-01-13 16:41:14

プリアンブル

スロットはVueにとって非常に重要な部分だと思います。私が学習し実践している中では、コンポーネントとスロットを一緒に使うと、より効果的に機能します。また、より便利になることが多いです。

今日はVueのスロットのうち、デフォルトスロット、ネームドスロット、スコープドスロットの3種類を紹介します。

環境整備

最初にハッとするような初期環境を構築してみましょう。スロットを通して順を追って説明します。

は、これら3種類のデータをそれぞれレンダリングするカテゴリコンポーネントを書くことです。

カテゴリーコンポーネント

<template>
  <div class="category">
    <h1>{{title}}</h1>
    <ul>
      <li 
      v-for="(item,index) in listData"
      :key="index">{{item}}</li>
    </ul>
  </div>
</template>
<script>
export default {
  props: {
    listData:Array,
    title: String
  }
}
</script>
<style scoped>
.category{
  width: 200px;
  height: 300px;
  background-color:pink;
}
</style>

アプリコンポーネント

<template>
  <div id="app">
    <Category :listData="games" :title="'Games'" />
    <Category :listData="movies" :title="'Movies'" />
    <Category :listData="foods" :title="'Foods'" />
  </div>
</template>
<script>
import Category from '. /components/Category.vue'
export default {
  name: 'App',
  components: {
    Category
  },
  data () {
    return {
      games:['Crossfire','qq飞车','Rock Kingdom'],
      movies:['Hello, Lee Hwan Young','Youth Pie','Rush Hour'],
      foods:['Shaoyang Rice Noodles','Changsha Cha Yan','Chongqing Hot Pot']
    }
  }
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
  display: flex;
  justify-content: space-between;
}
</style>

最初は上記のような要件でしたが、現在はビジネス要件が変わり、映画は1本だけ宣伝して他は宣伝しない、料理は1本だけ宣伝するプルになっています。

次の図のようになります。

どうすれば合うように変更できるのか?

Categoryコンポーネントにifを追加して1つずつ判断したほうがいいのでしょうか?それとも、もっと良い方法があるのでしょうか?

一つ一つやっていては、コードが非常に複雑になって読みづらくなるし、後でビジネス要件を変更したいときにコードを移動するのも簡単ではありません。

次はデフォルトスロットです。

I. デフォルトのスロット

propsでデータを受け取り、子コンポーネントでレンダリングを行うのではなく、スロットを定義するのです。

<template>
<div class="category">
    <! -- Define slots, default content of slots -->
    <slot> If this default </slot> is displayed when the parent component does not pass a value over;
    </div>
</template>
<script>
    export default {
        props: {
        }
    }
</script>

アプリコンポーネントも変更

<template>
<div id="app">
    <Category>
        <h1>Games</h1>
        <! -- <ul>
<li v-for="(item, index) in games" :key="index">{{ item }}</li>
    </ul> -->
        <img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farticle% 2Fb352264fa7bfdb6d211f2e71e87cc2c48d85b805.jpg&refer=http%3A%2F%2Fi0.hdslb.com&app=2002&size=f9999,10000&q=a80& ;n=0&g=0n&fmt=jpeg?sec=1639931135&t=0b2c6c622c84a1e387196cce8f50455e">
    </Category>
    
    <Category>
        <h1>Movies</h1>
        <img class="movies" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0% 2F13236694597%2F641.jpg&refer=http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n& fmt=jpeg?sec=1639931502&t=f89c2197bda9bb129d9404d3c4b30f2f">
        <! -- <ul> -->
        <! -- <li v-for="(item, index) in movies" :key="index">{{ item }}</li> -->
        <! -- </ul> -->
    </Category>
    <Category>
        <h1>Foods</h1>
        <ul>
            <li v-for="(item, index) in foods" :key="index">{{ item }}</li>
    </ul>
    </Category>
    
    <! -- look at what is displayed when we write nothing -- >
    <Category>
    </Category>
    </div>
</template>
 
<script>
    import Category from '. /components/Category.vue'
 
    export default {
        name: 'App',
        components: {
            Category
        },
        data () {
            return {
                games:['Crossfire','qq飞车','Rock Kingdom'],
                movies:['Hello, Lee Hwan Young','Youth Pie','Rush Hour'],
                foods:['Shaoyang Rice Noodles','Changsha Cha Yan','Chongqing Hot Pot']
            }
        }
    }
</script>

表示効果。

説明します。

を書きました。 を表示するために、子コンポーネントにこのデフォルトの タグは、親コンポーネントが値を渡さない場合、ここでポジションを取ることと同じになります。

親コンポーネントに自閉とタグを書く代わりに、従来通り また、非自己閉鎖的なタグも記述します。 <カテゴリ 内容 . こうすることで、Vueはデフォルトでcomponentタグに書かれた内容をレンダリングし、子コンポーネントに戻します。 <スロット がその代わりとなる。

注:CSSスタイルは、親コンポーネント、子コンポーネントのいずれに記述してもかまいません。子コンポーネントに書くということは、子コンポーネントに戻したときにレンダリングされるということです。

ここに書いた後、お客さんは急に「あなたはとてもパワフルだ、満足できない」と感じて、全部を渡すようになったのです。

次は、再びネーミングスロットの登場です。

ネームドスロット

1つのスロットを使って考えるのもすごいですが、試しに2つのスロットを使って考えてみてはどうでしょうか。

サブコンポーネントの変更

<template>
  <div class="category">
    <! -- must add the name in the parent component to specify which slot to put it in, which is why it's called a named slot --- >
    <slot name="slot1"> If the parent component does not pass a value, this default </slot> is displayed;
    <slot name="slot2"></slot>
  </div>
</template>
<script>
export default {
  props: {
  }
}
</script>

親コンポーネント

<template>
	<div id="app">
    	<Category>
       	 <template slot="slot1">
          	  <h1>Games</h1>
            <img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farticle% 2Fb352264fa7bfdb6d211f2e71e87cc2c48d85b805.jpg&refer=http%3A%2F%2Fi0.hdslb.com&app=2002&size=f9999,10000&q=a80& ;n=0&g=0n&fmt=jpeg?sec=1639931135&t=0b2c6c622c84a1e387196cce8f50455e"
                 />
	</template>
	<template slot="slot2">
		<button > qq登录</button>
		<button > 微信登录</button>
	</template>
 
</Category>
<Category>
    <template slot="slot1">
		<h1>Movies</h1>
			<img
     class="movies"
     src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Finews.gtimg.com%2Fnewsapp_bt%2F0%2F13236694597%2F641.jpg&refer =http%3A%2F%2Finews.gtimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1639931502&t= f89c2197bda9bb129d9404d3c4b30f2f"
     />
    </template>
    <template slot="slot2">
		<button > Click to buy tickets </button>
    </template>
</Category>
 
<Category>
    <template slot="slot1">
		<h1>Foods</h1>
		<ul>
    		<li v-for="(item, index) in foods" :key="index">{{ item }}</li>
        </ul>
    </template>
</Category>
 
<! -- look at what is displayed when we write nothing -- >
<Category> </Category>
</div>
</template>
 
<script>
    import Category from '. /components/Category.vue'
 
    export default {
        name: 'App',
        components: {
            Category
        },
        data () {
            return {
                games:['Crossfire','qq飞车','Rock Kingdom'],
                movies:['Hello, Lee Hwan-young','Youth Pie','Rush

Explanation.

We can put more than one slot in the component, but when there are more than one, we have to name them, and also specify them in the parent component so that they don't not fit in.

III. Scope slots

The scope slots are slightly different from the previous ones in that the data is in the parent component, while the scope slots are where the data is in the child component, which in turn is passed to the parent component to define the structure for rendering.

The modified child component

<template>
  <div class="category">
    <slot name="slot1"> If this default </slot> is displayed when the parent component does not pass a value over;
    <slot name="slot2" :foods="foods"> If this default is displayed when the parent component is not passed over </slot>
  </div>
</template>
<script>
export default {
  data () {
    return{
      foods:['Shaoyang Rice Noodles','Changsha Cha Yan','Chongqing Hot Pot']
    }
  }
}
</script>

Parent component

<template>
  <div id="app">
    <Category>
      <template slot="slot1">
        <h1>Foods</h1>
      </template>
      <template slot="slot2" scope="listData">
        <! --if you don't know, we can output it and see what it is- {{listData}} -->
        <ul>
          <li v-for="(item, index) in listData.foods" :key="index">
            {{ item }}
          </li>
        </ul>
      </template>
    </Category>
    <Category>
      <template slot="slot1">
        <h1>Foods</h1>
      </template>
      <template slot="slot2" scope="listData">
        <ol>
          <li v-for="(item, index) in listData.foods" :key="index">
            {{ item }}
          </li>
        </ol>
      </template>
    </Category>
    <Category>
      <template slot="slot1">
        <h1>Foods</h1>
      </template>
      <template slot="slot2" scope="listData">
          <h4 v-for="(item, index) in listData.foods" :key="index">
            {{ item }}
          </h4>
      </template>
    </Category>
    <Category>
      <template slot="slot1" scope="listData">	
{{listData}}
      </template>
    </Category>
  </div>
</template>
 
<script>
import Category from '. /components/Category.vue'
 
export default {
  name: 'App',
  components: {
    Category
  }
}
</script>

rendering

I didn't think of any scenarios for this kind of use during my study and practice, but there are cases on the official website, so I think it must have a reason to exist, but my knowledge is too small to take advantage of it.

Explanation.

The child component passes a value to the parent component via :variable name="defined data" and the parent component receives it with