Vue之组件

64 阅读2分钟

知识点

  • 组件注册
  • 组件复用
  • 组件通信
  • 动态组件
  • 实例生命周期
  • 生命周期示意图

组建注册

全局注册

Vue.component(组件名字,template:{元素标签})

<body>
    <div id="app">
        <syl></syl>
        <syl></syl>
    </div>
    <script>
            Vue.component("syl",{template:"<h1>实验室全局组件</h1>"});
            var app = new Vue({
                el:"#app",
            });
    </script>
</body>

运行效果

image-20230320105329835.png

局部组件

在父级的components对象中声明,局部组件只有它的父级才能调用。

<body>
    <div id="app">
        <syl></syl>
        <syl></syl>
        <div id="father">
            <child></child>
        </div>
        <!-- 不是父组件无法调用 -->
        <child></child>
    </div>
    
    <script>
            // 声明子组件
            var childComponent = {
                template:"<h2>我们是子组件,只有父组件才能调用</h2>"
            };
            var app = new Vue({
                el:"#app",
            });
            var father = new Vue({
                el:"#father",
                // 子组件必须先声明后使用,不然不起效,记住是components
                components:{
                    "child": childComponent,
                },
            });
    </script>
</body>

组件复用

组件的优点就在于能够复用,一次代码编写,整个项目受用。

注意: 复用组件内的 data 必须是一个函数,如果是一个对象(引用类型),组件与组件间会相互影响,组件数据不能独立管理。

    <div id="app">
        <button-counter></button-counter>
        <button-counter></button-counter>
        <button-counter></button-counter>
    </div>
    <script>
           Vue.component("button-counter",{
            data(){
                return{
                    counter:0,
                };
            },
            template:'<button @click="counter++">{{counter}}</button>',     
           });
           var app = new Vue({
            el:"#app",
           });
    </script>

组件间通信

父子组件之 props

只允许父组件向子组件传值

传值类型:数值、字符、布尔值、数值、对象

子组件需要显式地用 props 选项声明 "prop",告诉使用者需要传入什么数据

注意:HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 需要使用其等价的 kebab-case (短横线分隔命名) 命名

个人理解:使用该模板的是父组件,子组件暴露出可传入的值,由父组件传入

注意:

所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。

另外,每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,这意味着你不应该在子组件中去更改一个 prop。若你这么做了,Vue 会在控制台上向你抛出警告:

export default {
  props: ['foo'],
  created() {
    // ❌ 警告!prop 是只读的!
    this.foo = 'bar'
  }
}

若子组件有更改需求,建议重新定义一个变量承接prop的值。

示例:

<body>
    <div id="app">
        //动态组件
        <blog-post v-for="post in posts"
                   :key="post.id"
                   :title="post.title">
        </blog-post>
    </div>
    <script>
        Vue.component("blog-post",{
            props:["title"],
            template:"<h1>{{title}}</h1>",
        });
        var app = new Vue({
            el:"#app",
            data(){
                return{
                    posts:[
                        { id: 1, title: 'My journey with Vue'},
                        { id: 2, title: 'Blogging with Vue'},
                        {id: 3, title: 'Why Vue is so fun'},
                    ]
                }
            }
        })
    </script>
</body>

props 类型检测

以对象形式列出 prop,这些属性的名称和值分别是 prop 各自的名称和类型

<body>
    <div id="app">
      <child-component
        id="1"
        title="hello syl"
        content="you are welcom"
      ></child-component>
    </div>
    <script>
      // 注册一个子组件
      Vue.component("child-component", {
        // props 对象形式,传递属性值 进行类型检测,在脚手架环境中很有用
        props: {
          id: Number,
          title: String,
          content: String,
        },
        // 使用 es6 模板字符串书写格式更优美
        template: `<div><p>id:{{id}}</p><p>title:{{title}}</p><p>content:{{content}}</p></div>`,
      });
      var app = new Vue({
        el: "#app",
      });
    </script>
  </body>

子父组件通信之 emit

子组件向父组件通信

这里要使用自定义事件 emit 方法,通过自定义事件来由下到上的数据流动。

语法如下:

this.$emit('自定义事件名',参数)
<div id="app">
        <child-component v-on:send-msg="getMsg">
        </child-component>
    </div>
    <script>
        // 1、定义一个子组件,template绑定click事件
        // 2、当click事件触发就使用emit自定义一个事件send-msg,传入参数“我是子组件请求与你通信”
        // $emit('send-msg','我是子组件请求与你通信')
        // 3、子组件标签绑定自定义事件send-msg,并绑定上父级的方法getMsg,即可完成了子父组件通信
        // <child-component v-on:send-msg="getMsg"></child-component>
        Vue.component("child-component",{
            template:`
            <button v-on:click="$emit('send-msg','我是子组件请求与你通信')">
                Click me
            </button>
            `,
        });
        var app = new Vue({
            el:"#app",
            methods:{
                getMsg:function(msg){
                    // 父组件的获取子组件消息的方法
                    alert(msg);
                }
            }
        });
    </script>

子组件向父组件数据传递套路:

第一步:子组件绑定事件。

第二步:子组件绑定事件触发,使用 $emit 创建自定义事件并传入需要传值给父组件的数据。

第三步:在子组件标签上 用 v-on 绑定自定义事件,在父组件中声明自定义事件处理的方法。

第四步:父组件方法,接受自定义事件传的参数,就完成了整个由下到上的数据流。

生命周期函数

//主要的生命周期函数	    
		beforeCreate() {
          alert(
            "在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用"
          );
        },
        created() {
          alert(
            "在实例创建完成后被立即调用,挂载阶段还没开始,$el 属性目前不可见"
          );
        },
        beforeMount() {
          alert("在挂载开始之前被调用:相关的 render 函数首次被调用");
        },
        mounted() {
          alert("el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子");
        },
        beforeUpdate() {
          alert("数据更新时调用");
        },
        updated() {
          alert("组件 DOM 已经更新");
        },
        beforeDestroy() {},
        destroyed() {},

这么多钩子函数我们经常主要用到有:

  1. created 钩子函数内我们可以进行异步数据请求。

    created() {
        fetch('url')
        .then(function(response) {
            console.log(response)
        })
    }
    
  2. mounted 我们可以直接操作元素 DOM 了,但是并不推荐这样做,不利于性能提升。

    <body>
        <div id="app">
          <div id="box" style="width:40px;background: tomato;">点击</div>
        </div>
        <script>
          var app = new Vue({
            el: "#app",
            data() {
              return {};
            },
            // div#box 开始并没有绑定事件,挂载后我们直接操作原生 dom
            mounted() {
              var box = document.querySelector("#box");
    
              box.addEventListener("click", function () {
                alert("我们挂载后 原生点击事件");
              });
            },
          });
        </script>
      </body>
    

    vue组件创建生命周期