Vue - コンポーネント開発

 目次

1. コンポーネントの基本的な使い方

1.1 コンポーネントコンストラクターオブジェクトを作成する

1.2 コンポーネントの登録

1.3 コンポーネントの使用

2. グローバルコンポーネントとローカルコンポーネント

2.1 グローバルコンポーネント

2.2 部分的なコンポーネント

3. 親コンポーネントと子コンポーネントの違い

4. コンポーネントを登録するための糖衣構文

5. コンポーネントテンプレートの書き分け

5.1 スクリプトタグ

5.2 テンプレートタグ

6. コンポーネントデータ

6.1 ストレージの問題

6.2 コンポーネントのデータはなぜ関数でなければならないのか

7. 親コンポーネントはデータを子コンポーネントに渡します

7.1 props 属性を使用して、親コンポーネントは子コンポーネントにデータを渡します

7.2 props 属性の使用

8. コンポーネント通信

8.1 父から息子への受け継ぎ(小道具のザトウクジラの識別)

8.2 息子から父親への $emit

8.3 親子コンポーネント通信の場合

9. 親から子へのアクセス (children-ref)


1. コンポーネントの基本的な使い方

簡単なコンポーネントの例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<div id="app">
  <!-- 3.使用组件 -->
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <my-cpn></my-cpn>
  <cpnc></cpnc>
</div>
<script src="../js/vue.js"></script>
<script>
  // 1.创建组件构造器对象
  const cpnc = Vue.extend({
    template:`
        <div>
          <h2>标题</h2>
          <p>内容1...<p>
          <p>内容2...<p>
        </div>`
  })
  // 2.全局注册组件
  Vue.component('my-cpn', cpnc)
  const app = new Vue({
    el:"#app",
    data:{
    },
    components:{
      //局部组件创建
      cpnc:cpnc
    }
  })
</script>
</body>
</html>

コンポーネントは、名前が付けられた再利用可能な Vue インスタンスです。この場合は my-cpnnew Vue このコンポーネントは、次のようにして作成された Vue ルート インスタンスのカスタム要素として使用 できます <my-cpn></my-cpn>

1.1 コンポーネントコンストラクターオブジェクトを作成する

templateここで、 はコンポーネントの DOM 要素の内容です。

1.2 コンポーネントの登録

  1. グローバル登録、合格しました Vue.component 
  2. 部分的な登録、合格しました components:{cpnc:cpnc}

1.3 コンポーネントの使用

HTMLタグと同様に使用します。

  <div id="app">
    <!-- 3.使用组件 -->
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
    <my-cpn></my-cpn>
    <cpnc></cpnc>
  </div>

2. グローバルコンポーネントとローカルコンポーネント

コンポーネントを登録するには 2 つの方法があります。1 つはグローバル コンポーネント、もう 1 つはローカル コンポーネントです。

  <div id="app">
    <h2>全局组件</h2>
    <my-cpn></my-cpn>
    <h2>局部组件</h2>
    <cpnc></cpnc>
  </div>
  <script src="../js/vue.js"></script>
  <script>
    // 1.创建组件构造器对象
    const cpnc = Vue.extend({
      template:`
        <div>
          <h2>标题</h2>
          <p>内容1</p>
          <p>内容2</p>
        </div>`
    })
    // 2.注册组件(全局组件,可以在多个vue实例中使用)
    Vue.component('my-cpn', cpnc)

    const app = new Vue({
      el:"#app",
      components:{//局部组件创建
        cpnc:cpnc
      }
    })
  </script>

2.1 グローバルコンポーネント

複数の vue インスタンスで使用できるグローバル コンポーネントは、グローバル変数に似ています。

Vue.component('my-cpn', cpnc)メソッドを使用して登録し、直接呼び出します<my-cpn></my-cpn>my-cpnグローバルコンポーネントの名前であり、cpnc定義されたコンポーネントオブジェクトです。

2.2 部分的なコンポーネント

ローカル コンポーネントは、ローカル変数と同様に、ブロック レベルのスコープで、現在の vue インスタンスによってマウントされたオブジェクト内でのみ使用できます。

登録方法

    const app = new Vue({
      el:"#app",
      components:{//局部组件创建
        cpnc:cpnc
      }
    })

