Vue组件(Vue中重中之重)

template(模板)

  1. 如果有template属性,当初始化实例时,会把template的属性值编译并替换掉App元素;
  2. template中只能有一个根元素,如果有两个,会默认取第一个作为根元素
  3. template中可以获取到data中数据和methods中的方法
<body>
    <div id="app">
        <span>{{msg}}</span>
    </div>
    <div id="app1"></div>
    <template id="first">
        <div>{{msg}}<div @click='fn'>888</div></div>
    </template>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        // 1. 如果有template属性,当初始化实例时,会把template的属性值编译并替换掉App元素;
        // 2. template中只能有一个根元素,如果有两个,会默认取第一个作为根元素
        // 3.template中可以获取到data中数据和methods中的方法
        // let vm = new Vue({
        //     el:"#app",
        //     data:{
        //         msg:"hello",
        //         flag:false
        //     },
        //     methods:{
        //         fn(){
        //             console.log(888);
        //         }
        //     },
        //     template:"<div>{{msg}}<div @click='fn'  v-if='flag'>888</div></div>"
        // })
        let vm = new Vue({
            el:"#app",
            data:{
                msg:"hello",
                flag:false
            },
            methods:{
                fn(){
                    console.log(888);
                }
            },
            template:"#first"
        })
        let vm1 = new Vue({
            el:"#app1",
            data:{
                msg:"zfpx",
                flag:false
            },
            methods:{
                fn(){
                    console.log(888);
                }
            },
            template:"#first"
        });
        // 抽离公共部分的结构;
    </script>
</body>

组件

组件化思想

单页面应用:框架一般适用于开发大型的单页面应用;整个项目只有一个页面,其他页面都是通过路由方式进行切换的;
组件:把相同功能的代码封装成一个组件,当想再次适用这个结构时,直接调用这个组件就可以,体现了代码的复用性。

如何创建组件:

  1. 全局组件
  2. 局部组件
  • VUE中的每一个组件都是一个小实例;每一个组件都有自己独立的生命周期

全局组件

在Vue的属性上一个component函数,执行可以创建一个组件,接收两个参数,第一个是组件的名字,第二个是组件的信息对象
注册一个全局组件,在页面中组件名和闭合标签的方式使用该组件:接收两个参数,第一个是组件名,第二个就是组件的信息;

VUE中的每一个组件都是一个小实例;
全局组件可以在任何的Vm实例中使用,每一个组件都相当于一个VUE的实例,当调用这个组件时,就会生成Vue的生命周期;每当使用一次,就会执行一遍生命周期钩子函数

  • 组件名
  1. 组件的名字-单词的首字母可以大写
  2. 页面中的组件的名字不支持驼峰,如果是驼峰,需要加-;
  3. 不能使用内置的标签名作为组件名称

组件.png

<body>
    <div id="app">
        <!-- <ZFPX></ZFPX> -->
        <hand-some></hand-some>
        <ul></ul>
    </div>
    <div id="app1">
        <!-- <zfpx></zfpx> -->
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        // 组件化思想
        // 单页面应用:框架一般适用于开发大型的单页面应用;整个项目只有一个页面,其他页面都是通过路由方式进行切换的;
        // 组件:把相同功能的代码封装成一个组件,当想再次适用这个结构时,直接调用这个组件就可以,体现了代码的复用性。

        // 如何创建组件: 1. 全局组件   2. 局部组件
        // 在Vue的属性上一个component函数,执行可以创建一个组件,接收两个参数,第一个是组件的名字,第二个是组件的信息对象
        // 注册一个全局组件,在页面中组件名和闭合标签的方式使用该组件:接收两个参数,第一个是组件名,第二个就是组件的信息;
        // VUE中的每一个组件都是一个小实例;
        // 全局组件可以在任何的Vm实例中使用,每一个组件都相当于一个VUE的实例,当调用这个组件时,就会生成Vue的生命周期;每当使用一次,就会执行一遍生命周期钩子函数;

        // 1. 组件的名字-单词的首字母可以大写
        // 2. 页面中的组件的名字不支持驼峰,如果是驼峰,需要加-;
        // 3. 不能使用内置的标签名作为组件名称
        Vue.component("handsome",{
            data:function(){
                return {a:"今天有雨"}
            },
            created(){
                console.log(1);
            },
            methods:{
            },
            template:"<div>{{a}}</div>"
        });
        let vm = new Vue({
            el:"#app",
            data:{
               
            },
            methods:{
               
            }
        });
        let vm1 = new Vue({
            el:"#app1",
            data:{
               
            },
            methods:{
               
            }
        });
       
    </script>
</body>

局部组件

1.创建组件
2.局部注册组件
3.在组件定义中,data必须返回一个函数,并且函数返回一个对象,不能直接写对象
template: 模板 components : 组件
局部组件:只能在注册的vue实例中使用该组件,不能跨组件使用;但是可以另一个vue实例中再注册一次;

<body>
    <div id="app">
        <son></son>
    </div>
    <div id="app1">
        <span>111</span>
        <son></son>
    </div>
    <template id="son">
        <div @click='fn'>{{msg}}</div>
    </template>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        // 1.创建组件
        // 2.局部注册组件
        // 在组件定义中,data必须返回一个函数,并且函数返回一个对象,不能直接写对象
          // template: 模板  components : 组件
        // 局部组件:只能在注册的vue实例中使用该组件,不能跨组件使用;但是可以另一个vue实例中再注册一次;
        let  son = {
            data(){
                return {
                    msg:"hello"
                }
            },
            methods:{
                fn(){
                    console.log(this);// this 就指向了当前组件的实例
                    console.log("好好学习");
                }
            },
            template:"#son"
        }
        // template: 模板  components : 组件
        // 局部组件:只能在注册的vue实例中使用该组件,不能跨组件使用;但是可以另一个vue实例中再注册一次;
        let vm = new Vue({
            el:"#app",
            data:{
            },
            methods:{
            },
            components:{// 注册局部组件
                // 这个属性名和页面使用组件时名字一样;
                //child:son
                son
            }
        });
        let vm1 = new Vue({
            el:"#app1",
            data:{
            },
            methods:{
            },
            components:{// 注册局部组件
                son:son
            }
        });
    </script>
</body>

组件嵌套

组件嵌套: 组件和组件之间可以嵌套,但是子组件需要在父组件的components的属性中进行注册,才能在父组件中使用,在html结构中不能嵌套;
每一个组件都有自己独立的生命周期
先解析父组件,然后再解析子组件;

在mounted的钩子函数中,child先执行;挂载到parent组件上,最后parent一次性挂载到真实的DOM上;

<body>
    <div id="app">
        <parent> 
        </parent>
        
    </div>
    <div id="app1">
        <parent></parent>
    </div>
    <template id="parent">
        <div>
            <child></child>
            父组件1000
        </div>
    </template> 
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        // 1.创建组件
        // 2. 注册组件
        // 3. 使用组件: 用闭合标签的方式写在app结构中
        let  child = {
            data(){
                return {}
            },
            beforeMount(){
                console.log("child");
            },
            methods:{

            },
            template:"<div>子组件100</div>"
        };
        // 组件嵌套: 组件和组件之间可以嵌套,但是子组件需要在父组件的components的属性中进行注册,才能在父组件中使用,在html结构中不能嵌套;
        // 每一个组件都有自己独立的生命周期
        // 先解析父组件,然后再解析子组件;
        // 在mounted的钩子函数中,child先执行;挂载到parent组件上,最后parent一次性挂载到真实的DOM上;
        let parent  ={
            data(){
                return {}
            },
            beforeMount(){
                console.log("parent");
            },
            components:{
                child
            },
            template:"#parent"
        }
        Vue.component("parent",{
            template:"<div>111</div>"
        })
        let vm = new Vue({
            el:"#app",
            data:{
            },
            methods:{
            },
            components:{
                parent
            }
        });
        let vm1 = new Vue({
            el:"#app1",
            data:{
            },
            methods:{
            }
        });
        
    </script>
</body>

数据传递–>VueX(store)

组件: 组件就是抽离的公共的部分,这个公共的部分可以有自己独立的html,css,js
实现复用:可复用,可维护

数据传递: vue中数据传递有哪些方式?

组件之间信息传递.jpg

Vue是单项数据流,当父组件的数据发生更改,如果子组件也使用了父组件的数据,那么子组件也会随着更新;如果改变子组件这个数据,那么父组件不能更改;

  1. 父传子(props) props props=[“a”] :a=“num”
  2. 子传父(自定义事件)
    @change=‘num’ this.$emit(“change”,1000)
    .sync修饰符 :a.sync this.$emit(“updata:a”,2000)
  3. 兄弟组件(eventBus)
    let eventBus=new Vue eventBus.$on(事件池,方法) eventBus.$emit(事件池)
  4. VueX(store) 把每一个stroe注入到各个组件里 [state,mutations,actions,modules,getters]

vue的单向数据流(父=>子)

当父组件中的数据通过某些方法发生改变,更改了自己的数据,子组件如果使用到这个数据也会随着发生更改,父组件的数据流向了子组件,子组件也更新,这就是组件之间的数据传递的单向数据流
父组件==>子组件,但是子组件变化,不能引发父组件变化;

单向数据流.jpg

<body>
    <div id="app">
        <span>{{num}}</span>
        <button @click="add"></button>
        <child :m="num"></child>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        // 当父组件中的数据通过某些方法发生改变,更改了自己的数据,
      子组件如果使用到这个数据也会随着发生更改,父组件的数据流向了子组件,子组件也更新,
	这就是组件之间的数据传递的单向数据流
        // 父组件==>子组件,但是子组件变化,不能引发父组件变化;
        let child = {
            data() {
                return {}
            },
            methods: {
                fn() {
                    // this ==> 组件的实例
                    //组件的methods中的方法中的this,也指向这个组件实例
                    //console.log(this.m);
                    this.m--;
                }
            },
            beforeUpdate() {
                console.log("child beforeUpdate");
            },
            updated() {
                console.log("child updated");
            },
            props: ["m"], // props继承过来的属性也会放在这个组件的实例上
            template: "<div>{{m}}<button @click='fn'>反对</button></div>"
        };
        let vm = new Vue({
            el: "#app",
            data: {
                num: 100
            },
            methods: {
                add() {
                    this.num++;
                }
            },
            components: {
                child
            },
            beforeUpdate() {
                console.log("parent beforeUpdate");
            },
            updated() {
                console.log("parent updated");
            },
        });
        //   父组件数据更新时:
        //parent beforeUpdate==child beforeUpdate ==> child updated==> parent  updated    
    </script>
</body>

组件之间数据传递(父=>子)

数组传递

  1. 把父组件的数据以动态属性的方式放在当前子组件的行间属性上
  2. 在子组件中用props接收到这个属性 (数组、对象)
  3. 在子组件取值使用动态的属性名取值
<body>
    <div id="app">
        <input type="text" v-model="msg">
        <!-- <div :c="msg"></div> -->
        <child :a="msg"></child>
        <child :b="book"></child>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        // child 是Vm这个vue实例的子组件;判断组件在哪个实例中注册,就是谁的子组件;
        // 数组传递
        // 1. 把父组件的数据以动态属性的方式放在当前子组件的行间属性上
        // 2. 在子组件中用props接收到这个属性 (数组、对象)
        // 3. 在子组件取值使用动态的属性名取值
        let  child = {
            data(){
                return {
                    // msg:"abc"
                }
            },
            props:["a","b"],// props:和行间属性名的属性名保持一致
            template:"<div>{{a}}{{b}}</div>"// 取值和props保持一致
        };
        let vm = new Vue({
            el:"#app",
            data:{
                msg:"hello",
                book:"vue.js"
            },
            methods:{
            },
            components:{
                child
            }
        });
    </script>
</body>

props的验证

props: {
a: {
type: [Number], // 对传递过来的数据进行校验,验证不满足则跑出警告
//required:true,// 这是一个必须传递的值
default: 200, // 这是一个默认值 子组件属性名a对应的属性值不传默认为200
required: true, //必传项 设置为这是一个必须传递的值,子组件属性名a对应的属性值必传
validator(val) { // val 就是传递过来的值
//这个函数返回一个布尔值;如果返回true,说明这个值没有问题,如果返回false;那么会抛出异常
console.log(val);
return val < 100 && val > 10;
}
}
}

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <div id="app">

        <child :a="msg"></child>

    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        let child = {
            data() {
                return {}
            },
            props: {
                a: {
                    type: [Number], // 对传递过来的数据进行校验,验证不满足则跑出警告
                    //required:true,// 这是一个必须传递的值
                    default: 200, // 这是一个默认值 子组件属性名a对应的属性值不传默认为200
                    required: true, //必传项  设置为这是一个必须传递的值,子组件属性名a对应的属性值必传
                    validator(val) { // val 就是传递过来的值
                        //这个函数返回一个布尔值;如果返回true,说明这个值没有问题,如果返回false;那么会抛出异常
                        console.log(val);
                        return val < 100 && val > 10;
                    }
                }
            },
            template: "<div>{{a}}</div>" //取值和props的属性名保持一致
        };
        let vm = new Vue({
            el: "#app",
            data: {
                msg: "60",
                book: "vue.js"
            },
            methods: {},
            components: {
                child
            }
        });
    </script>
</body>

</html>

子=>父(数据传递)

props: [“a”, “b”], //props接收到的属性也会放到组件实例上一份
methods: {
add() {
// this==> 组件的实例
// 子组件不能直接修改父组件的数据
// $emit : 用来发布自定义事件
// 自定义的名称必须小写
// 1.直接调取父亲(实例)上的方法
// vm.money++ // 这样改粗暴
// 2.v-bind:b 绑定事件
// this.b();

// 3, e m i t : t h i s . emit:用来可以发布自定义事件 this. emit(“changemoney”, 1080);
}
},

<body>
    <div id="app">
        父亲:{{money}} <button @click="fn1">少给点</button>
        <br></br>
        <!-- 自定义事件 @  订阅-->
        <son :a="money" @changemoney="fn2" :b="fn2"></son>
    </div>

    <!--  IMPORT JS -->
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        //创建Vue实例
        // 组件的数据传递  
        // 父传子  子传父  兄弟组件之间的传递
        let son = {
            data() {
                return {

                }
            },
            props: ["a", "b"], //props接收到的属性也会放到组件实例上一份
            methods: {
                add() {
                    // this==> 组件的实例  
                    // 子组件不能直接修改父组件的数据
                    // $emit : 用来发布自定义事件
                    // 自定义的名称必须小写

                    // 1.直接调取父亲(实例)上的方法
                    // vm.money++  // 这样改粗暴 
                    // 2.v-bind:b 绑定事件
                    // this.b();
                  
                    // 3,$emit:用来可以发布自定义事件
                    this.$emit("changemoney", 1080);
                }
            },
            template: "<div>儿子:{{a}}<button @click='add'>多要点</button></div>"
        }
        let vm = new Vue({
            el: '#app',
            data: {
                money: 888
            },
            methods: {
                fn1() {
                    this.money--
                },
                fn2(val) {
                    console.log(val);
                    
                    this.money++
                }
            },
            components: {
                son
            },
        });
    </script>
</body>

.sync修饰符

<son :a.sync=“money” :v.sync=“val”>
下面: this.$emit(“update:a”, );

<body>
    <div id="app">
        父亲:{{money}} <button>少给点</button>
        <br></br>
        <!-- 自定义事件 @  订阅-->
        <!-- $event 接收的是$emit的第二个参数  
             @updata  @updaa:m  名字随便起
            -->
        <!-- <son :a="money" @update:a="money+=$event"></son> -->
        
        <son :a.sync="money" :v.sync="val"></son>
        <!-- 下面不可以改: this.$emit("update:a", 2000); -->
    </div>

    <!--  IMPORT JS -->
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        //语法糖
        let son = {
            data() {
                return {

                }
            },
            props: ["a", "b", "v"],
            methods: {
                add() {
                    this.$emit("update:a", 2000);
                    this.$emit("update:v", 8899);
                }
            },
            template: "<div>儿子:{{a}}<button @click='add'>多要点</button></div>"
        }
        let vm = new Vue({
            el: '#app',
            data: {
                money: 888,
                val: 555
            },
            methods: {

            },
            components: {
                son
            },
        });
    </script>
</body>

兄弟组件之间数据传递

兄弟之间的组件数据传递:eventBus;
$on : 订阅
$emit : 发布;轮询对应的事件池,让其中的方法执行
let eventBus = new Vue; // 这就是一个容器;联系了兄弟之间的纽带
created() {
eventBus.KaTeX parse error: Expected 'EOF', got '}' at position 49: …n) }̲, methods: { …emit(‘changeRed’);
},
},

<body>
    <div id="app">
        <bro1></bro1>
        <bro2></bro2>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        // 兄弟之间的组件数据传递:eventBus;
        // $on : 订阅
        // $emit : 发布;轮询对应的事件池,让其中的方法执行
        let eventBus = new Vue; // 这就是一个容器;联系了兄弟之间的纽带
        let bro1 = {
            data() {
                return {
                    color: "红色"
                }
            },
            created() {
                eventBus.$on("changeGreen", this.changeGreen)
            },
            methods: {
                fn1() {
                    eventBus.$emit('changeRed');
                },
                changeGreen() {
                    this.color = "绿色"
                }
            },
            template: "<div>{{color}}<button @click='fn1'>变红</button></div>"
        };
        let bro2 = {
            data() {
                return {
                    color: "绿色"
                }
            },
            created() {
                eventBus.$on("changeRed", this.changeRed)
            },
            methods: {
                changeRed() {
                    this.color = "红色";
                },
                fn2() {
                    eventBus.$emit('changeGreen');
                }
            },
            template: "<div>{{color}}<button @click='fn2'>变绿</button></div>"
        };

        let vm = new Vue({
            el: "#app",
            data: {},
            components: {
                bro1,
                bro2
            }
        })
    </script>
</body>

爷=>孙(数据传递)

父子props
祖先元素传递子孙元素的数据
a t t r s attrs: 把行间属性放在一个对象上,传给孙子组件的 attrs属性 $listeners :方法

atters.png

<body>
    <div id="app">
        <child :val="a" name="北京" age="10" @click="()=>{this.a=888}"></child>
    </div>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        // 父子props  
        // 祖先元素传递子孙元素的数据
        // $attrs: 把行间属性放在一个对象上,传给孙子组件的$attrs属性  $listeners :方法
        let grandson = {
            template: "<div>{{$attrs}}==={{$attrs.name}}<button @click='$listeners.click()'>
      </button></div>"
        }
        let child = {
            data() {
                return {}
            },
            components: {
                grandson
            },
            // props:["val"],
            template: "<div>{{val}}<grandson v-bind='$attrs' v-on='$listeners'>
      </grandson></div>"
        }
        let vm = new Vue({
            el: "#app",
            data: {
                a: 100
            },
            components: {
                child
            }
        })
    </script>
</body>

插槽:slot

slot:内置的组件:可以将父组件中的子组件里面的模板数据进行显示

<body>
    <div id="app">
        {{msg}}
        <h2>这是父组件</h2>
        <child>
            {{msg}}
            <div>菜单一</div>
            <div>菜单二</div>
            <div>菜单三</div>
        </child>
    </div>
    <template id="child">
        <div>
            
            <slot></slot>
            <h2>这是子组件</h2>
            {{msg}}
            <!-- slot:内置的组件:可以将父组件中的子组件里面的模板数据进行显示 -->
        </div>
    </template>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        let  child = {
            data(){
                return {
                    msg:"world"
                }
            },
            template:"#child"
        }
        let vm = new Vue({
            el:"#app",
            data:{
                msg:"hello"
            },
            components:{
                child
            }
        })
    </script>
</body>

具名插槽

  • slot:内置的组件:可以将父组件中的子组件里面的模板数据进行显示
  • slot属性值和子组件中slot插槽中的name属性对应
  • 没有name属性的slot会解析默认的标签
  • 子组件的slot组件上的name属性会和父组件中的slot属性进行匹配,并按照子组件的顺序显示对应的模板数据
<body>
    <div id="app">
        <h2>这是父组件</h2>
        <child>
            <!-- // slot属性值和子组件中slot插槽中的name属性对应 -->
            <div slot="first">菜单一</div>
            <div>菜单二</div>
            <div>菜单三</div>
        </child>
    </div>
    <template id="child">
        <div>
            <h2>这是子组件</h2>
            <!-- 没有name属性的slot会解析默认的标签 -->
            <slot></slot>
            <!-- 子组件的slot组件上的name属性会和父组件中的slot属性进行匹配,
并按照子组件的顺序显示对应的模板数据 -->
            <slot name="first"></slot>
            <!-- slot:内置的组件:可以将父组件中的子组件里面的模板数据进行显示 -->
        </div>
    </template>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        let  child = {
            data(){
                return {
                    msg:"world"
                }
            },
            template:"#child"
        }
        let vm = new Vue({
            el:"#app",
            data:{
                msg:"hello"
            },
            components:{
                child
            }
        })
    </script>
</body>

作用域插槽

  • 能够让父组件使用子组件中的组件
  • slot-scope 作用域插槽,可以让我们在父组件这个位置获取到组件的数据

<child>
<div slot-scope="{user}">{{user}}
<div slot-scope=“abc”>{{abc.user}}
</child>

<template id=“child”>
<div>
<h2>这是子组件</h2>
<slot :user=“msg”></slot>
</div>
</template>

<body>
    <div id="app">
        <h2>这是父组件</h2>
        <child>
            <!-- slot-scope  作用域插槽,可以让我们在父组件这个位置获取到组件的数据 -->
            <div slot-scope="{user}">{{user}}</div>
            <div slot-scope="abc">{{abc.user}}</div>
        </child>
    </div>
    <template id="child">
        <div>
            <h2>这是子组件</h2>
            <slot :user="msg"></slot>
    </template>
    <script src="../node_modules/vue/dist/vue.js"></script>
    <script>
        // 能够让父组件使用子组件中的组件
        let child = {
            data() {
                return {
                    msg: "world"
                }
            },
            template: "#child"
        }
        let vm = new Vue({
            el: "#app",
            data: {
                msg: "hello"
            },
            components: {
                child
            }
        })
    </script>
</body>

组件内的render方法

        Vue.component('my',{
            // template:"<div></div>"
            // render(h){
            //     // h==> 函数
            //     // h:第一个参数可以标签名  对象:行间属性   标签的文本内容
            //     //console.log(h("h1",{class:"bar",a:1},"hello",{c:1}));
            //     // 这个函数就会返回一个虚拟的DOM,那么vue再将这个虚拟的DOM转成
          真实的DOM放在页面上
            //     //console.log(h);
            //     return h("h1",{class:"bar",attrs:{id:100}},"hello");
            // }
            template:"<div>{{msg}}</div>"
        })
发布了51 篇原创文章 · 获赞 13 · 访问量 3052

猜你喜欢

转载自blog.csdn.net/Sheng_zhenzhen/article/details/104663525
今日推荐