7

vue.js学习笔记六

 3 years ago
source link: https://blog.csdn.net/weixin_46334272/article/details/117453235
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一、全局组件和局部组件

  • 当我们通过调用Vue.component()注册组件时,组件的注册是全局的
  • 这意味着该组件可以在任意Vue示例下使用
  • 如果我们注册的组件是挂载在某个实例中,那么就是一个局部组件
    <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: {
                // cpn使用组件时的标签名
                cpn: cpnC
            }
        })

        const app2 = new Vue({
            el: '#app2'
        })
    </script>

二、父组件和子组件

  • 在前面我们看到了组件树
  • 组件和组件之间存在层级关系
  • 而其中一种非常重要的关系就是父子组件的关系
  • 父子组件错误用法:以子标签的形式在Vue实例中使用
  • 因为当子组件注册到父组件的components时,Vue会编译好父组件的模块
  • 该模板的内容已经决定了父组件将要渲染的HTML(相当于父组件中已经有了子组件中的内容了)
  • <child-cpn></child-cpn>是只能在父组件中被识别的
  • 类似这种用法, <child-cpn></child-cpn>是会被浏览器忽略的

在这里插入图片描述

 <div id="app">
        <cpn2></cpn2>
        <!--<cpn1></cpn1>-->
        <!-- 会被浏览器忽略的 -->
    </div>
    <script src="../js/vue.js"></script>
    <script>
        // 1.创建第一个组件构造器(子组件)
        const cpnC1 = Vue.extend({
                template: `
      <div>
        <h2>我是标题1</h2>
        <p>我是内容, 哈哈哈哈</p>
      </div>
    `
            })
            // 2.创建第二个组件构造器(父组件)
        const cpnC2 = Vue.extend({
            template: `
      <div>
        <h2>我是标题2</h2>
        <p>我是内容, 呵呵呵呵</p>
        <cpn1></cpn1>
      </div>
    `,
            components: {
                cpn1: cpnC1
            }
        })

        // root组件
        const app = new Vue({
            el: '#app',
            data: {
                message: '你好啊'
            },
            components: {
                cpn2: cpnC2
            }
        })
    </script>



三、注册组件语法糖

  • 在上面注册组件的方式,可能会有些繁琐
  • 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", {
            template: `
            <div>
              <h2>我是标题1</h2>
              <p>我是内容,哈哈哈哈</p>
            </div>
        `
        })

        //2.注册局部组件的语法糖
        const app = new Vue({
            el: "#app",
            data: {
                message: "你好啊"
            },
            components: {
                "cpn2": {
                    template: `
                <div>
                  <h2>我是标题2</h2>
                  <p>我是内容,hhehe1</p>
                </div>`
                }
            }
        })
    </script>



四、模板的分离写法

  • 刚才,我们通过语法糖简化了Vue组件的注册过程,另外还有一个的写法比较麻烦,就是template模板写法
  • 如果我们能将其中的HTML分离出来写,然后挂载到对应的组件上,必然结构会变得非常清晰
  • Vue提供了两种方案来定义HTML模板内容:
  • 使用<script>标签
  • 使用<template>标签
    在这里插入图片描述
    在这里插入图片描述
    <div id="app">
        <cpn></cpn>
        <cpn></cpn>
        <cpn></cpn>
    </div>

    <!-- 1.第一种方法script标签,注意:类型必须是text/x-template -->
    <!-- <script type="text/x-template" id="cpn"></script> -->
    <!-- <div>
        <h2>我是标题</h2>
        <p>我是内容,hhhh</p>
    </div>
  </script> -->

    <!-- 2.第二种方法:template标签 -->
    <template id="cpn">
      <div>
        <h2>我是标题</h2>
        <p>我是内容,呵呵呵</p>
      </div>
    </template>

    <script src="../js/vue.js"></script>
    <script>
        // 1.注册一个全局组件
        Vue.component('cpn', {
            template: '#cpn'
        })

        const app = new Vue({
            el: '#app',
            data: {
                message: '你好啊'
            }
        })
    </script>



五、组件可以访问Vue实例数据吗?

  • 组件是一个单独功能模块的封装:
  • 这个模块有属于自己的HTML模板,也应该有属性自己的数据data
  • 组件中的数据是保存在哪里呢?顶层的Vue实例中吗?
  • 我们先来测试一下,组件中能不能直接访问Vue实例中的data

解析:组件去访问message,message定义在Vue,我们发现最终并没有显示结果
结论:组件是不能直接访问Vue实例中的data数据

在这里插入图片描述


六、组件数据的存放

  • 组件自己的数据存放在哪里呢?
  • 组件对象也有一个data属性(也可以有methods等属性,下面我们会用到)
  • 只是这个data属性必须是一个函数
  • 而且这个函数返回一个对象,对象内部保存着数据
    <div id="app">
        <cpn></cpn>
        <cpn></cpn>
        <cpn></cpn>
    </div>

    <!--1.script标签, 注意:类型必须是text/x-template-->
    <!--<script type="text/x-template" id="cpn">-->
    <!--<div>-->
    <!--<h2>我是标题</h2>-->
    <!--<p>我是内容,哈哈哈</p>-->
    <!--</div>-->
    <!--</script>-->

    <!--2.template标签-->
    <template id="cpn">
    <div>
      <h2>{{title}}</h2>
      <p>我是内容,呵呵呵</p>
    </div>
  </template>

    <script src="../js/vue.js"></script>
    <script>
        //1.注册一个全局事件
        Vue.component("cpn", {
            template: "#app",
            data() {
                return {
                    title: "abc"
                }
            }
        })
        const app = new Vue({
            el: "#app",
            data: {
                message: "你好啊",
            }
        })
    </script>