使い方はグローバル変数と同じで、直接<cpnc></cpnc>呼び出して使用します。cpnc:cpnc最初の cpnc はコンポーネントに付けられた名前で、2 番目は定義されたコンポーネント オブジェクトです。2 つの名前が同じ場合は、es6 構文を直接使用することもできます。

components:{//局部组件创建
        cpnc
}

3. 親コンポーネントと子コンポーネントの違い

  <div id="app">
    <cpn2></cpn2>
  </div>
  <script src="../js/vue.js"></script>
  <script>
    // 1.创建组件构造器对象
    const cpn1 = Vue.extend({
      template:`
        <div>
          <h2>标题1</h2>
          <p>组件1</p>
        </div>`
    })
    // 组件2中使用组件1
    const cpn2 = Vue.extend({
      template:`
        <div>
          <h2>标题2</h2>
          <p>组件2</p>
          <cpn1></cpn1>
        </div>`,
      components:{
        cpn1:cpn1
      }
    })

    const app = new Vue({
      el:"#app",
      components:{//局部组件创建
        cpn2:cpn2
      }
    })
  </script>

上記のコードでは、2 つのコンポーネント オブジェクトが定義され、cpn1コンポーネントcpn2cpn2のローカル コンポーネントを使用して登録されcpn1template登録されたものはコンポーネント内で使用cpn1され、ローカル コンポーネントは vue インスタンスに登録されcpn2、によってマウントされた div で呼び出されます。 vue インスタンスcpn2コンポーネントの親子関係を形成します。cpn2cpn1

注: コンポーネントは vue インスタンスであり、データ、メソッド、計算など、vue インスタンスの属性もコンポーネントに含めることができます。

4. コンポーネントを登録するための糖衣構文

 <div id="app">
    <cpn1></cpn1>
    <cpn2></cpn2>
  </div>
  <script src="../js/vue.js"></script>
  <script>
    // 1.注册全局组件语法糖
    Vue.component('cpn1', {
      template:`
        <div>
          <h2>全局组件语法糖</h2>
          <p>全局组件语法糖</p>
        </div>`
    })

    const app = new Vue({
      el:"#app",
      components:{//局部组件创建
        cpn2:{
          template:`
        <div>
          <h2>局部组件语法糖</h2>
          <p>局部组件语法糖</p>
        </div>`
        }
      }
    })
  </script>

コンポーネントを登録する場合、コンポーネント オブジェクトをインスタンス化する必要はありませんが、登録時に直接インスタンス化します。{}コンポーネントオブジェクトです。

5. コンポーネントテンプレートの書き分け

5.1 スクリプトタグ

タグを使用してscriptコンポーネントのテンプレートを定義します。scriptタグのアテンション タイプは ですtext/x-template

  <!-- 1.script标签注意类型是text/x-template -->
  <script type="text/x-template" id="cpn1">
    <div>
        <h2>组件模板的分离写法</h2>
        <p>script标签注意类型是text/x-template</p>
      </div>
  </script>

5.2 テンプレートタグ

タグを使用してtemplate、タグ内にコンテンツを書き込みます。

  <!-- 2.template标签 -->
  <template id="cpn2">
    <div>
      <h2>组件模板的分离写法</h2>
      <p>template标签</p>
    </div>
  </template>

切り離されたテンプレートを呼び出すには、次を使用します。template:'#cpn1'

  <script src="../js/vue.js"></script>
  <script>

    const app = new Vue({
      el: "#app",
      components: { //局部组件创建
        cpn1:{
          template:'#cpn1'
        },
        cpn2: {
          template: '#cpn2'
        }
      }
    })
  </script>

6. コンポーネントデータ

6.1 ストレージの問題

前述したように、vue コンポーネントは vue インスタンスであり、対応する vue コンポーネントにはdataデータを保存するための属性もあります。

  <div id="app">
    <cpn1></cpn1>
  </div>

  <script src="../js/vue.js"></script>
  <script>

    const app = new Vue({
      el: "#app",
      components: { //局部组件创建
        cpn1:{
          template:'<div>{
   
   {msg}}</div>',
          data(){
            return {
              msg:"组件的数据存放必须要是一个函数"
            }
          }
        }
      }
    })
  </script>

templateコンポーネント内のデータを使用しますmsg

6.2 コンポーネントのデータはなぜ関数でなければならないのか

コンポーネントの考え方は再利用であり、コンポーネントを定義するということは、当然のことながら、共通の公共のものを抽出して再利用することです。

<div id="app">
    <h2>data不使用函数</h2>
    <cpn1></cpn1>
    <cpn1></cpn1>
    <hr>
    <h2>data使用函数</h2>
    <cpn2></cpn2>
    <cpn2></cpn2>
    <hr>
  </div>
  <script src="../js/vue.js"></script>
  <template id="cpn1">
    <div>
      <button @click="count--">-</button>
      当前计数:{
   
   {count}}
      <button @click="count++">+</button>
    </div>
  </template>
  <template id="cpn2">
    <div>
      <button @click="count--">-</button>
      当前计数:{
   
   {count}}
      <button @click="count++">+</button>
    </div>
  </template>
  <script>
    const obj = {
      count:0
    };
    const app = new Vue({
      el: "#app",
      components: { //局部组件创建
        cpn1: {
          template: '#cpn1',
          data() {
            return obj;
          }
        },
        cpn2: {
          template: '#cpn2',
          data() {
            return {
              count: 0
            }
          }
        }
      }
    })
  </script>

上記のコードでは2つのコンポーネントcpn1cpn22つのカウンタが定義されており、con1データは関数を使用していますが、シミュレーションするためにカウントを返すためにdata:{count:0}定数を使用しています。obj

図からわかるように、関数を使用しないものは同じ属性dataを共有しているように見えますcountが、関数を使用するものはdataローカル変数のようなブロックレベルのスコープを持つ独自のカウントを使用し、このブロックレベルが Vue のスコープになります。コンポーネント。

コンポーネントを再利用する場合は、各コンポーネントが独自の変数を使用することを強く望みますが、どうしても同じ変数を使用する必要がある場合は、コンポーネントをグローバルに登録するか、状態管理に vuex を使用します。

7. 親コンポーネントはデータを子コンポーネントに渡します

7.1props属性を使用して、親コンポーネントが子コンポーネントにデータを渡す

propsコンポーネントのプロパティの使用

const cpn = {
  template: "#cpn",
  props: { 
          cmessage: {
          type: String,
          default: 'zzzzz',
          required: true //在使用组件必传值
          }
  }
}

cmessage オブジェクトに値を渡す

<div id="app">
    <cpn :cMessage="message"></cpn>
</div>
<script>    
const app = new Vue({
      el: "#app",
      data: {
        message: "你好",
        movies: ["复仇者联盟", "钢铁侠", "星际穿越", "哪吒传奇"]
      },
      components: {
        cpn
      }
    })
  </script>

7.2 props 属性の使用

配列の書き込み

props: ['cmovies', 'cmessage']

オブジェクトの書き込み

  props: { 
          cmessage: {
          type: String,
          default: 'zzzzz',
          required: true //在使用组件必传值
          }
  }

props 属性の型制限

//1.类型限制(多个类使用数组)
cmovies:Array,//限制为数组类型
cmessage:String,//限制为Strin类型
cmessage:['String','Number']//限制为String或Number类型

props 属性のデフォルト値

// 2.提供一些默认值,以及必传值
        cmessage: {
          type: String,
          default: 'zzzzz',//默认值
        }

props 属性の必須値

cmessage: {
          type: String,
          default: 'zzzzz',
          required: true //在使用组件必传值
        }

タイプはオブジェクト/配列で、デフォルト値は関数である必要があります。

// 型は Object/Array で、デフォルト値は関数である必要があります
cmovies: {
	type: Array,
	default () {
		return [1, 2, 3, 4]
	}
},

カスタム検証関数

vaildator: function (value) {
	//这个传递的值必须匹配下列字符串中的一个
	return ['zzzzz', 'ttttt', 'yyy'].indexOf(value) !== -1
}

カスタムタイプ

  function Person(firstName,lastName) {
      this.firstName = firstName
      this.lastName = lastName
    }
	cmessage:Person//限定了cmeessage必须是Person类型

総合利用

<div id="app">
    <cpn :cMovies="movies" :cMessage="message"></cpn>
  </div>
  <template id="cpn">
    <div>
      <ul>
        <li v-for="(item, index) in cmovies" :key="index">{
   
   {item}}</li>
      </ul>
      <h2>{
   
   {cmessage}}</h2>
    </div>
  </template>
  <script src="../js/vue.js"></script>

  <script>
    function Person(firstName,lastName) {
      this.firstName = firstName
      this.lastName = lastName
    }
    // 父传子:props
    const cpn = {
      template: "#cpn",
      // props: ['cmovies', 'cmessage'],//数组写法
      props: { //对象写法
        // 1.类型限制(多个类使用数组)
        // cmovies:Array,
        // cmessage:String,
        // cmessage:['String','Number'],
        // 2.提供一些默认值,以及必传值
        cmessage: {
          type: String,
          default: 'zzzzz',
          required: true //在使用组件必传值
        },
        //类型是Object/Array,默认值必须是一个函数
        cmovies: {
          type: Array,
          default () {
            return [1, 2, 3, 4]
          }
        },
        // 3.自定义验证函数
        // vaildator: function (value) {
        //   //这个传递的值必须匹配下列字符串中的一个
        //   return ['zzzzz', 'ttttt', 'yyy'].indexOf(value) !== -1
        // }
        // 4.自定义类型
        // cmessage:Person,
      },
      data() {
        return {
        }
      },
      methods: {

      },
    };
    const app = new Vue({
      el: "#app",
      data: {
        message: "你好",
        movies: ["复仇者联盟", "钢铁侠", "星际穿越", "哪吒传奇"]
      },
      components: {
        cpn
      }
    })
  </script>

8. コンポーネント通信

8.1 父から息子への受け継ぎ(小道具のザトウクジラの識別)

v-bind はキャメルケースの使用をサポートしていないため、たとえば、cUserに変更する必要がありますc-User

  <div id="app">
    <!-- v-bind不支持驼峰 :cUser改成 :c-User-->
    <!-- <cpn :cUser="user"></cpn> -->
    <cpn :c-User="user"></cpn>
    <cpn :cuser="user" ></cpn>
  </div>
  <template id="cpn">
    <div>
      <!-- 使用驼峰 -->
      <h2>{
   
   {cUser}}</h2>
      <!-- 不使用 -->
      <h2>{
   
   {cuser}}</h2>
    </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>
    // 父传子:props
    const cpn = {
      template: "#cpn",
      props: { //对象写法
        //驼峰
        cUser:Object,
        //未使用驼峰
        cuser:Object
      },
      data() {return {}},
      methods: {},
    };
    const app = new Vue({
      el: "#app",
      data: {
        user:{
          name:'zzz',
          age:18,
          height:175
        }
      },
      components: {
        cpn
      }
    })
  </script>

props は参照型を受け取ります

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>

	</head>
	<body>
		<div id="app">
			<!-- <cpn1 :msg="message"></cpn1> -->
			<!-- <cpn1 :msg="message2"></cpn1> -->
			<cpn1 :msgab="add"></cpn1>
			<h2>{
   
   {count}}</h2>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				data: {
					/* message: ['蔡英文', '吴钊燮'] */
					/* message2:{
						name:'蔡英文',
						age:56,
						sex:'女'
					} */
					count:0
				},
				methods: {
                    add:function(){
						return this.count++
					}
				},
				computed: {

				},
				components: {
					cpn1: {
						/* template: `
						  <div>我是中国人{
   
   {msg.name}}{
   
   {msg.sex}}</div>
						`, */
						template: `
						<div>
						  <div @click="sum">+</div>
						
						</div>
						`,
						props: {
							/* msg:{
								type: Array
							} */
							/* msg:{
								type: Object
							} */
							msgab:{
								type:Function
							},
							
						},
						methods:{
							sum(){
								this.msgab()
							}
						}
						
						
					}
				}
			})
		</script>
	</body>
</html>

8.2 子传父$emit

子コンポーネントは、カスタム イベントを使用して、親コンポーネントに値を渡します$emit

 <!-- 父组件 -->
  <div id="app">
    <!-- 不写参数默认传递btnClick的item -->
    <cpn @itemclick="cpnClcik"></cpn>

  </div>

  <!-- 子组件 -->
  <template id="cpn">

    <div>
      <button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">{
   
   {item.name}}</button>
    </div>
  </template>

  <script src="../js/vue.js"></script>

  <script>
    const cpn = {
      template: "#cpn",
      data() {
        return {
          categoties: [{
              id: 'aaa',
              name: '热门推荐'
            },
            {
              id: 'bbb',
              name: '手机数码'
            },
            {
              id: 'ccc',
              name: '家用家电'
            },
            {
              id: 'ddd',
              name: '电脑办公'
            },
          ]
        }
      },
      methods: {
        btnClick(item) {
          this.$emit('itemclick', item)
        }
      },
    };
    const app = new Vue({
      el: "#app",
      data() {
        return {

        }
      },
      methods: {
        cpnClcik(item) {
          console.log('cpnClick'+item.name);
        }
      },
      components: {
        cpn
      },
    })
  </script>

1. サブコンポーネントでメソッドを定義しますbtnClick(item)$emit「itemclick」はイベント名であり、item渡される値です。

methods: {
        btnClick(item) {
          this.$emit('itemclick', item)
        }
      },

2. 子コンポーネントでクリック イベントをリッスンし、このメソッドをコールバックします。

  <div>
      <button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">{
   
   {item.name}}</button>
   </div>

3. 親コンポーネントでメソッド cpnClcik(item) を定義します

methods: {
	cpnClcik(item) {
		console.log('cpnClick'+item.name);
	}
},

4. そして親コンポーネント(vueインスタンス)で呼び出し<cpn @itemclick="cpnClcik"></cpn>(パラメータを書かずにbtnClickの項目がデフォルトで渡されます )、親コンポーネントはitemclick子コンポーネントからイベント名で渡されたイベントをリッスンします。

<cpn @itemclick="cpnClcik"></cpn>


ネイティブのクリック イベントをリッスンする

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<script type="text/javascript" src="./vue.js"></script>
</head>
<body>
	<div id="app">
    <cpn @click.native="btnClick">点击</cpn>
  </div>
  <!-- 子组件 -->
  <template id="cpn">
    <div>
      我是子组件
    </div>
  </template>
</body>
<script type="text/javascript">
   // 父传子:props
    const cpn = {
      template: "#cpn",
      data() {
        return {
          name:"我是子组件的name"
        }
      }
     
    };
    const app = new Vue({
      el: "#app",
      data() {
        return {
          message:"hello"
        }
      },
       methods: {
        btnClick(){
          
          console.log('click')
        }
      },
      components: {
        cpn
      },
    })
</script>
</html>

8.3 親子コンポーネント通信の場合

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>组件通信-父子通信案例</title>
</head>

<body>
<!-- 父组件 -->
<div id="app">

  <cpn :number1='num1' :number2='num2'></cpn>

</div>

<!-- 子组件 -->
<template id="cpn">

  <div>
    <h2>number1:{
   
   {number1}}</h2>
    <input type="text" v-model="number1">
    <h2>number2:{
   
   {number2}}</h2>
    <input type="text" v-model="number2">
  </div>
</template>
 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
  // 父传子:props
  const cpn = {
    template: "#cpn",
    data() {
      return {
      }
    },
    props:{
      number1:[Number,String],
      number2:[Number,String],
    },
  };
  const app = new Vue({
    el: "#app",
    data: {
      num1:1,
      num2:2
    },
    components: {
      cpn
    },
  })
</script>
</body>

</html>

上記のエラーは props の値を直接変更することはできません。次のように変更できます。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>组件通信-父子通信案例</title>
</head>

<body>
<!-- 父组件 -->
<div id="app">

  <cpn :number1='num1' :number2='num2'></cpn>

</div>

<!-- 子组件 -->
<template id="cpn">

  <div>
    <h2>number1:{
   
   {number1}}</h2>
    <h2>number1:{
   
   {dnumber1}}</h2>
    <input type="text" v-model="dnumber1">
    <h2>number2:{
   
   {number2}}</h2>
    <h2>number2:{
   
   {dnumber2}}</h2>
    <input type="text" v-model="dnumber2">
  </div>
</template>
 <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
  // 父传子:props
  const cpn = {
    template: "#cpn",
    data() {
      return {
        dnumber1:this.number1,
        dnumber2:this.number2
      }
    },
    props:{
      number1:[Number,String],
      number2:[Number,String],
    },
  };
  const app = new Vue({
    el: "#app",
    data: {
      num1:1,
      num2:2
    },
    components: {
      cpn
    },
  })
</script>
</body>

</html>

親子コンポーネントの双方向バインディングの価値を実現します。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>组件通信-父子通信案例</title>
</head>

<body>
<!-- 父组件 -->
<div id="app">

  <h2>子组件</h2>
  <cpn :number1='num1' :number2='num2'
       @num1change="num1Change"
       @num2change="num2Change"></cpn>
  <h2>--------------</h2>

  <h2>父组件{
   
   {num1}}</h2>
  <input type="text" v-model="num1" >
  <h2>父组件{
   
   {num2}}</h2>
  <input type="text" v-model="num2">

</div>

<!-- 子组件 -->
<template id="cpn">

  <div>
    <h2>number1:{
   
   {number1}}</h2>
    <h2>dnumber1:{
   
   {dnumber1}}</h2>
    <input type="text" :value="dnumber1" @input="num1input">
    <h2>number2:{
   
   {number2}}</h2>
    <h2>dnumber2:{
   
   {dnumber2}}</h2>
    <input type="text" :value="dnumber2" @input="num2input">
  </div>
</template>

<script src="../js/vue.js"></script>

<script>
  // 父传子:props
  const cpn = {
    template: "#cpn",
    data() {
      return {
        dnumber1:this.number1,
        dnumber2:this.number2
      }
    },
    props:{
      number1:[Number,String],
      number2:[Number,String],
    },
    methods: {
      num1input(event){
        this.dnumber1 = event.target.value
        this.$emit('num1change',this.dnumber1)
      },
      num2input(event){
        this.dnumber2 = event.target.value
        this.$emit('num2change',this.dnumber2)
      }
    },
  };
  const app = new Vue({
    el: "#app",
    data: {
      num1:1,
      num2:2
    },
    methods: {
      num1Change(value){
        this.num1=value
      },
      num2Change(value){
        this.num1=value
      }
    },
    components: {
      cpn
    },
  })
</script>
</body>

</html>

達成するには時計を使用してください。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>组件通信-父子通信案例(watch实现)</title>
</head>

<body>
  <!-- 父组件 -->
  <div id="app">

    <cpn :number1='num1' :number2='num2' @num1change="num1Change" @num2change="num2Change"></cpn>

    <h2>父组件{
   
   {num1}}</h2>
    <input type="text" v-model="num1" >
    <h2>父组件{
   
   {num2}}</h2>
    <input type="text" v-model="num2">

  </div>

  <!-- 子组件 -->
  <template id="cpn">

    <div>
      <h2>{
   
   {number1}}</h2>
      <input type="text" v-model="dnumber1">
      <h2>{
   
   {number2}}</h2>
      <input type="text" v-model="dnumber2">
    </div>
  </template>

  <script src="../js/vue.js"></script>

  <script>
    // 父传子:props
    const cpn = {
      template: "#cpn",
      data() {
        return {
          dnumber1:this.number1,
          dnumber2:this.number2
        }
      },
      props:{
        number1:[Number,String],
        number2:[Number,String],
      },
      watch: {
        dnumber1(newValue){
          this.dnumber1 = newValue
          this.$emit('num1change',newValue)
        },
        dnumber2(newValue){
          this.dnumber1 = newValue
          this.$emit('num2change',newValue)
        }
      },
    };
    const app = new Vue({
      el: "#app",
      data() {
        return {
          num1:1,
          num2:2,
        }
      },
      methods: {
        num1Change(value){
          this.num1=value*10
        },
        num2Change(value){
          this.num1=value*100
        }
      },
      components: {
        cpn
      },
    })
  </script>
</body>

</html>
ようやく気づいた
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>

	</head>
	<body>
		<div id="app">
			<h2>子组件</h2>
			<cpn :number1="num1" :number2="num2" @num1change="Num1change" @num2change="Num2change"></cpn>
			<h2>--------------</h2>

			<h2>父组件{
   
   {num1}}</h2>
			<input type="text" v-model="num1">
			<h2>父组件{
   
   {num2}}</h2>
			<input type="text" v-model="num2">
		</div>
		<template id="cpn">
			<div>
				<h2>dnumber1:{
   
   {dnumber1}}</h2>
				<h2>number1:{
   
   {number1}}</h2>
				<input type="text" v-model="dnumber1"/>
				<br />
				<h2>dnumber2:{
   
   {dnumber2}}</h2>
				<h2>number2:{
   
   {number2}}</h2>
				<input type="text" v-model="dnumber2"/>
			</div>
		</template>
		<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
		<script>
			/* 子组件 */
			const cpn = {
				template: '#cpn',
				data() {
					return {
						dnumber1: this.number1,
						dnumber2: this.number2
					}
				},
				props: {
					number1: {
						type: [Number,String]
					},
					number2: {
						type:[Number,String]
					}
				},
				watch:{
					dnumber1(n){
						this.$emit('num1change', n/100)
					},
					dnumber2(n){
						
						this.$emit('num2change', n*100)
					},
					number1(n){
						this.dnumber1 = n*100
					},
					number2(n){
						this.dnumber2 = n/100
					}
				}
			}

			/* 父组件 */
			const app = new Vue({
				el: "#app",
				data() {
					return {
						num1: 1,
						num2: 2
					}
				},
				methods: {
					Num1change(value) {
						this.num1 = value
					},
					Num2change(value) {
						this.num2 = value
					}
				},
				computed: {

				},
				components: {
					cpn
				}
			})
		</script>
	</body>
</html>

9. 親から子へのアクセス (children-ref)

親コンポーネントが子コンポーネントにアクセスする場合、子コンポーネントのメソッドまたはプロパティを直接操作する必要がある場合があります。この場合、$childrenと が必要です$ref

  <!-- 父组件 -->
  <div id="app">
    <cpn></cpn>
    <cpn></cpn>
    <cpn ref="aaa"></cpn>
    <button @click="btnClick" >按钮</button>
  </div>
  <!-- 子组件 -->
  <template id="cpn">
    <div>
      我是子组件
    </div>
  </template>
  <script src="../js/vue.js"></script>
  <script>
    // 父传子:props
    const cpn = {
      template: "#cpn",
      data() {
        return {
          name:"我是子组件的name"
        }
      },
      methods: {
        showMessage(){
          console.log("showMessage");
        }
      },
    };
    const app = new Vue({
      el: "#app",
      data() {
        return {
          message:"hello"
        }
      },
      methods: {
        btnClick(){
          // 1.children
          // console.log(this.$children[0].showMessage)
          // for (let cpn of this.$children) {
          //   console.log(cpn.showMessage)
          // }
          // 2.$ref
          console.log(this.$refs.aaa.name)
        }
      },
      components: {
        cpn
      },
    })
  </script>

$children方法

// 1.children
console.log(this.$children[0].showMessage)
for (let cpn of this.$children) {
    console.log(cpn.showMessage)
}

**現在のインスタンスを直接取得する直接サブコンポーネントを使用する場合、 順序は保証されず、応答性もないことthis.$childrenに注意してください 。$children** を使用してデータバインドしようとしている場合は $children 、配列を使用して v-for 子コンポーネントを生成し、配列を実際のソースとして使用することを検討してください。

$refs メソッド: ref は、要素またはサブコンポーネントの参照情報を登録するために使用されます。参照情報は親コンポーネントの$refsオブジェクトに登録されます。通常の DOM 要素で使用される場合、参照は DOM 要素を指します。子コンポーネントで使用される場合、参照はコンポーネント インスタンスを指します。

ref の基本的な使用法は要素に対して使用されます
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>

	</head>
	<body>
		<div id="app">
          <p ref="p" @click="handelClick" id="ppp">hello</p>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
		<script>
			const app = new Vue({
				el: "#app",
				data: {
					
				},
				methods: {
                 handelClick(){
					console.log(this.$refs.p);
					 const ppp = document.querySelector('#ppp')
					 console.log(ppp);
				 }
				},
				computed:{
					
				}
			})
		</script>
	</body>
</html>

最初にサブコンポーネントを定義する

<cpn ref="aaa"></cpn>

直接電話する

サブコンポーネントでの ref の使用
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>

	</head>
	<body>
		<div id="app">
           <counter ref="one" @change="handelChange"></counter>
		   <counter ref="two" @change="handelChange"></counter>
		   <div>total:{
   
   {total}}</div>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
		<script>
			Vue.component('counter',{
				template:'<div @click="handelclick">{
   
   {number}}</div>',
				data(){
					return {
						number:0
					}
				},
				methods:{
					handelclick(){
						this.number++;
						this.$emit('change');
					}
				}
			})
			const app = new Vue({
				el: "#app",
				data: {
					total:0
				},
				methods: {
                 handelChange(){
					 this.total = this.$refs.one.number + this.$refs.two.number
				 }
				},
				computed:{
					
				}
			})
		</script>
	</body>
</html>
<!-- ref可以调用组件中的数据 -->
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>

	</head>
	<body>
		<div id="app">
              <helloworld ref="hello"></helloworld>
              <button @click="getHello">获取helloworld组件中的值</button>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
		<script>
			Vue.component('helloworld',{
				template:'<div></div>',
				data(){
					return {
						number:0
					}
				},
				methods:{
					handelclick(){
						console.log('被调用了');
					}
				}
			})
			const app = new Vue({
				el: "#app",
				data: {
					
				},
				methods: {
                  getHello(){
					   this.$refs.hello.handelclick();
			                   console.log(this.$refs.hello.number);
					   console.log(this.$refs.hello.$el.innerHTML);
				  }
				},
				computed:{
					
				}
			})
		</script>
	</body>
</html>
<!-- ref可以调用组件中的方法 -->

これは動的コンポーネント用であり、DOM 内のテンプレートの制約に基づいて動作します。

DOM 内のテンプレートの制約に基づいて動作します。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>

	</head>
	<body>
		<div id="app">
          <table>
			  <tr is="row">
			  </tr> 
		  </table>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
		<script>
			Vue.component('row',{
				template:'<tr><td>111</td></tr>'
			})
			const app = new Vue({
				el: "#app",
				data() {
					return {}
				},
				methods: {
                 
				},
				computed:{
					
				}
			})
		</script>
	</body>
</html>

動的コンポーネント コンポーネント

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<div id="app">
			<!-- <child-one></child-one>
			<child-two></child-two> -->
			<component :is="type"></component>
			<button @click="handerClick">点击</button>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		 <script>
			 Vue.component('child-one',{
				 template:'<div>child-one</div>'
			 })
			 Vue.component('child-two',{
			 	template:'<div>child-two</div>'
			 })
			const app = new Vue({
				el:'#app',
				data(){
					return {
						type:'child-one'
					}
				},
				methods:{
					handerClick(){
						console.log('111');
						this.type=this.type==='child-one'?'child-two':'child-one';
					}
					
				}
			}) 
			 
		 </script>
	</body>
</html>
こちらは公式サイトのダイナミックコンポーネントの事例です
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style>
		.tab-button {
		        padding: 6px 10px;
		        border-top-left-radius: 3px;
		        border-top-right-radius: 3px;
		        border: 1px solid #ccc;
		        cursor: pointer;
		        background: #f0f0f0;
		        margin-bottom: -1px;
		        margin-right: -1px;
		      }
		      .tab-button:hover {
		        background: #e0e0e0;
		      }
		      .tab-button.active {
		        background: #e0e0e0;
		      }
		      .tab {
		        border: 1px solid #ccc;
		        padding: 10px;
		      }
		</style>
	</head>
	<body>
		<div id="app">
			<button v-for="(tab,index) in tabs":key="index" @click="handelclick(tab)" :class="getStyle(tab)">{
   
   {tab}}</button>
			<component :is="currentTabComponent"></component>
		</div>
		<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
		 <script>
			Vue.component('tab-home',{
				template:'<div>child-one</div>'
			})
			Vue.component('tab-posts',{
				template:'<div>child-two</div>'
			})
			Vue.component('tab-archive',{
				template:'<div>child-three</div>'
			})
			const app = new Vue({
				el:'#app',
				data(){
					return {
						 currentTab: "Home",
						 tabs: ["Home", "Posts", "Archive"]
					}
				},
				methods:{
					handelclick(tab){
						this.currentTab = tab
					},
					getStyle(tab){
						return ['tab-button',{active:this.currentTab===tab}]
					}
				},
				computed:{
					currentTabComponent(){
						/* return `tab-${this.currentTab}`.toLowerCase() */
						return "tab-"+this.currentTab.toLowerCase()
					},
					
				}
			}) 
			 
		 </script>
	</body>
</html>

おすすめ

転載: blog.csdn.net/m0_46461853/article/details/126240185