这一章感觉要学好久了...

<body>
    <!-- 组件:Vue.js最核心、设计最精彩的功能,也是最难掌握的(555) -->
    <!-- 组件:提高重用性,让代码能够复用 -->
    <div id="app1">
        <my-component-01></my-component-01>
        <my-component></my-component>
    </div>

    <!-- 在某些情况下,组件的模板会受到html的限制,如table标签内规定只允许是tr、td、th这些表格元素, 所以直接在table标签内使用组件是无效的,这种情况下可以使用特殊的is属性来挂载组件 -->
    <div id="app2">
        <table>
            <tbody is = 'my-component-table'>

            </tbody>
        </table>
    </div>

    <div id="app3">
        <my-component-02></my-component-02>
    </div>

    <div id="app4">
        <my-component-03></my-component-03>
        <my-component-03></my-component-03>
        <my-component-03></my-component-03>
        <my-component-03></my-component-03>
        <my-component-03></my-component-03>
    </div>
</body>
<script>
    // 组件需要注册之后才能使用,有全局注册(任何Vue实例都可以使用)以及局部注册两种方式
    // 全局注册,注册的组件需要在初始化根实例之前注册了组件;
    // 局部注册,通过使用组件实例选项注册,可以使组件仅在另一个组件或者实例的作用域中可用:
 Vue.component('my-component-01',{ template:'<div>这是第一个组件的内容</div>'
        //组件内容
 }); Vue.component("my-component-table",{ template:'<div>这是塞进表格组件里的内容</div>'//渲染时会将tbody替换
 }); var childCompo = { template:'<div>这是第一个局部注册组件的内容</div>' }; var app1 = new Vue({ el:"#app1", components:{ 'my-component':childCompo } }); var app2 = new Vue({ el:"#app2" });//注意了,使用组件时要确保已经将元素挂载到Vue实例

    //组件还可以像vue实例那样使用其他选项,比如data、computed、methods等,但在使用data时有区别:
    //data必须是函数,将数据return出去
 Vue.component('my-component-02',{ template:'<div>{{ message }}</div>', data() { return { message:'组件内容,这里的data是函数' } }, }); var app3 = new Vue({ el:"#app3" }); //js的对象是引用关系(值传递和引用传递的相关知识),如果return的对象引用了外部的一个对象,那么这个对象就是共享的
    //任何一方修改都会同步
    var dataObj = { counter:0 }; Vue.component('my-component-03',{ template:'<button v-on:click="counter++">记录点击次数:{{ counter }}</button>', // data:function(){
        // return {
        // dataObj//上面那个对象
        // }
        // }会报错的写法
 data:function(){ return dataObj }, // data:function(){
        // return {
        // counter:0
        // }
        // }
 }) var app4 = new Vue({ el:"#app4", }); //如果这样,每点击一个按钮,所有按钮的计数次数都会+1,改写为96~100行的形式
    //原理:给每个组件返回一个新的data对象
</script>

 

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

重难点是后面两个部分,使用props传递数据、父子组件通信

<body>
    <div id="app1">
        <my-component-01 message-from="来自父组件的数据"></my-component-01>
    </div>

    <div id="app2">
        <input type="text" v-model="parentMessage">
        <my-component-02 :message = "parentMessage"></my-component-02>
    </div>

    <div id="app3">
        <my-component-03 message="[1,2,3]"></my-component-03>
        <my-component-03 :message="[1,2,3]"></my-component-03>
        <!-- 直接传递数字、布尔值、数组、对象而不使用v-bind那么传递过去的只会是字符串!例如上面两个组件中的message.length,一个是7,一个是3 -->
    </div>

    <div id="app4">
        <my-component-04 :init-count="1"></my-component-04>
        <my-component-04 :width="200"></my-component-04>
    </div>

    <div id="app5">
        <input type="text" v-model="parentMessage">
        <my-component-05 :prop_a = "parentMessage"></my-component-05>
    </div>

    <div id="app6">
        <p>总计:{{ total }}</p>
        <my-component-06 @increase = "handleGetTotal" @reduce = "handleGetTotal"></my-component-06>
        </my-component-06>
    </div>

    <div id="app7">
        <p>app7:{{ total }}</p>
        <my-component-07 v-model = "total"></my-component-07>
    </div>

    <div id="app8">
        <p>app8:{{ total }}</p>
        <my-component-08 v-model="total"></my-component-08>
        <button @click = "handleReduce">-1</button>
    </div>
</body>
<script> Vue.component('my-component-01',{ //使用props声明需要从父级接收的数据
 props:['messageFrom'],//如果要传递多个数据,直接在props数组中添加项即可
        //注意短横杠分隔命名与驼峰式命名
 template:'<div>{{ messageFrom }}</div>', }); var app1 = new Vue({ el:"#app1" }); //上面是写死的数据,但大多数情况传递的数据是来自父级的动态数据,此时应使用v-bind动态绑定
 Vue.component('my-component-02',{ props:['message'], template:'<div>子组件:{{ message }}</div>' }); var app2 = new Vue({ el:"#app2", data:{ parentMessage:''
           //数据传递:pM更改-->v-model更改-->message值更改(:message = "parentMessage")-->props中的message-->子组件中的message
 } }); Vue.component('my-component-03',{ props:['message'], template:'<div>{{ message.length }}</div>', data:function(){ console.log(this,this.message); return {messages:this.message}; } }); var app3 = new Vue({ el:"#app3", }); //业务中经常会遇到的两种改变prop的情况:
    //1.父组件传递初始值,子组件将其保存起来,在自己的作用域下任意传值与修改,
    //2.另一种情况:prop作为需要进行转变的初始值传入
 Vue.component('my-component-04',{ props:['initCount','width'], template:'<div>\ <p>{{ count }}</p>\ <div :style="style"></div>\ </div>', data:function(){ return { count:this.initCount,//在组件初始化时会获取来自父组件的initCount,之后就与之无关了
 }//返回的必须是一个数据对象哈小老弟
 }, computed: { style:function(){ return { width:this.width + 'px'
                    //这里会得到:style="width:200px"
 } } }, }); var app4 = new Vue({ el:"#app4", }); //数据验证,当某个数据不符合输入类型时会在控制台弹出警告
 Vue.component('my-component-05',{ props:{ //数字类型限定
 prop_a:Number, // propA:[Number,String],
            //布尔值限定,默认为true,必须传入
 propB:{ type:Boolean, default:true, // required:true
 }, //默认值必须是一个函数来返回
 propC:{ default:function(){ return []; } }, //自定义验证函数
 propD:{ validator:function(value){ return value > 500; } } }, template:'<div>子组件只能是数字:{{ prop_a }}</div>', }) var app5 = new Vue({ el:"#app5", data:{ parentMessage:0 } }); //当子组件需要向父组件传递数据时需要用到自定义事件以及$emit()方法
 Vue.component('my-component-06',{ template:'\ <div>\ <button @click="handleIncrease()">+1</button>\ <button @click="handleReduce">-1</button>\ </div>', data:function(){ return { counter:0 } }, methods: { handleIncrease:function(){ this.counter++; this.$emit('increase',this.counter); }, handleReduce:function(){ this.counter--; this.$emit('reduce',this.counter); } }, }); //分析一下数据的传递:
    //1,total最初为0
    //点击+1键:触发组件06methods中的handleIncrease方法,counter++,通过$emit()方法(第一个参数是自定义,第二个是可不填或多填的参数)
    //父组件上的v-on监听到increase事件,触发handleGetTotal()方法,同时$emit()方法的第二个参数被传入handleGetTotal()
    //this.total=totalNum,即新的counter值
    //v-on还可以用于监听原生的dom事件,但需要加上.native修饰符
    //eg:<m-c @click.native="handleClick"></m-c>
    var app6 = new Vue({ el:"#app6", data:{ total:0 }, methods:{ handleGetTotal:function(totalNum){ this.total = totalNum; } } }); Vue.component('my-component-07',{ template:'\ <button @click = "handleClick">+1</button>', data: function(){ return { counter:0 } }, methods: { handleClick:function(){ this.counter++; this.$emit('input',this.counter); } }, }); // 这一块的数据流动有点奇怪,我尽力分析一下:
    // 点击按钮 触发handleClick事件---counter++,并将事件名称input与当前counter值传递给父组件,

    // 注意,在前面几章有一个知识点,v-model实际上是一个语法糖,从前面复制过来并加上些详细点的解释:
    // v-model你可以理解成是value的更高级,:value(v-bind)属于数据单向绑定(从script到html的单向),v-model属于双向绑定
    // v-model官方给出的说法是:这其实是一个简写的形式,v-model实际执行的是下面的绑定:
    // <input type="text" v-bind:value="dataA" v-on:input="dataA = $event.target.value" />
    // (会根据在不同的表单控件上执行不同的作用,如option与button)
    // 在本例(app7)中则是:<input type="text" v-bind:value="total" v-on:input ="total = $event.target.value" />
    //然后更新total值后就会影响视图如{{ total }}辣~
    // 接前面对于数据流动的分析:子组件将input事件传递给父组件后,相当于组件07上触发了
    //input事件,使得v-model="total"获得更新,继而更新{{ total }}

    //前面碰到的例子都是这样写的:<input v-model="a">
    // <p>{{ a }}</p>
    var app7 = new Vue({ el:"#app7", data:{ total:0 } }); Vue.component('my-component-08',{ props:['value'], template:'<input :value = "value" @input = "updateValue">', methods:{ updateValue:function(event){ this.$emit('input',event.target.value); } } }); var app8 = new Vue({ el:"#app8", data:{ total:0 }, methods:{ handleReduce:function(){ this.total--; } } }); //这一部分的数据变化方向:
    //1:点击-1按钮,执行handleReduce方法,total--,直接反馈到视图中的{{ total }}与v-model="total"(双向绑定)
    //2.输入值,执行updateValue方法,同时更新value(记得前面说的v-model是个语法糖以及实际展现)
    //value被更新,子组件获取的是实时的value,也会获得更新
</script>

一个需要注意点的地方:

app5、组件05部分:

Vue.js 章7:组件、使用props传递数据、父子组件通信 随笔 第1张

Vue.js 章7:组件、使用props传递数据、父子组件通信 随笔 第2张

如果规定了类型,那么一开始传入的值就必须是符合类型要求的,否则会报错

Vue.js 章7:组件、使用props传递数据、父子组件通信 随笔 第3张

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