vue组件(二)--prop传递数据

组件组合

组件设计初衷就是要配合使用的,最常见的就是形成父子组件的关系:组件 A 在它的模板中使用了组件 B。它们之间必然需要相互通信:父组件可能要给子组件下发数据,子组件则可能要将它内部发生的事情告知父组件。然而,通过一个良好定义的接口来尽可能将父子组件解耦也是很重要的。这保证了每个组件的代码可以在相对隔离的环境中书写和理解,从而提高了其可维护性和复用性。

在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop给子组件下发数据,子组件通过事件给父组件发送消息。看看它们是怎么工作的。

Prop

prop 是父组件用来传递数据的一个自定义属性。

父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop"

使用Prop传递数据

组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。父组件的数据需要通过 prop 才能下发到子组件中。

子组件要显式地用 props 选项声明它预期的数据:

传递静态prop

<div id="app">	
    <child message="hello!"></child>
</div>
 <script>
    // 注册
    Vue.component('child', {  
        // 声明 props
        props: ['message'],  
        // 同样也可以在 vm 实例中像 “this.message” 这样使用  
        template: '<span>{{ message }}</span>'
    })
    // 创建根实例
    new Vue({  el: '#app'})
</script>

为了便于理解,你可以将这个Vue实例看作child的父组件。

动态prop

类似于用 v-bind 绑定 HTML 特性到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:

<div id="app">
    <div>
      <input v-model="parentMsg">
      <br>
      <child v-bind:message="parentMsg"></child>
    </div>
</div>
<script>
// 注册
Vue.component('child', {  
    // 声明 props
   props: ['message'],
  // 同样也可以在 vm 实例中像 “this.message” 这样使用
  template: '<span>{{ message }}</span>'
})
// 创建根实例
new Vue({
  el: '#app',
  data: {
    parentMsg: '父组件内容'  
  }
})
</script>


# 传入一个对象的所有属性

如果你想要将一个对象的所有属性都作为 prop 传入,你可以使用不带参数的 v-bind(取代 v-bind:prop-name)。例如,对于一个给定的对象 post

post: {
  id: 1,
  title: 'My Journey with Vue'
}

下面的模板:

<blog-post v-bind="post"></blog-post>

等价于:

<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"
></blog-post>

属性值都绑定在这个模板上了。

   <div id="app">	
		<ol>
			<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
		</ol>
	</div> 

<script>
Vue.component('todo-item', {  
	props: ['todo'],
	template: '<li>{{todo}}</li>'  
})
new Vue({
	el: '#app',
	data: {
		sites:{
			name:'张三',
			age:24 
		}
	}
})
</script>

#

<div id="app">	
		<ol>
			<todo-item v-for="item in sites" v-bind:todo="item"></todo-item>
		</ol>
</div> 
<script src="../js/lib/vue.min.js"></script>
<script>
Vue.component('todo-item', {  
	props: ['todo'],
	template: '<li>{{todo.name}}</li>'  
})
new Vue({
	el: '#app',
	data: {
		sites:[
			{name:"pp"},
			{name:"yy"},
			{name:"haha"}
		]
	}
})
</script>

字面量语法vs动态语法


<comp some-prop="1"></comp>

定义prop时,要是不使用v-bind是字面量prop,传递了一个字符串而不是数值1,如果想传递一个真正的 JavaScript 数值,则需要使用 v-bind,从而让它的值被当作 JavaScript表达式计算。

<div id="app">
    <!-- 这里传递是字符串 -->
	<child my-message="123+456"></child>
	<!-- 这里用了动态语法,传递的值会通过js的表达式计算,传递的是数字 -->
	<child :my-message="123+456"></child>
</div>
<script>
	Vue.component("child", {
		props: ["myMessage"],
		template: "<div>计算结果为: {{myMessage}}</div>",
	});
	new Vue({
		el: "#app",
	});
</script>

Prop的大小写(camelCase vs kebab-case)

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

Vue.component('blog-post', {
  // 在 JavaScript 中是 camelCase 的
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})
<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-title="hello!"></blog-post>

重申一次,如果你使用字符串模板,那么这个限制就不存在了。

单向数据流

父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

这里有两种常见的试图改变一个 prop 的情形:

  1. 这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值:

    props: ['initialCounter'],
    data: function () {
      return {
        counter: this.initialCounter
      }
    }
    
  2. 这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:

    props: ['size'],
    computed: {
      normalizedSize: function () {
        return this.size.trim().toLowerCase()
      }
    }

代码在线工具箱:http://www.matools.com/

猜你喜欢

转载自blog.csdn.net/dd1145322563/article/details/82882352