02 vue基本使用


1. Java高阶函数的使用

编程范式:命令式编程/声明式编程
编程范式:面向对象编程(对象)/函数式编程(函数)

filter/map/reduce
(过滤)filter中的回调函数有一个要求,必须返回一个boolean值
    true:当返回true时,函数内部会自动将这次回调的n加入到新的数组中
    false:当返回false时,函数会自动过滤这次的n
(映射)map:在回调函数中对数字进行处理
(聚合)reduce的作用:对数字中的所有内容进行汇总
//1 filter函数的使用
//取出小于100的数字
const nums = [10,20,30,40,50,60,70,566,343]

let newNums = nums.filter(function(n){   //newNums接受结果  newNums[] 
    return n<100;  //n符合则加入到新数组
}) 
console.log(newNums); // [10, 20, 30, 40, 50, 60, 70]
-------------------------
//2 map函数的使用
let new2Num = newNums.map(function (n) {
    return n*2;
})
console.log(new2Num);  //[20, 40, 60, 80, 100, 120, 140]
-------------------------
//3 reduce函数的使用
/* 
new2Num.reduce(function (preValue,n) {
    return 100;  //preValue拿到上一次函数返回的值
},0) 初始值
*/
//第一次:preValue:0 , n:20
//第二次:preValue:100 , n:40
//第三次:preValue:100 , n:60

let total = new2Num.reduce(function (preValue,n) {
    return preValue+n
},0) //初始
console.log(total);  //560
//第一次:preValue:0 , n:20
//第二次:preValue:20 , n:40
//第三次:preValue:60 , n:60

//链式
let total = nums.filter(function (n) {
    return n < 100;
}).map(function (n) {
    return n*2;
}).reduce(function (prevalue,n) {
    return preValue + n;
},0)
//等效
let total= nums.filter(n => n<100).map(n => n*2).reduce((preValue,n)=>preValue+n);
console.log(total);  //560

2. 表单绑定 v-model

  1. 双向绑定原理
    * vue中使用v-model指令来实现表单元素和数据的双向绑定。

当我们在输入框中输入内容时,因为input中的v-model绑定了message,所以会将实时输入的内容传递给message,使message发生改变。
当message发生改变时,因为上面使用了mustache语法,将message的值插入到dom中,所以dom会发生相应的变化。

<div id="app">
        <!-- v-model实现双向绑定 -->
        <!-- <input type="text" v-model='message'> -->

        <!-- 原理 -->
        <!--1 :value="message" 数据和view的绑定 -->
        <!--<input type="text" :value="message" @input="valueChange">  input:监听输入 -->

		<!-- 等效v-model -->
        <input type="text" :value="message" @input="message = $event.target.value"> <!-- $event直接获取事件  -->
        <h2>{{message}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
            },
            methods:{
                valueChange(event){ //产生事件浏览器会有event事件对象 
                    //上面不传参,浏览器会自动传入event
                    this.message = event.target.value; //2 输入的数据绑定到message
                }
            }
        })
    </script>
  1. v-model:redio
<div id="app">
        <!-- 加上name属性实现互斥选择,但是一旦v-model绑定同一个变量,也可以实现互斥,可以省略name属性,服务器提交需要name作为key -->
        <!-- value是要绑定到sex里的值 -->
        <label for="male">
            <input type="radio" id="male" value="" v-model="sex"></label>
        <label for="female">
            <input type="radio" id="female" value="" v-model="sex"></label>
        <h2>您选择的性别是:{{sex}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
                sex:'男'  //默认值
            },
            methods:{
                
            }
        })
    </script>
  1. v-model:checkbox
<div id="app">
<!--    1 checkbox单选框 -- 布尔类型
        <label for="agree">
            <input type="checkbox" id="agree" v-model="isAgree">同意协议
        </label>
        <h2>您选择的是{{isAgree}}</h2>
        <button :disabled="!isAgree">下一步</button>
-->
<!-- 
        2 checkbox多选框 -- 数组类型
        
 -->
        <!-- value是用来获取的 -->
        <input type="checkbox" value="篮球" v-model="hobbies">篮球
        <input type="checkbox" value="足球" v-model="hobbies">足球
        <input type="checkbox" value="兵乓球" v-model="hobbies">兵乓球
        <input type="checkbox" value="排球" v-model="hobbies">排球
        <h2>您的爱好是:{{hobbies}}</h2>
    </div>
    <script src="../js/vue.js"></script>
    <script>
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
                isAgree:false,
                hobbies:[],
            }
        })
    </script>
  1. v-model:select
<div id="app">
        <!-- 1 多个选择一个 -->
        <select name="abc"  v-model="fluit">
            <option value="苹果">苹果</option>
            <option value="香蕉">香蕉</option>
            <option value="西瓜">西瓜</option>
            <option value="桃子">桃子</option>
        </select>
        <h2>您选择的水果是:{{fluit}}</h2> <!-- 字符串类型 -->

        <!-- 2 选择多个 -->
        <select name="abc"  v-model="fluits" multiple>  <!-- multiple:下拉框多选 -->
            <option value="苹果">苹果</option>
            <option value="香蕉">香蕉</option>
            <option value="西瓜">西瓜</option>
            <option value="桃子">桃子</option>
        </select>
        <h2>您选择的水果是:{{fluits}}</h2> <!-- 数组类型 -->
    </div>
    <script src="../js/vue.js"></script>
    <script>
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
                fluit:'香蕉',
                fluits:[]
            }
        })
    </script>
  1. input中的值绑定
    之前的案例中input的值都是写死的,但是实际上开发中input的值可能是从网络获取或者定义在data中的,我们可以通过v-bind:value动态地给value绑定值。
	<div>
	 <!-- value值的动态绑定 -->
        <label v-for="item in originHobbies">
            <input type="checkbox" :value="item" v-model="hobbies">{{item}}
        </label>
    </div>
    <script src="../js/vue.js"></script>
    <script>
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
                isAgree:false,
                hobbies:[],
                originHobbies:['篮球','足球','兵乓球','排球','高尔夫球']
            }
        })
    </script>
  1. v-model修饰符的使用
  • lazy修饰符:
    v-model默认是在input事件中同步输入框的数据的,也就是说一旦有数据发生变化,对应的data中的数据就会发生变化,lazy修饰符可以让数据在失去焦点或者回车时才会更新。
  • number:
    默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当成字符串进行处理,但是如果我们希望处理的是数组类型,那么最好直接将内容当中数组处理。
    number修饰符可以让在输入框中的内容自动转换成为数字类型。
  • trim修饰符:
    如果输入的内容首尾有很多空格,通常我们需要将其去除,trim修饰符可以过滤内容左右两边的空格。
<div id="app">
        <!-- 1 修饰符:lazy 当失去焦点或者按下回车时才进行绑定-->
        <input type="text" v-model.lazy="message">
        <h2>{{message}}</h2>


        <!-- 2 修饰符:number 处理数字类型-->
        <input type="number" v-model.number="age"> <!-- v-model默认绑定过去的类型都是string -->
        <h2>{{age}}-{{typeof age}}</h2>

        <!-- 3 修饰符:trim 过滤内容左右两边的空格 -->
        <input type="text" v-model.trim="name">
        <h2>您输入的名字:{{name}}</h2>
    </div> 
    <script src="../js/vue.js"></script>
    <script>
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
                age:0,  //number --> '111' string
                name:''
            }
        })
    </script>


3.组件化开发

  1. vue组件化思想
    它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。
    任何应用都会被抽象成一颗组件树。
  2. 注册组件的基本步骤
    * 创建组件构造器
    * 注册组件
    * 使用组件
	<div id="app">
        <!-- 组件可以使代码复用 -->

        <!-- 3 使用组件 -->
        <my-cpn></my-cpn>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        /* 
            ES6:``波浪线小按键那里,使用``定义字符串,及时换行也可以看成一个整体,不需要+连接
            原先:
                const s = 'abcd'+
                 'sds'

            ES6:
                const s = `abcs
                 ds`
         */
        
        //1 创建组件构造器对象
        const cpnC = Vue.extend({
            template:`
            <div>
                <h2>我是标题</h2>
                <p>我是内容,哈哈哈哈</p>
                <p>我是内容,呵呵呵呵</p>
            </div>`
        })
        //2 注册组件 
        // Vue.component('组件标签名',组件构造器)
        Vue.component('my-cpn',cpnC)
        
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
            }
        })
    </script>
  1. 全局组件和局部组件
<div id="app">
        <cpn></cpn>
        <cpn></cpn>
        <cpn></cpn>
    </div>
    <div id="app2">
        <cpn></cpn>
    </div>
    <script src="../js/vue.js"></script>
    <script>
        //1 创建组件构造器
        const cpnC = Vue.extend({
            template:`
                <div>
                    <h2>我是标题</h2>
                    <p>我是内容哈哈哈</p>   
                </div>`
        }) 

        //2 注册组件(全局组件,可以在多个vue的实例下使用)
        Vue.component('cpn',cpnC)

        //疑问:怎么注册的组件才是局部组件?
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
            },
            components:{ //3 局部组件
                //cpn:使用组件时的标签名
                cpn:cpnC,
            }
        })
        //一般只有一个vue实例,但是也可以定义多个
        const app2 = new Vue({
            el:"#app2",  
        })
    </script>
  1. 父组件和子组件
  • 父子组件的错误用法:
    当子组件注册到父组件的components时,Vue会编译号父组件的模块,该模板的内容已经决定父组件将要渲染的HTML(相当于父组件中已经有了子组件的内容了)
    <cpn-child></cpn-child>中的内容是只能在父组件中被识别的,如果未注册就使用,浏览器不识别,会报错。
<div id="app">
        <cpn2></cpn2>
        <!-- <cpn1></cpn1> 组件的使用要么是全局组件,要么得在它的components中注册过,否则使用报错
            会优先在自己的components中找,如果找不到再找全局组件
        -->
    </div>

    <script src="../vue.js"></script>
    <script>

        //第一个组件构造器(子组件)
        const cpnC1 = Vue.extend({
            template:`
                <div>
                    <h2>我是标题1</h2>
                    <P>我是内容哈哈哈</P>
                </div>
            `
            
        })

        //第二个组件构造器(父组件)
        const cpnC2 = Vue.extend({
            template:`
                <div>
                    <h2>我是标题2</h2>
                    <P>我是内容呵呵呵</P>
                    <cpn1></cpn1>
                </div>
            `,
            //写在构造器中的组件(在某一个组件中注册另一个组件 -- 可以在组件的模板中使用注册过的另一个组件)
            components:{
                cpn1:cpnC1, //注册(既不是全局组件也不是局部组件)
            }
        })

        //Vue实例也可以看成是最顶层的组件 --- root
        let app = new Vue({
            el: '#app',
            data: {
                msg: '你好',
            },
            //注册局部组件
            components:{
                cpn2:cpnC2, /* 虽然cpnC2模板中有cpnC1,但是对于vue实例它是不知道cpnC1存在的*/
            }
        })
    </script>
  1. 注册组件的语法糖写法
    Vue简化了注册组件的过程,省去了调用Vue.extend()的步骤,直接使用一个对象来代替。
<div id="app">
        <cpn1></cpn1>   <!-- 全局 -->
        <cpn2></cpn2>   <!-- 局部 -->
    </div>
    <script src="../js/vue.js"></script>
    <script>
        //1 全局组件注册的语法糖
        //1 创建组件构造器
        // const Cpn1 = Vue.extend()
        //2 注册组件

        //(全局组件)
        Vue.component('cpn1',{  //语法糖,直接把构造器放里面,内部会传给extend
            template:`
                <div>
                    <h2>我是标题1</h2>
                    <p>我是内容哈哈哈</p>   
                </div>`
        })

       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
            },
            components:{  //局部组件
                'cpn2':{
                    template:`
                    <div>
                        <h2>我是标题2</h2>
                        <p>我是内容嘿嘿嘿</p>   
                    </div>`
                }
            }
        })
    </script>
  1. 组件模板抽离的写法
<div id="app">
        <cpn></cpn>
    </div>

    <!-- 1 这样写打标签比较方便,使用script标签,类型必须是text/x-template-->
    <script type="text/x-template" id="cpn1">
        <div>
            <h2>我是标题1</h2>
            <p>我是内容,哈哈哈</p>
        </div>
    </script>

    <!-- 2 template标签 -->
    <template id="cpn2">
        <div>
            <h2>我是标题2</h2>
            <p>我是内容,哈哈哈</p>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script>
        //1 注册一个全局组件
        Vue.component('cpn',{
            template:'#cpn1'  //分离模板到外边
        })

       const app = new Vue({
            el:"#app", 
        })
    </script>
  1. 为什么组件data必须是函数
  • 组件是一个单独功能模块的封装:这个模块有属于自己的HTML模板,也应该有属性自己的数据data,组件是不能直接访问vue实例中的data的
  • 组件对象也有一个data属性,而且这个data属性必须是一个函数,函数返回一个对象,对象内部保存着数据。
	<script type="text/x-template" id="cpn1">
        <div>
            <h2>{{title}}</h2>
            <p>我是内容,哈哈哈</p>
        </div>
    </script>
Vue.component('cpn',{
            template:'#cpn1',  //分离模板到外边
            data(){
                return{  //返回一个实例对象
                    title:'abc',
                }
            }
        })
  • 为什么data必须是函数?
    如果不是函数,组件之间数据会造成影响。
 <!-- 组件实例对象 -->
    <div id="app">
        <cpn></cpn>
        <cpn></cpn>
        <cpn></cpn>
    </div>

    <template id="cpn">
        <div>
           <h2>当前计数:{{counter}}</h2>
           <button @click="increment">+</button>
           <button @click="decrement">-</button>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
        //1 注册组件
        /* const obj = {
            counter:0
        } */

        Vue.component('cpn',{
            template:'#cpn',
            //如果是data{...},那么组件实例调用的都想同一个对象,会导致数据一起改变,互相影响
            data(){  //函数,每次都返回一个新的对象  
                return{
                    counter:0
                }
                // return obj;  //如果这么写那么每次返回的还是同一个对象,数据还是互相影响
            },
            methods:{
                increment(){
                    this.counter++;
                },
                decrement(){
                    this.counter--;
                }
            }
        })
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
            }
        })
    </script>

4.父子组件的通信

子组件是不能引用父组件或者vue实例的数据的,在开发中,往往一些数据确实需要从上层传递到下层,需要子组件来进行展示。这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)。

  • 父子组件间的通信:
    通过props向子组件传递数据
    通过事件向父组件发送消息
    在这里插入图片描述

01. 父组件向子组件传递数据

  • props的值有两种方式:
    方式一:字符串数组,数组中的字符串就是传递时的名称
    方式二:对象,对象可以设置传递时的类型,也可以设置默认值等
	<div id="app">
        <!--<cpn v-bind:cmovices='movices'></cpn>   记住要v-bind,否则内容会直接当做字符串传递给子组件 -->
        <cpn :cmessage='message' :cmovices="movices"></cpn>
    </div>

    <template id="cpn">
        <div>
            <ul>
                <li v-for="item in cmovices">{{item}}</li>
            </ul>
            <p>{{cmovices}}</p>
            <h2>{{cmessage}}</h2>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script>
        //父传子:props
        const cpn = {
            template:'#cpn',
            // ---- 1.传递数组:可以将数组中的字符串看成变量 -----
            // props:['cmovices','cmessage'],  
            
            
            //----- 2.传递对象 -->可以进行类型限制 --------------
            props:{
                //01 指定类型
                // cmovices:Array,  
                // cmessage:String
                
                //02 提供一些默认值,以及必传值
                cmessage:{
                    type:String,
                    default:'aaaaa',
                    required:true  //必须传值
                },
                //03 类型是对象或者数组时,默认值必须是一个函数
                cmovices:{
                    type:Array,
                    // default:[] //vue2.5.17以下,现在会报错
                    default(){
                        return [] //写成函数就不会报错
                    }
                }
            },
            data(){
                return {}
            },
            methods:{

            }
        }

        //vue实例可以看成父组件
       const app = new Vue({
            el:'#app',  
            data:{  
                message:'哈哈哈',
                movices:['海王','海贼王','海尔兄弟'] //将数据传递给子组件显示
            },
            components:{  //注册局部组件(子组件)
                cpn
            }
        })
    </script>
  • props驼峰标识
	<div id="app">
        <!-- c-bind不支持驼峰命名,CInfo是不能够识别的,如果要写驼峰标识,格式应该为C-info -->
        <cpn :C-info='info' :child-my-message='message'></cpn> 
    </div>

    <template id="cpn">
        <!-- 组件的模板如果包含多标签,外层需要有一个根把内容包起来 -->
        <div> 
            <h2>{{CInfo}}</h2>
            <h2>{{childMyMessage}}</h2>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>

        const cpn = {
            template:'#cpn',
            props:{
                CInfo:{
                    type:Object,
                    default(){
                        return {} //对象的默认值必须是一个函数
                    }
                },
                childMyMessage:{
                    type:String,
                    default:''
                }
            }

        }
       const app = new Vue({
            el:"#app",  
            data:{  
                info:{
                    name:'why',
                    age:18,
                    height:1.88
                },
                message:'aaa'
            },
            components:{
                cpn
            }
        })
    </script>

02. 子传父(自定义事件)

以下写法中要注意驼峰命名,可能会报错,识别不了,需要将命名转换一下。但是在脚手架中是可以直接驼峰命名的。

	<!-- 父组件模板 -->
    <div id="app">
        <cpn @itemclick="cpnClick"></cpn>
    </div>

    <!-- 子组件模板 -->
    <template id="cpn">
        <div>
            <!-- 父组件根据子组件点击的item去请求新的数据 -->
            <button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button>
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script>
        //1 子组件
        const cpn = {
            template:'#cpn',
            data(){
                return {
                    categories:[
                        {id:'aaa',name:'热门推荐'},
                        {id:'bbb',name:'手机数码'},
                        {id:'ccc',name:'家用家电'},
                        {id:'ddd',name:'电脑办公'},
                    ]
                }
            },
            methods:{
                btnClick(item){   //父传子 --- 自定义事件
                    //发射事件
                    this.$emit('itemclick',item)  /* 'itemClick'事件名称 */
                }
            }

        }
        

        //2 父组件
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
            },
            components:{
                cpn
            },
            methods:{
                cpnClick(item){
                    console.log("cpnClick",item);
                }
            }
        })
    </script>

03. 父子组件通信(结合双向绑定)

(非常绕的代码,要多听几次课理解)

在这里插入图片描述

<div id="app">
        <!-- :number1='num1' :实现将父组件数据传递给子组件
            @num1change="num1change" :实现对子组件传递的数据进行处理,重新给父组件的num赋值
        -->
        <cpn :number1='num1' 
             :number2='num2' 
             @num1change="num1change" @num2change="num2change" 
        />
    </div>

    <template id="cpn">
        <div>
            <!----------++++ 需求1: 输入框输入可以改变h2中的number1,并且vue实例中的num1也发生改变 ++++-------->
            <h2>props:{{number1}}</h2>
            <h2>data:{{dnumber1}}</h2>
            <!-- <input type="text" v-model="number1"> 
                01 绑定到组件的props中,这样绑定虽然数值会发生改变,但是浏览器报错 
                props中的属性一般是父组件进行修改的,我们不可以用子组件来修改props中的属性,官方不推荐,我们要避免直接改变里面的值
            -->
            <!-- <input type="text" v-model="dnumber1"> 
                04 将v-model换成下面等价的方式:也可以实现双向绑定
            -->
            <input type="text" :value="dnumber1" @input="num1input">

            <h2>props:{{number2}}</h2>
            <h2>data:{{dnumber2}}</h2>  <!-- 03 当前input绑定的是data中的数据,不要直接将数据绑定到props中 -->
            <input type="text" :value="dnumber2" @input="num2input">
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script>

       const app = new Vue({
            el:"#app",  
            data:{  
               num1:1,
               num2:0
            },
            methods:{  //06 接受从子组件传来的数据,进行处理
                num1change(value){
                    this.num1 = parseFloat(value);  //这里实现了将子组件传来的数据赋值给父组件原本的数据
                },
                num2change(value){
                    this.num2 = parseFloat(value);
                },
            },
            components:{
                cpn:{
                    template:'#cpn',
                    props:{ //父传子
                        number1:Number,
                        number2:Number,
                    },
                    data(){ //用data或者计算属性
                        return {
                            dnumber1:this.number1,   //02 根据props中的number1来初始化data里的dnumber1
                            dnumber2:this.number2, 
                        }
                    },
                    methods:{
                        num1input(event){
                            //1将input中的value赋值到dnumber中
                            this.dnumber1 = event.target.value;
                            //2 为了让父组件可以修改值,发出一个事件
                            this.$emit('num1change',this.dnumber1); //05 子传父--自定义方法

                            /* ====== 需求2 :下面的data值永远是上面的100倍 ======= */
                            //3 同时修改dnumber2的值 和 num2的值
                            this.dnumber2 = this.dnumber1 * 100;
                            this.$emit('num2change',this.dnumber2)


                        },
                        num2input(event){
                            this.dnumber2 = event.target.value,
                            this.$emit('num2change',this.dnumber2); 

                            this.dnumber1 = this.dnumber2 / 100;
                            this.$emit('num1change',this.dnumber1)
                        }
                    }
                }
            }
        })
    </script>

04. 父子组件的访问方式

是通过对象直接访问的,而不是信息的传递那么简单,可能需要在父组件中直接操作子组件的属性或者方法。

  • 父组件访问子组件:使用$children或者$refs
  • 子组件访问父组件:使用$parent
父访问子-children-refs
	<div id="app">
        <cpn></cpn>
        <cpn></cpn>
        <cpn ref='aaa'></cpn> <!-- ref相当于一个key,有key则能获取相应的组件 -->
        <button @click='btnClick'>按钮</button>
    </div>
    <template id="cpn">
        <div>我是子组件</div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
            },
            methods:{
                btnClick(){
                    //1 $children --- 当我们需要获取所有子组件的时候,会使用这个
                    // console.log(this.$children);   //this.$children直接获取子组件,调用子组件的方法
                    // for(let c of this.$children){
                    //     c.showMessage();
                    //     console.log(c.name);
                    // }
                    // console.log(this.$children[3].name);  根据下标获取元素不方便,开发子组件不是一成不变的


                    //2 $refs --- 多用
                    //必须在组件上加属性ref='...',aaa类似组件的名字,还可以进一步获取具体数据
                    console.log(this.$refs.aaa.name);  //$refs => 对象类型,默认是一个空对象

                }
            },
            components:{
                cpn:{
                    template:'#cpn',
                    data(){
                        return {
                            name:'我是子组件的name',
                        }
                    },
                    methods: {
                        showMessage(){
                            console.log('showMessage');
                        }
                    },
                }
            }
        })
    </script>
子访问父-parent-root
	<div id="app">
        <cpn></cpn>
    </div>

    <template id="cpn"> 
        <div>
            <h2>我是cpn组件</h2>
            <ccpn></ccpn> <!-- 使用子组件 -->
        </div>
    </template>

    <template id="ccpn">
        <div>
            <h2>我是子组件</h2>
            <button @click="btnClick">按钮</button>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
            },
            components:{ //子组件
                cpn:{
                    template:'#cpn',
                    data() {
                        return {
                            name:'我是cpn的组件的name'
                        }
                    },
                    components:{  //子子组件
                        ccpn:{
                            template:'#ccpn',
                            methods: {
                                btnClick(){
                                    //1 访问父组件 $parent  -- 用得少
                                    console.log(this.$parent);
                                    console.log(this.$parent.name);

                                    //2 访问根组件
                                    console.log(this.$root); //访问到vue实例
                                    console.log(this.$root.message); 
                                }
                           },
                        },
                       
                    }
                },
                
            }
        })
    </script>

5. slot 插槽

  1. 为什么使用插槽:组件的插槽是为了让我们封装的组件更加具有扩展性。
  2. 插槽的基本使用
<body>
    <!-- 
       1 插槽的基本使用:<slot></slot>
       2 插槽的默认值:<slot><button>按钮</button></slot>
       3 如果有多个值同时放入到组件中进行替换,会一起作为替换元素 
     -->
    <div id="app">
        <cpn><button>按钮</button></cpn> <!-- 2 根据插槽显示不同的内容 -->
        <cpn><span>哈哈哈</span></cpn>
        <cpn>
            <i>呵呵呵</i>
            <div>我是div</div>  <!-- 4 插槽中多个标签,会全部替换  -->
        </cpn> 
        <cpn></cpn>  <!-- 3 不指定则显示默认设置的值  -->
    </div>
    <template id='cpn'>
        <div>
            <h2>我是组件</h2>
            <p>我是组件,哈哈哈</p>
            <slot><button>按钮</button></slot> <!-- 1 预备插槽,可以设置默认值 -->
        </div>
    </template>


    <script src="../js/vue.js"></script>
    <script>
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
            },
            components:{
                cpn:{
                    template:'#cpn',
                }
            }
        })
    </script>
</body>
  1. 具名插槽的使用
    例如购物商城的导航栏,不同页面的导航栏类似但又有些不同,就可以使用插槽替换内容,给插槽指定名称,就可以控制替换具体的插槽了。
<body>
    <div id="app">
        <cpn>
            <span>哈哈哈</span> <!-- 替换没有名字的插槽 -->
            <span slot="center">标题</span> <!-- 替换指定名字的插槽 -->
        </cpn>
        <cpn><button slot='left'>按钮</button></cpn>
    </div>
    <template id='cpn'>
        <div>
            <slot name="left"><span>左边</span></slot>
            <slot name="center"><span>中间</span></slot>
            <slot name="right"><span>右边</span></slot>
            <slot></slot>
        </div>
    </template>


    <script src="../js/vue.js"></script>
    <script>
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
            },
            components:{
                cpn:{
                    template:'#cpn',
                }
            }
        })
    </script>
</body>

编译作用域

父组件模板的所有东西都会在父级作用域内编译,子组件模板的所有东西都会在子级作用域内编译。

	<div id="app">  <!-- 1 在使用的变量的时候都会先看模板,这里是属于vue实例的模板 -->
        <cpn v-show="isShow"></cpn>  <!-- 使用的是实例中的isShow -->
    </div>
    <template id="cpn">
        <div>
            <h2>我是子组件</h2>
            <p>我是内容,哈哈哈</p>
            <button v-show="isShow">按钮</button> <!-- 2 组件也有自己的作用域 -->
        </div>
    </template>

    <script src="../js/vue.js"></script>
    <script>
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
                isShow:true,
            },
            components:{
                cpn:{
                    template:'#cpn',
                    data() {
                        return {
                            isShow:false,
                        }
                    },
                }
            }
        })
    </script>

作用域插槽

  • 其实就是父组件对子组件里面展示的数据不满意,想要以另一种方式进行展示的时候,就需要从子组件中获取数据,自己设置展示。

  • 父组件替换插槽的标签,但是内容由子组件来提供

	<div id="app">
        <cpn></cpn>  <!-- 默认显示 -->
        <cpn>
            <!-- 父组件想要拿到子组件的数据展示,但是因为作用域问题,不能直接遍历子组件的数据 -->
            <!-- 目的是获取子组件中的PLanguages 2.5.x以下需要使用template模板-->

            <!-- 2 引用插槽对象 ,使用slot.data即可获取 -->
            <template slot-scope="slot">   
               <!-- <span v-for="item in slot.data">{{item}} - </span> -->
               <span>{{slot.data.join(' - ')}}</span>
               <!-- join()可以把数组转换为字符串,并且多个数组元素之间可以设置一个字符连接 -->
            </template>
        </cpn>

        <cpn>
            <template slot-scope="slot">  
               <!-- <span v-for="item in slot.data">{{item}} * </span> -->
               <span>{{slot.data.join(' * ')}}</span>
            </template>
        </cpn>
    </div>
    <template id="cpn">
        <div>
            <slot :data="PLanguages"> <!-- 1 data是自定义名 -->
                <ul>
                    <li v-for="item in PLanguages">{{item}}</li>
                </ul>
            </slot>
        </div>
    </template>
    <script src="../js/vue.js"></script>
    <script>
       const app = new Vue({
            el:"#app",  
            data:{  
                message:'哈哈哈',
            },
            components:{
                cpn:{
                    template:'#cpn',
                    data() {
                        return {
                            PLanguages:['java','c#','python','c++','go','Swift']
                        }
                    }
                }
            }
        })
    </script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值