在这里插入图片描述

在这里插入图片描述

七、为什么data是一个函数呢?

  • 为什么data在组件中必须是一个函数呢?
  • 首先,如果不是一个函数,Vue直接就会报错
  • 其次,原因是在于Vue让每个组件对象都返回一个新的对象,因为如果是同一个对象的,组件在多次使用后会相互影响
    <!--组件实例对象-->
    <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() {
            //     return {
            //         counter: 0
            //     }
            // },
            data() {
                return obj
            },
            methods: {
                increment() {
                    this.counter++
                },
                decrement() {
                    this.counter--
                }
            }
        })
        const app = new Vue({
            el: '#app',
            data: {
                message: '你好啊'
            }
        })
    </script>

    <script>
        // const obj = {
        //   name: 'why',
        //   age: 18
        // }
        //
        // function abc() {
        //   return obj
        // }
        //
        // let obj1 = abc()
        // let obj2 = abc()
        // let obj3 = abc()
        //
        // obj1.name = 'kobe'
        // console.log(obj2);
        // console.log(obj3);
    </script>

在这里插入图片描述


八、父子组件的通信

  • 在上一个小节中,我们提到了子组件是不能引用父组件或者Vue实例的数据的
  • 但是,在开发中,往往一些数据确实需要从上层传递到下层:
  • 比如在一个页面中,我们从服务器请求到了很多的数据
  • 其中一部分数据,并非是我们整个页面的大组件来展示的,而是需要下面的子组件进行展示
  • 这个时候,并不会让子组件再次发送一个网络请求,而是直接让大组件(父组件)将数据传递给小组件(子组件)

在这里插入图片描述

  • 如何进行父子组件间的通信呢?
  • 通过props向子组件传递数据
  • 通过事件向父组件发送信息

在下面的代码中,会将Vue实例当做父组件,并且其中包含子组件来简化代码
真实的开发中,Vue实例和子组件的通信父组件和子组件的通信过程是一样的


九、props基本用法

  • 在组件中,使用选项props来声明需要从父级接收到的数据
  • props的值有两种方式:
  • 方式一:字符串数组,数组中的字符串就是传递时的名称
  • 方式二:对象,对象可以设置传递时的类型,也可以设置默认值等
  • 我们先来看一个最简单的props传递

在这里插入图片描述


十、props数据验证

  • 在前面,我们的props选项是使用一个数组
  • 除了数组之外,我们也可以使用对象,当需要对props进行类型等验证时,就需要对象写法了
  • 验证都支持哪些数据类型呢?
    String
    Number
    Boolean
    Array
    Object
    Date
    Function
    Symbol
   <script>
        Vue.component("my-component", {
            props: {
                //基础的类型检查(`null`匹配任何类型)
                propA: Number,
                //多个可能的类型
                propB: [String, Number],
                //必填的字符串
                propC: {
                    type: String,
                    required: true
                },
                //带有默认值的数字
                propD: {
                    type: Number,
                    default: 100
                },
                //带有默认值的对象
                propE: {
                    type: Object,
                    //对象或数组默认值必须从一个工厂函数获取
                    default: function() {
                        return {
                            message: "hello"
                        }
                    }
                },
                //自定义验证函数
                propF: {
                    validator: function(value) {
                        //这个值必须匹配下列字符串中的一个
                        return ["success", "warning", "danger"].indexOf(value) !== -1
                    }
                }
            }
        })
    </script>
  • 当我们有自定义构造函数时,验证也支持自定义的类型
<script>
        function Person(firstName, lastName) {
            this.firstName = firstName;
            this.lastName = lastName
        }
        Vue.component("blog-post", {
            props: {
                author: Person
            }
        })
    </script>



十一、子级向父级传递

  • props用于父组件向子组件传递数据,还有一种比较常见的是子组件传递数据或事件到父组件中
  • 这个时候,我们需要使用自定义事件来完成
  • 什么时候需要自定义事件呢?
  • 当子组件需要向父组件传递数据时,就要用到自定义事件了
  • 自定义事件的流程:
  • 在子组件中,通过$emit()来触发事件
  • 在父组件中,通过v-on来监听子组件事件

  • 我们来看一个简单的例子
  • 之前做过的那个两个按钮+1和-1,点击后修改counter
  • 整个操作的过程还是在子组件中完成,但是之后的展示交给父组件
  • 这样,我们就需要将子组件中的counter,传给父组件的某个属性,比如total

在这里插入图片描述

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

    <!--子组件模板-->
    <template id="cpn">
  <div>
    <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('item-click', item)
                }
            }
        }

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK