Vue组件传参方式

基本原则:
不要在子组件中直接修改父组件的状态数据
数据在哪, 更新数据的行为(函数)就应该定义在哪
通信方式:
1.Vuex 多组件共享状态(数据的管理)
(查看Vuex状态管理)
2.props传参
组件标签内,父组件向子组件传递数据
组件内声明所有props的方式:

①: 只指定名称		props: ['name', 'age', 'setName'] 
②: 指定名称和类型	
			    props: {
						name: String,
						  age: Number,
						  setNmae: Function
				}
③: 指定名称/类型/必要性/默认值
			

props: {
	   			  name: {type: String, required: true, default:xxx},
				}

1.子–>父
父:

1.<template>
  <!--模板中读取的是组件对象的属性数据-->
  <ul class="todo-main">
    <Item v-for="(todo, index) in todos" :key="index" :todo="todo" :deleteTodo="deleteTodo" :index="index"/>
  </ul>
</template>
import Item from './Item.vue'
export default {
// 声明接收属性: 属性名
props: ['todos', 'deleteTodo'], // 所有接收属性都会成为组件对象的属性(只读)
data () { // 组件对象可以读取data中的属性
  return {
        }
},
components: {
  Item
}

}
2.

<template>
  <div class="todo-container">
    <div class="todo-wrap">
      <todo-header :addTodo="addTodo"/>
      <List :todos="todos" :deleteTodo="deleteTodo"/>
      <TodoFooter :todos="todos" :deleteComplete="deleteComplete" :selectAll="selectAll"/>
    </div>
  </div>
</template>
<script>

  import storageUtils from './utils/storageUtils'
  import Header from './components/Header.vue'
  import List from './components/List.vue'
  import Footer from './components/Footer.vue'
  export default {

    data () {
      return {
        // 读取localstorage中存储的todos数据作为初始值
        todos: storageUtils.readTodos()
      }
    },

    methods: {
      // 添加todo
      addTodo (todo) {
        this.todos.unshift(todo)
      },

      // 删除指定下标的todo
      deleteTodo (index) {
        this.todos.splice(index, 1)
      },

      // 删除已完成的所有todo
      deleteComplete () {
        this.todos = this.todos.filter(todo => !todo.complete)
      },

      // 全选/全不选
      selectAll (isSelect) {
        this.todos.forEach(todo => todo.complete = isSelect)
      }
    },

    watch: {
      todos: {
        deep: true, // 深度监视
        /*handler: function (value) {
          // 保存todos的json数据到localStorage
          storageUtils.saveTodos(value)
        }*/
        handler: storageUtils.saveTodos
        /*handler: function (todos) {
          localStorage.setItem(TODOS_KEY, JSON.stringify(todos))
        }*/
      }
    },

    components: {
      TodoHeader: Header,
      List,
      TodoFooter: Footer
    }
  }
</script>
<style>
  .todo-container {
    width: 600px;
    margin: 0 auto;
  }
  .todo-container .todo-wrap {
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
  }
</style>

子:

  1. {{todo.title}}
list在这里插入代码片
<template>
  <!--模板中读取的是组件对象的属性数据-->
  <ul class="todo-main">
    <Item v-for="(todo, index) in todos" :key="index" :todo="todo" :deleteTodo="deleteTodo" :index="index"/>
  </ul>
</template>
<script>
  import Item from './Item.vue'

  export default {
    // 声明接收属性: 属性名
    props: ['todos', 'deleteTodo'], // 所有接收属性都会成为组件对象的属性(只读)
    data () { // 组件对象可以读取data中的属性
      return {
        msg: 'abc'
      }
    },
    components: {
      Item
    }
  }
</script>
<style>
  .todo-main {
    margin-left: 0px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding: 0px;
  }

  .todo-empty {
    height: 40px;
    line-height: 40px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding-left: 5px;
    margin-top: 10px;
  }
</style>
header在这里面输入代码:
<template>
  <div class="todo-header">
    <input type="text" placeholder="请输入你的任务名称,按回车键确认"
           v-model="title" @keyup.enter="add"/>
  </div>
</template>
<script>
  export default {

    props: { // 属性名/属性值的类型/属性的必要性
      addTodo: {
        type: Function,
        required: true
      },
    },

    data() {
      return {
        title: ''
      }
    },

    methods: {
      add () {
        // 得到输入数据
        const title = this.title.trim()
        // 检查
        if(!title) {
          alert('必须输入')
          return
        }

        // 封装一个todo对象
        const todo = {
          title,
          complete: false
        }

        // 添加到todos中
        this.addTodo(todo)

        // 清除输入
        this.title = ''
      }
    }
  }
</script>
<style>
  .todo-header input {
    width: 560px;
    height: 28px;
    font-size: 14px;
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 4px 7px;
  }

  .todo-header input:focus {
    outline: none;
    border-color: rgba(82, 168, 236, 0.8);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
  }
</style>
footer在这里输入代码:
<template>
  <div class="todo-footer">
    <label>
      <input type="checkbox" v-model="isCheck"/>
    </label>
    <span>
          <span>已完成{{completeSize}}</span> / 全部{{todos.length}}
        </span>
    <button class="btn btn-danger" v-show="completeSize" @click="deleteComplete">清除已完成任务</button>
  </div>
</template>
<script>
  export default {
    props: {
      todos: Array,
      deleteComplete: Function,
      selectAll: Function
    },

    computed: {
      completeSize () {
        return this.todos.reduce((preTotal, todo) => preTotal + (todo.complete ? 1 : 0), 0)
      },

      isCheck: {
        get () { // 计算得到一个决定是否勾选的boolean值
          return this.todos.length===this.completeSize && this.completeSize>0
        },

        set (value) { // 用户操作勾选框时调用
          this.selectAll(value)
        }
      }
    }
  }
</script>
<style>
  .todo-footer {
    height: 40px;
    line-height: 40px;
    padding-left: 6px;
    margin-top: 5px;
  }

  .todo-footer label {
    display: inline-block;
    margin-right: 20px;
    cursor: pointer;
  }

  .todo-footer label input {
    position: relative;
    top: -1px;
    vertical-align: middle;
    margin-right: 5px;
  }

  .todo-footer button {
    float: right;
    margin-top: 5px;
  }
</style>


2.父–>子
父:

 <template>
  <div>
    <p>我是父组件,传递消息给子组件,需要传递的消息在下面输入:</p>
    <p><input type="text" v-model="message"/></p>
    <child :message="message"></child>
  </div>
</template>

<script>
  import child from './VComChild'

  export default {
    name: "parent",
    data(){
      return{
        message:''
      }
    },
    components : {
      'child': child
    }
  }
</script>

子:

<template>
  <div>
    <p>我是子组件,接收来自父组件的信息:{{message}}</p>
  </div>
</template>

<script>
  export default {
    name: "child",
    props: ['message']
  }
**3. vue自定义事件**		
绑定事件监听,子组件向父组件发送数据。代替props中的函数数据
	绑定事件监听: 			@delete_todo="deleteTodo" 
	触发事件(只在父组件):	this.$emit(eventName, data) 	// $emit 是组件对象的方法
	

实例:
		<!-- 父组件 -->
<template>
  <div>
    <!--我们想在这个dealName的方法中传递额外参数name -->
    <test-son v-for="item in list" @dealName="todo(item.name, arguments)" :item="item"></test-son>
  </div>
</template>

<script>
  export default {
    name: 'test-p',
    data() {
      return {
        list: [{
          name: '小王'
        }, {
          name: '小刚'
        }]
      }
    },
    methods: {
      todo(name, data) {
        console.log(name);
        console.log(data)
      }
    }
  }
</script>
<!-- 子组件 -->
<template>
  <div>
    <button @click="sendData">发射{{item.name}}</button>
  </div>
</template>

<script>
  export default {
    name: 'test-s',
    props: ['item'],
    methods: {
      sendData() {
        this.$emit('dealName', '王老吉');
      }
    }
  }
</script>

当我们点击子组件button的时候就会打印对应的 xxx, 王老吉
4. PubSub

下载包: npm install –save pubsub-js  
		发布消息: PubSub.publish('msg', data)  
订阅消息: PubSub.subscribe('msg', function(msg, data){})  
**4. slot(插槽)**		
用于父组件向子组件传递 标签数据 , 标签里的props属性在父组件里编译 
	子组件: 
		<template> 
			<div> 
			  <slot name="xxx">不确定的标签结构1</slot> 
			  <div>组件确定的标签结构</div> 
			  <slot name="yyy">不确定的标签结构2</slot> 
			</div> 
</template> 
		父组件:
			<template> 
			  <div slot="xxx">xxx对应的标签结构</div>
			  <div slot="yyy">yyyy对应的标签结构</div>
			</template> 

猜你喜欢

转载自blog.csdn.net/diaojw090/article/details/89510686