vue组件传值

1.父组件向子组件传值

//- 父组件发送的形式是以属性的形式绑定值到子组件身上。
//- 然后子组件用属性props接收
    <div id="app">
        <menu-item title='来自父组件的值'></menu-item>  //给子组件传入一个静态的值
        //2.需要动态的数据的时候 需要属性绑定的形式设置 此时 ptitle  来自父组件data 中的数据 .  传的值可以是数字、对象、数组等
        <menu-item :title='ptitle' content='hello'></menu-item>
    </div>
    <script type="text/javascript">
      Vue.component('menu-item', {   //menu-item   为  子组件
        props: ['title', 'content'],  // 3、 子组件用属性props接收父组件传递过来的数据  
        data: function() {
          return { msg: '子组件本身的数据'}
        },
        template: '<div>{{msg + "----" + title + "-----" + content}}</div>'
      });
      var vm = new Vue({
        el: '#app',
        data: {
          pmsg: '父组件中内容',
          ptitle: '动态绑定属性'
        }  });
    </script>

2.子组件向父组件传值

// 子组件用`$emit()`触发事件   // 父组件用v-on 监听子组件的事件
// `$emit()`  第一个参数为 自定义的事件名称     第二个参数为需要传递的数据
    <div id="app">
      <div :style='{fontSize: fontSize + "px"}'>{{pmsg}}</div>
        <!--父组件用v-on 监听子组件的事件  这里 enlarge-text  是从 $emit 中的第一个参数对应   handle 为对应的事件处理函数-->		
      <menu-item :parr='parr' @enlarge-text='handle($event)'></menu-item>
    </div>
    <script type="text/javascript" src="js/vue.js"></script>
    <script type="text/javascript">
      Vue.component('menu-item', {  //子组件向父组件传值-携带参数
        props: ['parr'],
        template: `
          <div>
            <ul><li :key='index' v-for='(item,index) in parr'>{{item}}</li></ul>
              ###  1、子组件用$emit()触发事件
              ### 第一个参数为 自定义的事件名称   第二个参数为需要传递的数据  
            <button @click='$emit("enlarge-text", 5)'>扩大父组件中字体大小</button>
          </div>` });
      var vm = new Vue({
        el: '#app',
        data: {
          pmsg: '父组件中内容',
          parr: ['apple','orange','banana'],
          fontSize: 10 },
        methods: {
          handle: function(val){
            this.fontSize += val;   // 扩大字体大小
          } } });
    </script>

3.兄弟之间的传递

//借助于事件中心   var hub = new Vue()
- 传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)
- 接收数据方,通过mounted(){} 钩子中  触发hub.$on()方法名
- 销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据
    <div id="app">
        <div>父组件</div>
        <div> <button @click='handle'>销毁事件</button></div>
        <test-tom></test-tom>
        <test-jerry></test-jerry>
    </div>
        <script type="text/javascript" src="js/vue.js"></script>
        <script type="text/javascript">
          var hub = new Vue();  //1、 提供事件中心  //兄弟组件之间数据传递
          Vue.component('test-tom', {  
            data: function(){
              return {num: 0}},
            template: `<div> 
              <div>TOM:{{num}}</div>
                <div>
                  <button @click='handle'>点击</button>
                </div> </div>`,
            methods: {
              handle: function(){  
              //2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)   触发兄弟组件的事件
                hub.$emit('jerry-event', 2);
              }},
            mounted: function() {
             // 3、接收数据方,通过mounted(){} 钩子中  触发hub.$on(方法名
              hub.$on('tom-event', (val) => {
                this.num += val;
              })}
          });
          Vue.component('test-jerry', {
            data: function(){
              return {num: 0}  },
            template: `
              <div> <div>JERRY:{{num}}</div>
                <div>
                  <button @click='handle'>点击</button>
                </div>  </div> `,
            methods: {
              handle: function(){
                //2、传递数据方,通过一个事件触发hub.$emit(方法名,传递的数据)   触发兄弟组件的事件
                hub.$emit('tom-event', 1);
              }  },
            mounted: function() {
              // 3、接收数据方,通过mounted(){} 钩子中  触发hub.$on()方法名
              hub.$on('jerry-event', (val) => {
                this.num += val;
              })}
          });
          var vm = new Vue({
            el: '#app',
            data: { },
            methods: {
              handle: function(){
                //4、销毁事件 通过hub.$off()方法名销毁之后无法进行传递数据  
                hub.$off('tom-event');
                hub.$off('jerry-event');
              }}  });
        </script>

4,provide 和 inject https://vue3js.cn/docs/zh/guide/component-provide-inject.html

父组件可以作为其所有子组件的依赖项提供程序,而不管组件层次结构有多深。这个特性有两个部分:父组件有一个 provide 选项来提供数据,子组件有一个 inject 选项来开始使用这个数据。
如果要将 todo-items 的长度直接传递给 TodoListStatistics,我们将把这个属性向下传递到层次结构:TodoList -> TodoListFooter -> TodoListStatistics。
通过 provide/inject 方法,我们可以直接执行以下操作:

const app = Vue.createApp({})
app.component('todo-list', {
  data() {
    return {
      todos: ['Feed a cat', 'Buy tickets']
    }
  },
  provide: {
    user: 'John Doe'
  },
  template: `
    <div>
      {{ todos.length }}
      <!-- 模板的其余部分 -->
    </div>
  `
})
app.component('todo-list-statistics', {
  inject: ['user'],
  created() {
    console.log(`Injected property: ${this.user}`) // > 注入 property: John Doe
  }
})

要访问组件实例 property,我们需要将 provide 转换为返回对象的函数
这使我们能够更安全地继续开发该组件,而不必担心可能会更改/删除子组件所依赖的某些内容。

app.component('todo-list', {
  data() {
    return {
      todos: ['Feed a cat', 'Buy tickets']
    }
  },
  provide() {
    return {
      todoLength: this.todos.length
    }
  },
  template: `
    ...
  `
})

处理响应性
在上面的例子中,如果我们更改了 todos 的列表,这个更改将不会反映在注入的 todoLength property 中
如果我们想对祖先组件中的更改做出反应,我们需要为我们提供的 todoLength 分配一个组合式 API computed property:

app.component('todo-list', {
  // ...
  provide() {
    return {
      todoLength: Vue.computed(() => this.todos.length)
    }
  }
})

5,props https://vue3js.cn/docs/zh/guide/component-props.html

A,Prop 类型

// 到这里,我们只看到了以字符串数组形式列出的 prop:
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
// 通常你希望每个 prop 都有指定的值类型。这时,你可以以对象形式列出 prop,这些 property 的名称和值分别是 prop 各自的名称和类型:
props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object,
  callback: Function,
  contactsPromise: Promise // 或任何其他构造函数
}

B,传递静态或动态的 Prop

//1. 你已经知道了可以像这样给 prop 传入一个静态的值:
<blog-post title="My journey with Vue"></blog-post>

//2. 你也知道 prop 可以通过 v-bind 或简写 : 动态赋值,例如:
<!-- 动态赋予一个变量的值 -->
<blog-post :title="post.title"></blog-post>
<!-- 动态赋予一个复杂表达式的值 -->
<blog-post :title="post.title + ' by ' + post.author.name"></blog-post>

// 我们传入的值都是字符串类型的,但实际上任何类型的值都可以传给一个 prop。
//3. 传入一个数字
<!-- 即便 `42` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue     -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。             -->
<blog-post :likes="42"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post :likes="post.likes"></blog-post>

//4. 传入一个布尔值
<!-- 包含该 prop 没有值的情况在内,都意味着 `true`。          -->
<blog-post is-published></blog-post>
<!-- 即便 `false` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue  -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。             -->
<blog-post :is-published="false"></blog-post>
<!-- 用一个变量进行动态赋值。                                -->
<blog-post :is-published="post.isPublished"></blog-post>

// 5.传入一个数组
<!-- 即便数组是静态的,我们仍然需要 `v-bind` 来告诉 Vue        -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。             -->
<blog-post :comment-ids="[234, 266, 273]"></blog-post>
<!-- 用一个变量进行动态赋值。                                -->
<blog-post :comment-ids="post.commentIds"></blog-post>

// 6.传入一个对象
<!-- 即便对象是静态的,我们仍然需要 `v-bind` 来告诉 Vue        -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。             -->
<blog-post
  :author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
></blog-post>
<!-- 用一个变量进行动态赋值。                                 -->
<blog-post :author="post.author"></blog-post>

// 7.传入一个对象的所有 property
<!-- 如果你想要将一个对象的所有 property 都作为 prop 传入,你可以使用不带参数的 v-bind (取代 v-bind:prop-name)。例如,对于一个给定的对象 post:-->
<blog-post v-bind="post"></blog-post>
post: {
  id: 1,
  title: 'My Journey with Vue'
}

C,单向数据流
1,所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。
2,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。
如果你这样做了,Vue 会在浏览器的控制台中发出警告。
3,这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data property 并将这个 prop 作为其初始值:
4,这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:
5,注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。

D,Prop 验证
为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组

app.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function() {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator: function(value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    },
    // 具有默认值的函数
    propG: {
      type: Function,
      // 与对象或数组默认值不同,这不是一个工厂函数 —— 这是一个用作默认值的函数
      default: function() {
        return 'Default function'
      }
    }
  }
})

type 可以是下列原生构造函数中的一个:
String Number Boolean Array Object Date Function Symbol
此外,type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认。例如,给定下列现成的构造函数:

function Person(firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
}
// 用于验证 author prop 的值是否是通过 new Person 创建的
app.component('blog-post', {
  props: {
    author: Person
  }
})

E,Prop 的大小写命名
HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,
camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:

const app = Vue.createApp({})
app.component('blog-post', {
  // camelCase in JavaScript
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})
<!-- kebab-case in HTML -->
<blog-post post-title="hello!"></blog-post>
原文地址:https://www.cnblogs.com/xm0328/p/14250042.html