Vue2(六):生命周期、组件、组件的嵌套、VueComponent构造函数、单文件组件

一、生命周期

1.什么是生命周期?

生命周期

1.又名:生命周期回调函数、生命周期函数、生命周期钩子。

2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。

3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。

4.生命周期函数中的this指向是vm 或 组件实例对象。

2、生命周期中的8个钩子

常用的生命周期钩子

1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。

2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

关于销毁Vue实例

1.销毁后借助Vue开发者工具看不到任何信息。

2.销毁后自定义事件会失效,但原生DOM事件依然有效(现在的版本好像也会失效)。(留个疑点,啥是自定义事件?啥是原生DOM事件?答:自定义事件就是定义在组件标签上的事件,是组件通信的一种方式,原生DOM事件就是类似onclick这种的)。销毁后所有的监视也没了

3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。

html 复制代码
   <!-- 准备一个容器 -->
    <div id="hello">
        <h1>欢迎来到{{n}}年代</h1>
        <button @click="add">点击n+1</button>
    </div>

    <script>
        const vm = new Vue({
            el: '#hello',
            data: {
                n: 1
            },
            methods: {
                add() {
                    this.n++;
                }
            },
            beforeCreate() {
                console.log('beforeCreate');
                console.log(this);
                // debugger;
            },
            created() {
                console.log('created');
            },
            beforeMount() {
                console.log('beforeMount');
            },
            mounted() {
                console.log('mounted');
            },
            beforeUpdate() {
                console.log('beforeUpdate');
            },
            updated() {
                console.log('updated');
            },
            beforeDestroy() {
                console.log('beforeDestroy');
            },
            destryed() {
                console.log('destryed');
            }
        })
    </script>

3.图解生命周期

4.小案例:字体闪烁,点击停止(销毁vm)

javascript 复制代码
<!-- 准备一个容器 -->
<div id="hello">
    <h1 :style="{opacity: opacity}">欢迎来到90年代</h1>
    <button @click="stop">点击停止闪烁</button>
</div>

<script>
    const vm = new Vue({
        el: '#hello',
        data: {
            opacity: 1
        },
        methods: {
            stop() {
                // clearInterval(this.timer);  vm自杀可以这么写,他杀需要写在beforeDestroy中
                this.$destroy();  //vm自杀
            }
        },
        //挂载意思就是放在页面上
        //挂载函数,Vue完成模板的解析并把*初始的(只调用一次)*真实DOM放入页面后(完成挂载)调用mounted
        mounted() {
            this.timer = setInterval(() => {
                console.log('计时器调用');
                this.opacity -= 0.01;
                if (this.opacity <= 0) this.opacity = 1;  //js里玩儿小数一般碰不到0 
            }, 16)
        },

        beforeDestroy() {
            console.log('vm即将被销毁');
            // 为什么vm的后事需要写在这里,是因为vm很有可能是被别人干掉的
            clearInterval(this.timer);
        },

    })

    //通过外部的定时器实现(不推荐)
    // setInterval(() => {
    //     vm.opacity -= 0.01;
    //     if (vm.opacity <= 0) vm.opacity = 1;  //js里玩儿小数一般碰不到0
    // }, 16);
</script>

下面这个不知道为什么点击停止变换之后,在点击透明度变1没有反应?

html 复制代码
    <div id="root">
        <h2 :style="{opacity}">你好我饿了</h2>
        <button @click="opacity = 1">透明度变1</button>
        <button @click="stop">点击停止变换</button>
    </div>
</body>
<script>
    const vm = new Vue({
        el:'#root',
        data:{
            opacity:1
        },
        methods:{
            stop(){
                this.$destroy()
            }
        },
        mounted(){
            // Vue完成模板的解析并把真实的DoM元素放入页面后(挂载完毕)调用mounted
            this.timer = setInterval(() => {
            this.opacity -= 0.01
            if(this.opacity <= 0) this.opacity=1
            },16)
        },
        beforeDestory(){
            clearInterval(this.timer)
            console.log('vm即将驾鹤西游');
        },
    })
</script>

二、使用组件 的三大步骤

1、定义组件(创建组件)

2、注册组件

3、使用组件(写组件标签)

1、如何定义一个组件?

使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;

区别如下:

(1)el不要写,为什么?

最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。备注:使用template可以配置组件结构。

(2)data必须写成函数,为什么?

避免组件被复用时,数据存在引用关系,比如我父组件要多次复用一个子组件,那如果其中一个子组件做了修改数据操作,其他复用的地方数据也会被修改。看看下面的代码,就明白了

html 复制代码
 //1.data定义为对象,里面的值有人一改,那全都用到底地方都改了
    let data = { a: 1, b: 2 };
    let x = data;   //如果x.a = 10 ,那么y也会变成{ a: 10, b: 2 }
    let y = data;

    //2.data定义为函数,里面的值有人改,其他用到的地方不变(每次用到都会返回一个全新的)
    let data1 = function () {
        return { a1: 1, b1: 2 };
    }
    let x1 = data1();  //如果x1.a1=10,那么y1还是{ a1: 1, b1: 2 }
    let y1 = data1();

2、如何注册组件?

(1)局部注册

靠new Vue的时候传入components选项

javascript 复制代码
   <!-- 准备一个容器 -->
    <div id="root">
        <xuexiao></xuexiao>
        <hr>
        <xuesheng></xuesheng>
    </div>

    <script>
        //第一步:创建school组件
        const school = Vue.extend({
        	name: 'dj', //可以使用name配置项指定组件在开发者工具中呈现的名字(只是开发者工具里用的名字)。
            // el: '#hello'  el不能写
            template: `
                <div>
                    <h2>学校名字{{schoolName}}</h2>
                    <h2>学校地址{{address}}</h2>
                </div>
            `,
            data() {
                return {
                    schoolName: 'web',
                    address: '杭州',
                }
            }
        })

        //第一步:创建student组件
        const student = Vue.extend({
            template: `
                <div>
                    <h2>学生名字{{studentName}}</h2>
                    <h2>学生年龄{{age}}</h2>
                    <button @click="add">点击年龄+1</button>
                </div>
            `,
            data() {
                return {
                    studentName: 'zzy',
                    age: 18
                }
            },
            methods: {
                add() {
                    this.age++;
                }
            },
        })

        //创建一个vm带领小弟接管root容器
        const vm = new Vue({
            el: '#root',
            // 第二步:注册组件(局部注册)
            components: {
                //组件名:组件
                //这里最好写成school:school,简写为school
                xuexiao: school,
                //这里最好写成student:student,简写为student
                xuesheng: student
            }
        })
    </script>

(2) 全局注册

Vue.component('组件名',组件)

javascript 复制代码
   <!-- 准备一个容器 -->
    <div id="root">
        <sayhello></sayhello>
    </div>

    <!-- 准备第二个容器 -->
    <div id="root2">
        <sayhello></sayhello>
    </div>

    <script>
        //第一步:创建组件
        const hello = Vue.extend({
            template: `
                <div>
                    <h2>{{msg}}</h2>
                </div>
            `,
            data() {
                return {
                    msg: 'hello world'
                }
            }
        })
        //第二步:全局注册组件
        Vue.component('sayhello', hello);

        //创建第一个vm接管root
        const vm = new Vue({
            el: '#root'
        })

        //创建第二个vm接管root2
        new Vue({
            el: '#root2'
        })
    </script>

3、编写组件标签

直接写组件名的标签就欧了,一般我们定义组件时,组件名和定义的名字最好一样,这样就可以简写。(详见2.(1)代码中的注释)

javascript 复制代码
   <!-- 准备一个容器 -->
    <div id="root">
        <xuexiao></xuexiao>
        <xuesheng></xuesheng>
    </div>

三、使用组件的一些注意点

1.关于组件名:

一个单词组成:

第一种写法(首字母小写):school

第二种写法(首字母大写):School

多个单词组成:

第一种写法(kebab-case命名):'my-school'

第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)

备注:

(1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。

(2).可以使用name配置项指定组件在开发者工具中呈现的名字(不影响注册的名字)。

2.关于组件标签:

第一种写法:<school></school>

第二种写法:<school/>

备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。

3.一个简写方式:

const school = Vue.extend(options) 可简写为:const school = options

三、组件的嵌套

(ps:一定要把组件的创建使用练习两遍,不然这里会很乱)

这里要注意,vm里要写el,其他都不写。vm里的template可以不用写根节点,因为vm里的东西是放到容器里的,而组件的template要用根节点包起来(如div)。这块儿就是一直套娃(代码倒着看)

html 复制代码
<body>
    <div id="root">
        <h1>{{msg}}</h1>
    </div>
</body>
<script>
    // 1、定义sudent组件
    const student = Vue.extend({
                template: `
            <div>
                <h2>学生姓名:{{name}}</h2>
                <h2>学生年龄:{{age}}</h2>
            </div>
        `,
                data() {
                    return {
                        name: '蛋糕',
                        age: '18'

                    }
                }
            })
    // 1、定义school组件
    const school = Vue.extend({
        template: `
            <div>
                <h2>学校名称:{{name}}</h2>
                <h2>学校地址:{{address}}</h2>
                <student></student>
            </div>
        `,
        data() {
            return {
                name: '椰果',
                address: '郑州'

            }
        },
        // 注册student组件
        components: {
            student
        }
    })
    // 1、定义hello组件
    const hello = Vue.extend({
        template:`<h1>{{msg}}</h1>`,
        data(){
            return {
                msg:'欢迎来到椰果学习'
            }
        }
    })
    // 1、定义app组件
    const app = Vue.extend({
        template:`
        <div>
            <school></school>
            <hello></hello>
        </div>
        `,
        components: {
            school,
            hello
        }
    })
    // 创建vm
    new Vue({
        template:`<app></app>`,
        el: '#root',
        // 2、注册school组件(局部)
        components: {
            app
        }
    })
</script>

四、VueComponent构造函数

school组件是一个Vue.extend生成的构造函数,当组件写到页面上时,Vue开始解析,同时自动搞了个new,这才创建了school组件的实例对象。

1.什么是VueComponent?

1、school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。

2、我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)。

3、特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent构造函数,而不是返回VueComponent的实例(这个地方不要陷入误区),只有当Vue解析组件时,才会返回所对应组件(如school)的VueComponent的实例对象

2.VueComponent中的this指向

VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。Vue的实例对象,以后简称vm。

(1)组件配置中
data函数、methods中的函数、watch中的函数、computed中的函数。它们的this均是【VueComponent实例对象】。
我这么理解,school组件是一个Vue.extend生成的构造函数,然后在这个extend里鱿鱼西还搞了个自动生成new,所以在页面使用组件时(Vue解析组件标签时)就顺便儿创建了school组件的实例对象,所以this指向Vc
(2)new Vue(options)配置中
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。

3.组件实例和Vue实例

其实这俩就像一对儿双胞胎,东西基本上99%都一样,但是这俩人不能划等号,还是有点小小的区别的,比如组件里不能写el,组件里data必须写成函数。vc有的vm都有,但是vm可以用el决定操作谁

4.一个重要的内置关系

这块儿听懂了,但是还差点事儿,这个图可以结合pink老师的图去理解,js高级抽空儿得补补。

1、一个重要的内置关系:VueComponent.prototype.proto === Vue.prototype

2、为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。

五、单文件组件

5、index.html

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>单文件组件</title>
</head>
<body>
    <div id="root">
        <App></App>
    </div>
    <script src="../js/vue.js"></script>
    <script src="./main.js"></script>
</body>
</html>

4、main.js

html 复制代码
import App from './App.vue'

new Vue({
    el: '#root',
    components: { App }
})

3、App.vue

javascript 复制代码
<template>
    <div>
        <School></School>
        <Student></Student>
    </div>
</template>

<script>
    // 引入组件
    import School from './School'
    import Student from './Student'
    export default {
        name:'App',
        components:{
            School,
            Student
        }
    }
</script>

<style>

</style>

2、Student.vue

html 复制代码
<!-- vetur插件 -->
<template>
    <div>
        <!-- 组件的结构 -->
        <h2>学生姓名:{{ name }}</h2>
        <h2>年龄:{{age }}</h2>
    </div>
</template>

<script>
// 组件交互相关 的代码(数据、方法等等)
export default {
    name: 'Student',
    data() {
        return {
            name: '椰果',
            age: 18
        }
    },
}
</script>
<!-- 如果没有样式也可以不写 -->

1、School.vue

html 复制代码
<!-- vetur插件 -->
<template>
    <div class="demo">
        <!-- 组件的结构 -->
        <h2>学校名称:{{ schoolName }}</h2>
        <h2>学校地址:{{ address }}</h2>
        <button @click="showName">点我提示学校名称</button>
    </div>
</template>

<script>
    // 组件交互相关 的代码(数据、方法等等)
    export default {
        name:'School',
        data() { 
            return { 
                schoolName: '尚硅谷',
                address: '北京昌平'
            }
        },
        methods:{ 
            showName(){ 
                alert(this.schoolName)
            }
        },
    }
</script>

<style>
    /* 组件的样式  */
    .demo {
        background-color: blue;
    }
</style>
相关推荐
有梦想的刺儿7 分钟前
webWorker基本用法
前端·javascript·vue.js
cy玩具27 分钟前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
qq_390161771 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test2 小时前
js下载excel示例demo
前端·javascript·excel
Yaml42 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事2 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶2 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo2 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v2 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript