vue组件传参(父传子、子传父、利用组件传参实现分页显示数据)

vue组件传参

1、父传子

  父:自定义属性名 + 数据(要传递)=> :value="数据"
  子:props ["父组件上的自定义属性名"] =>进行数据接收   
         
  父级调用子组件,通过子组件的属性传入数据
  子元素内部通过props配置(数组),来接受对应的数据,如props:['属性1','属性2',...]
  • 在可复用的组件中,最上层只能有一个根元素,
    即template模板中需要一个根元素包裹着子元素
  • 组件中内部私有数据存储在组件data中,通过外部传入的数据, 则通过 props选项接收。
    props:使用存储数据,组件内部使用数据的方式与data的一样
  • 一个组件默认可以拥有任意数量的 属性,任何值都可以传递给任何 属性。
  • data必须写成函数,使各组件之间空间独立,数据互不影响。
    data(){ return { 属性名:属性值 } }
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>组件传参-父传子</title>
    <script src="js/vue.js"></script>
</head>
<body>
    <div id="app">
        <!-- vue实例中的属性 -->
        <p v-text="name2"></p><hr>
 
        <!-- 父传参给子 ,使用v-bind 绑定属性的方式 ,
             下面的pages与num是绑定的自定义属性-->
        <my-component :pages="10" :num="100"></my-component>

         <!--使用v-bind指令绑定对象或数组的值--> 
        <my-component v-for="elf in arrs" :key="elf.id" v-bind:username="elf.username"></my-component> 
    </div>
    
    <script>
        // 自定义全局组件
        Vue.component("my-component",{        
            props:["pages","num","username"],
            template:`
{{name1}}
{{pages}}
{{num}}
{{username}}
`
, // data必须写成函数,使各组件之间空间独立,数据互不影响 data(){ return { // name1是自身的属性 name1:"我是自身的属性值啊" } } }); let app = new Vue({ el:"#app", data:{ // 子组件的属性不能与实例中的属性名相同 // 这里的name是实例属性 name2:"我是实例属性值", arrs:[ {id:1,username:"皮卡丘"}, {id:2,username:"喷火龙"}, {id:3,username:"可达鸭"} ] }, // methods:{ // getName(){ // return this.name; // } // } }); </script> </body> </html>

注意:

  • 如果传入的props值是一个表达式,则必须使用v-bind
  • 组件中的data和props数据都可以通过组件实例进行直接访问
  • data中的key与props中的key不能冲突

2、子传父

   子:this.$emit('自定义事件名称', 数据) 
       子组件标签写法: <子组件名 @自定义事件名称='回调函数'></子组件名>
   父:methods: {    
           回调函数() {      
               //处理数据  
           }  
      }

注意
vue中的数据默认是单向流动,只能父到子直接传递,但是子到父不能直接修改;
原因:父级的数据,不一定只是某个子级使用,可能还有其他子级也在使用,
如果一个子级内部随意去修改了父级的数据,很容易导致数据混乱。
(这样语法没有错误,控制台不会报错,出来的不是自己想要的数,排查起来很麻烦)
所以,如果子级想修改数据

  • 子级执行:$emit() 触发执行自定义事件
  • 父级监听:子级触发的自定义事件
  • 监听到事件触发后,就执行父级的回调函数

子级在特定条件下,触发自定义事件来通知父级,父级通过监听接收到这个通知后,
自己决定是否改变数据或改变多少

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>vue组件传参-子传父</title>
    <script src="js/vue.js"></script>
</head>
<body>
    <div id="app">     
        <!-- v-on:自定义事件名称="函数名称" 或者 @事件名称="函数名称" 
         这个事件名称的字母必须要小写,或者使用-隔开小写 
         -->

        <!-- 绑定自定义点击事件hello ,点击事件一触发,就触发了父级监听函数fn
             注意:这里举例是自定义点击事件,自定义事件类型很多,不限于点击事件-->
        <div-child @hello="fn"></div-child>
        
        <!-- <div-child @hello-nice="fn"></div-child> -->    

        <!-- 子元素传参过来的name -->
        <p>我是子元素传过来的<b>{{name}}</b></p>   
        
    </div>
    <script>
        Vue.component('div-child',{
            data(){
                return {
                    // 子组件传来的属性
                    name:"小精豆"
                }
            },
         
            // // 如果只让父级触发一个事件,不去处理它,事件函数写在这里
            //  template:`
//

第一

//

第二

// //
`
// 模板中的元素自定义事件,可以写表达式 // 子组件中元素的点击事件触发methods中的函数 template:`

第一

第二

`
, methods:{ go(){ // $emit("自定义事件名称",数据); this.$emit("hello",this.name); // 自定义事件名如果有多个字母,比较长的,使用`-`连接命名 // this.$emit("hello-nice",this.name); } } }); let app = new Vue({ el:"#app", data:{ // 子元素传来的参数 name:"" }, methods:{ // 父级监听事件 回调函数fn // fn(){ // console.log("我是父级派来监听事件的"); // } fn(n){ // 按条件触发函数,如下,如果传来的数据是对象,不触发 // if (n==Object) return; console.log(n); this.name = n; } } }); </script> </body> </html>

好了,来看看利用组件传参,去实现的分页案例,如下:

.pagination a{
     width: 50px;
     margin-left: 5px;
     display: inline-block;
     text-align: center;
     text-decoration: none;
     border: 1px solid lightgreen;
}
.pagination a.ago{
     width: 26px;
}
.pagination a.active{
     background-color: lightblue;
     color:white;
}
<div id="app">
    <ul id="ulist">
        <li v-for="user of showUsers" :key="user.id">
            {{user.username}}
        li>
    ul>
     
    <partpage :pages="totalpage" :page="curpage" @change="changepage">partpage>
        
    
    
div>
Vue.component("partpage",{
            // 属性:总页数pages,当前页page
            props:["pages","page"],
            // 阻止a标签的默认事件(点击a标签后自动刷新页面):  @click.prevent="执行事件的函数" 
            //  给显示页码的a标签绑定一个类active,
            // 这个类中右指定的样式,如果当前页数在它自身所在的a标签,
            // 即page===p为true时,就改变它的样式 ,否则还是原来的样式
            template:``,
            methods:{
                // 改变当前页数(当用户点击当前页数时,触发点击事件gotopage)
                gotopage(p){
                    // 组件传参: 子传父
                    this.$emit("changepage",p);
                },
                // 上一页
                prev(){
                    if(this.page>1){
                        this.$emit("changepage",this.page-1);
                    }
                },
                // 下一页
                next(){
                    if(this.page<this.totalpage){
                        this.$emit("changepage",this.page+1);
                    }
                }
            }
        });

        let app = new Vue({
            el:"#app",
            data:{
                // 准备一些数据,做分页效果的演示使用(实际应用中是从数据库中获取的)
                users:[
                    {id:1,username:"汤姆"},
                    {id:2,username:"约翰"},
                    {id:3,username:"玛丽"},
                    {id:4,username:"杰克"},
                    {id:5,username:"露丝"},
                    {id:6,username:"萨利"},
                    {id:7,username:"乔治"},
                    {id:8,username:"罗娜"},
                   
                ],
                // 测试v-for指令使用的
                // nums:10
                
                // 当前页数 (用户点击页码,显示当前页数是多少)
                curpage:1,
                // 每页显示多少条数据 
                pagesize:2,
                // 总页数 (根据总数据的条数决定的,计算得出,不需要直接设置)
              
            },
            // computed存放属性,存放计算后的数据
            computed:{
                // 计算总页数
                // totalpage:{ get(){} }

                // 下面是computed中get方法的简写方式 ,totalpage是属性不是函数
                totalpage(){
                    // 总页数=数据总条数/每页显示的数据条数
                    // Math.ceil()向上取整,当每页数据不足3条时,翻到下一页显示
                    return Math.ceil(this.users.length/this.pagesize);
                },

                // 获取每页显示的数据
                showUsers(){
                    // 每页显示的数据起点(即每一页从原数据中截取数据的起始位置)    
                    let start = (this.curpage-1)*this.pagesize;
                    
                    // 从总数据中截取需要的数据  
                    // slice(开始,结束):截取数组中指定范围,并将其返回(多次使用时定义新数组来接收)  
                    return this.users.slice(start,start+this.pagesize);
                     /* 假如当前页是1   (1-1)*3 = 0  -->  [0,3)
                                   2   (2-1)*3 = 3  -->  [3,5)
                                   3   (3-1)*3 = 6  -->  [5,7)
                                  ...      ...           ...
                     */
                }
            },
            methods:{
                // 父组件来处理触发的监听函数changpage
                changepage(page){
                    // console.log("子组件传过来的数据"+page);
                    // 如果需要在满足一定条件下去处理,则如右 if(条件){ // 处理代码 }
                    this.curpage = page;
                }
            }
        });

你可能感兴趣的:(Vue)