前端之Vue:生命期钩子、组件、计算属性、全局局部组件、组件通信、ref属性、事件总线、动态组件和 keep-alive、插槽

目录

  • 一、 生命周期图
    • 官网原图
    • 注解的图
  • 二、 生命周期钩子函数
    • 测试代码
  • 三、 组件
    • 3.1 与后端交互的几种方式
      • 3.1.1 ajax使用
      • 3.1.2 fetch使用
      • 3.1.3 axios使用
    • 3.2 计算属性
      • 3.2.1 通过计算属性实现名字首字母大写
      • 3.2.2 通过计算属性重写过滤案例
    • 3.3 虚拟dom与diff算法 key的作用
    • 3.4 组件化开发基础
      • 3.4.1 组件化开发介绍
      • 3.4.2 注册全局组件
      • 3.4.3 注册局部组件
    • 3.5 组件通信
      • 3.5.1 组件通信之父传子
      • 3.5.2 组件通信之子传父(通过自定义事件)
      • 3.5.3 通过子传父控制字组件显示隐藏
    • 3.6 ref属性
    • 3.7 事件总线(不同层级的不通组件通信)
    • 3.8 动态组件和 keep-alive 使用
  • 四、 插槽

一、 生命周期图

官网原图

前端之Vue:生命期钩子、组件、计算属性、全局局部组件、组件通信、ref属性、事件总线、动态组件和 keep-alive、插槽_第1张图片

注解的图

前端之Vue:生命期钩子、组件、计算属性、全局局部组件、组件通信、ref属性、事件总线、动态组件和 keep-alive、插槽_第2张图片

二、 生命周期钩子函数

vue 的8个生命周期钩子函数

钩子函数 描述
beforeCreate 创建Vue实例之前调用
created 创建Vue实例成功后调用(可以在此处发送异步请求后端数据)
beforeMount 渲染DOM之前调用
mounted 渲染DOM之后调用
beforeUpdate 重新渲染之前调用(数据更新等操作时,控制DOM重新渲染)
updated 重新渲染完成之后调用
beforeDestroy 销毁之前调用
destroyed 销毁之后调用

create

let vm = new Vue()

mount
挂载,把div挂载到组件中
前端之Vue:生命期钩子、组件、计算属性、全局局部组件、组件通信、ref属性、事件总线、动态组件和 keep-alive、插槽_第3张图片
update

let vm = new Vue({
    el: '#box',
    data: {
        isShow: true    // 修改这个内容
    },
    methods: {
        handleClick() {
            console.log('我是根组件')
        }
    }
})

destroyed
组件销毁 - 给组件写一个定时器

setTimeout()    // 延迟3s干什么事
setInterval()    // 延迟3s干什么事

测试代码

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>生命周期title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js">script>
head>
<body>
<div id="box">
    <child v-if="isShow">child>
    <br>
    <button @click="terminate">删除子组件button>
    <button @click="reborn">显示子组件button>
div>
body>
<script>
    Vue.component('child', {
        template: `
            
{{name}}
`
, data() { return { name: 'Darker1', } }, beforeCreate() { console.group('当前状态:beforeCreate') console.log('当前el状态:', this.$el) console.log('当前data状态:', this.$data) console.log('当前name状态:', this.name) }, created() { console.group('当前状态:created') console.log('当前el状态:', this.$el) console.log('当前data状态:', this.$data) console.log('当前name状态:', this.name) }, beforeMount() { console.group('当前状态:beforeMount') console.log('当前el状态:', this.$el) console.log('当前data状态:', this.$data) console.log('当前name状态:', this.name) }, mounted() { console.group('当前状态:mounted') console.log('当前el状态:', this.$el) console.log('当前data状态:', this.$data) console.log('当前name状态:', this.name) //用的最多,向后端加载数据,创建定时器等 console.log("页面已被vue实例渲染, data, methods已更新"); console.log('mounted') this.t = setInterval(function () { console.log('daada') }, 3000) }, beforeUpdate() { console.group('当前状态:beforeUpdate') console.log('当前el状态:', this.$el) console.log('当前data状态:', this.$data) console.log('当前name状态:', this.name) }, updated() { console.group('当前状态:updated') console.log('当前el状态:', this.$el) console.log('当前data状态:', this.$data) console.log('当前name状态:', this.name) }, beforeDestroy() { console.group('当前状态:beforeDestroy') console.log('当前el状态:', this.$el) console.log('当前data状态:', this.$data) console.log('当前name状态:', this.name) }, destroyed() { console.group('当前状态:destroyed') console.log('当前el状态:', this.$el) console.log('当前data状态:', this.$data) console.log('当前name状态:', this.name) //组件销毁,清理定时器 clearInterval(this.t) this.t = null console.log('destoryed') }, }) let vm = new Vue({ el: '#box', data: { isShow: true }, methods: { terminate() { this.isShow = false }, reborn() { this.isShow = true } } })
script> html>

三、 组件

3.1 与后端交互的几种方式

1 向后端发送ajax请求

2 三种方式
    - 之前学过jq的ajax函数
        $.ajax({})
    - fetch:原生的,不需要导入js文件 (不是所有浏览器都支持,谷歌浏览器支持)
    - axios:vue中用的最多的

polyfill: https://github.com/camsong/fetch-ie8

3.1.1 ajax使用

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js">script>
    <script src="./js/vue.js">script>
head>
<body>

<div id="app">
   <div v-for="data in data_list">
       <h3>{{data.name}}h3>
       <img :src="data.poster" alt="">
       <h5>导演:{{data.director}}h5>
   div>

div>
body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            data_list: []
        },
        methods: {
            get_data() {
                //发送请求
                // let _this=this
                $.ajax({
                    url: 'http://127.0.0.1:5000/',
                    type: 'get',
                    success: (data) => {
                        let data_obj=JSON.parse(data)
                        // console.log(typeof data_obj)
                        this.data_list = data_obj.data.films
                    }
                    // success: function (data) {
                    //     // console.log(data)
                    //     _this.data_list = data
                    // }
                })
            }
        },
        mounted() {
            this.get_data()
        },
    })
script>
html>
from flask import Flask, make_response
​
app = Flask(__name__)
​
​
@app.route('/')
def index():
    res = make_response('hello world')
    # 运行所有域向我发请求(解决跨域问题)
    res.headers['Access-Control-Allow-Origin']='*'
    return res
​
​
if __name__ == '__main__':
    app.run()

3.1.2 fetch使用

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="./js/vue.js">script>
head>
<body>

<div id="app">
    <div v-for="data in data_list">
        <h3>{{data.name}}h3>
        <img :src="data.poster" alt="">
        <h5>导演:{{data.director}}h5>
    div>

div>
body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            data_list: []
        },
        methods: {
            get_data() {
                //发送请求
                fetch("http://127.0.0.1:5000/").then(res => res.json()).then(res => {
                    console.log(res.data.films)
                    this.data_list = res.data.films
                })

            }
        },
        mounted() {
            this.get_data()
        },
    })
script>
html>

3.1.3 axios使用

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="./js/vue.js">script>
    <script src="https://unpkg.com/axios/dist/axios.min.js">script>
head>
<body>

<div id="app">
    <div v-for="data in data_list">
        <h3>{{data.name}}h3>
        <img :src="data.poster" alt="">
        <h5>导演:{{data.director}}h5>
    div>

div>
body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            data_list: []
        },
        methods: {
            get_data() {
                //发送请求
                // axios.get('http://127.0.0.1:5000/').then(res => {
                //     // res.data才是真正后端返回的响应体中的内容
                //         console.log(res.status)
                //     this.data_list = res.data.data.films
                //
                // })
                axios({
                    url: 'http://127.0.0.1:5000/',
                    methods: 'get',

                }).then(res => {
                    // res.data才是真正后端返回的响应体中的内容
                    console.log(res.status)
                    this.data_list = res.data.data.films

                })

            }
        },
        mounted() {
            this.get_data()
        },
    })
script>
html>

3.2 计算属性

计算缓存 VS methods-计算属性是基于它们的依赖进行缓存的。
				  -计算属性只有在它的相关依赖发生改变时才会重新求值

计算属性优点
1 在同一个页面中使用多次计算属性,不会多次执行
2 不需要加括号,直接使用

3.2.1 通过计算属性实现名字首字母大写

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="./js/vue.js">script>
head>
<body>

<div id="app">
    <input type="text" v-model='name'>
    <br>
    您输入的是:{{get_name()}}
    <br>
    您输入的是2:{{get_name()}}

    <hr>


    <br>
     计算属性:您输入的是:{{upper_name}}
    <br>
     计算属性2:您输入的是:{{upper_name}}
div>
body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            name:''
        },
        computed:{

            upper_name(){
                console.log('计算属性我执行了')
                return this.name.substring(0,1).toUpperCase()+this.name.substring(1)
            },
        },
        methods:{
            get_name(){
                console.log('get_name我执行了')
                return this.name.substring(0,1).toUpperCase()+this.name.substring(1)
            },
        }

    })
script>
html>

3.2.2 通过计算属性重写过滤案例

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="./js/vue.js">script>
head>
<body>

<div id="app">
    <input type="text" v-model='search'>
    <div v-for="data in new_list">
        {{data}}
    div>


div>
body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            search: '',
            data_list: ['aaa', 'abc', 'abcde', 'abcdef', 'bbb', 'bac']
        },
        computed: {
            new_list() {
                return this.data_list.filter(item => {
                    return item.indexOf(this.search) > -1
                })
            }
        },
        methods: {}
    })
script>
html>

3.3 虚拟dom与diff算法 key的作用

Vue2.0 v-for 中 :key 有什么用呢?

1 v-for循环的时候,经常看到有个自定义属性 key
​
2 key是一个唯一值,为了虚拟dom替换的时候,效率高

前端之Vue:生命期钩子、组件、计算属性、全局局部组件、组件通信、ref属性、事件总线、动态组件和 keep-alive、插槽_第4张图片
前端之Vue:生命期钩子、组件、计算属性、全局局部组件、组件通信、ref属性、事件总线、动态组件和 keep-alive、插槽_第5张图片

3.4 组件化开发基础

3.4.1 组件化开发介绍

Vue的两大核心:1.数据驱动界面改变,2.组件化

什么是组件?什么是组件化?
    在前端开发中组件就是把一个很大的界面拆分为多个小的界面,每一个小的界面就是一个组件
    将大界面拆分成小界面就是组件化
​
组件化的好处:
    可以简化Vue实例的代码
    可以提高复用性
    -例如:有一个轮播,可以在很多页面中使用,一个轮播有js,css,html
    -组件把js,css,html放到一起,有逻辑,有样式,有html
    
Vue中如何创建组件?
    创建组件构造器
    注册已经创建好的组件
    使用注册好的组件
    
全局组件:整个项目中都能使用的组件
局部组件:只能再局部使用

3.4.2 注册全局组件

通过Vue.component来创建组件
组件可以有data,methods,computed…,但是data 必须是一个函数

Vue.component('my-component-name', {
  // ... 选项 ...
})
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="./js/vue.js">script>
head>
<body>

<div id="app">

    <myheader>myheader>

    <div>我是divdiv>

    <myheader>myheader>

div>
body>
<script>


    // 定义一个全局组件
    //组件可以有data,methods,computed....,但是data 必须是一个函数

    Vue.component('myheader', {
        template: `
         

我是全局组件:{{name}}

`
, data(){ return { name:'lqz' } }, methods:{ handleClick(){ alert('美女') } }, mounted(){}, computed:{ } }) var vm = new Vue({ el: '#app', data: {}, })
script> html>

3.4.3 注册局部组件

components 选项中定义你想要使用的组件:

new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="./js/vue.js">script>
head>
<body>

<div id="app">

    <myheader>myheader>

    <div>我是divdiv>

    <myheader>myheader>

    <div>div>


div>
body>
<script>

    Vue.component('myheader', {
        template: `
         

我是全局组件:{{name}}


`
, data(){ return { name:'lqz' } }, methods:{ handleClick(){ alert('美女') } }, mounted(){}, computed:{ }, components:{ child:{ template: `
{{age}}
`
, data(){ return { age:19 } }, methods:{ } } } }) var vm = new Vue({ el: '#app', data: {}, })
script> html>

3.5 组件通信

1 父子组件传值 (props down, events up)
2 父传子之属性验证props:{name:Number}Number,String,Boolean,Array,Object,Function,null(不限制类型)
3 事件机制a.使用 $on(eventName) 监听事件b.使用 $emit(eventName) 触发事件
4 Ref<input ref="mytext"/>  this.$refs.mytext
5 事件总线var bus = new Vue();* mounted生命周期中进行监听

3.5.1 组件通信之父传子

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="./js/vue.js">script>
head>
<body>

<div id="app">


    <myheader :myname="name" :myshow="false">myheader>

    {{obj.length}}



div>
body>
<script>

    Vue.component('myheader', {
        template: `
         

我是全局组件:{{myname}}


{{myshow}}
`
, data(){ return { name:'lqz' } }, methods:{ handleClick(){ alert('美女') } }, mounted(){}, computed:{ }, components:{ child:{ template: `
{{age}}
`
, data(){ return { age:19 } }, methods:{ } } }, // props:['myname'] , //注册一下 // 属性验证 props:{ myname:String, myshow:Boolean }, }) var vm = new Vue({ el: '#app', data: { name:'egon' }, })
script> html>

3.5.2 组件通信之子传父(通过自定义事件)

this.$emit('myEvent') //自定义事件
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="js/vue.js">script>
head>
<body>
<div id="box">

    <navbar @myevent="handleEvent">navbar>


div>
body>
<script>
    // 定义全局组件
    Vue.component('navbar', {
        template: `
        

我是navbar



`
, data() { return { name: 'lqz' } }, methods: { handleClick() { // 触发父组件中myevent这个自定义事件对应的函数执行 this.$emit('myevent',this.name) } } }) var vm = new Vue({ el: '#box', data: {}, methods: { handleEvent(name) { console.log('我执行了') console.log('从子组件传递的name:'+name) } } })
script> html>

3.5.3 通过子传父控制字组件显示隐藏

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="js/vue.js">script>
head>
<body>
<div id="box">

    <navbar @myevent="handleEvent" v-if="myshow">navbar>


div>
body>
<script>
    // 定义全局组件
    Vue.component('navbar', {
        template: `
        

我是navbar


`
, data() { return { // myshow: true } }, methods: { handleClick() { // 触发父组件中myevent这个自定义事件对应的函数执行 // this.myshow = !this.myshow this.$emit('myevent', false) } } }) var vm = new Vue({ el: '#box', data: { myshow: true }, methods: { handleEvent(show) { this.myshow = show } } })
script> html>

3.6 ref属性

ref放在标签上,拿到的是原生节点
ref放在组件上,拿到的是组件对象,
	通过这种方式实现子传父(this.$refs.mychild.text)
  通过这种方式实现父传子(调用子组件方法传参数)
<input ref="input">

methods: {
  // 用来从父级组件聚焦输入框
  focus: function () {
    this.$refs.input.focus()
  }
}
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="js/vue.js">script>
head>
<body>
<div id="box">
    ref放在标签上,拿到的是原生节点
    <br>
    ref放在组件上,拿到的是组件对象(数据,方法,直接使用即可)
    <hr>
    <h1>ref用在标签上h1>
    <input type="text" ref="myinput">
    <button @click="handleClick">点我触发事件button>

    <hr>
    <h1>ref用在组件上h1>
    <navbar ref="mynavbar">navbar>


div>
body>
<script>
    // 定义全局组件
    Vue.component('navbar', {
        template: `
        

我是navbar


`
, data() { return { myshow: true } }, methods: { handleClick(a) { console.log('父组件调用我,传入了:'+a) } } }) var vm = new Vue({ el: '#box', data: { myshow: true }, methods: { handleClick() { //this.$refs 取到一个对象,放着你在标签上写得ref对应的value值 //在父组件中直接取到了子组件的值(从子传到父) // console.log(this.$refs.mynavbar.myshow) //从父传子 // this.$refs.mynavbar.myshow='sss' //调用子组件方法 this.$refs.mynavbar.handleClick('lqz') } } })
script> html>

3.7 事件总线(不同层级的不通组件通信)

var bus=new Vue()

Vue.component('child1', {
	methods:{
	    send_msg(){
	        bus.$emit('suibian',this.msg)
	    }
	}
})

Vue.component('child2', {
	mounted(){
	    bus.$on('suibian',msg=> {
	        this.recv_msg=msg
	    })
	}
})	
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="js/vue.js">script>
head>
<body>
<div id="box">

    <child1>child1>

    <hr>
    <child2>child2>




div>
body>
<script>
    // 借助事件总线,实现跨组件通信
    //定义一个事件总线

    var bus=new Vue()

    Vue.component('child1', {
        template: `
        

`
, data() { return { msg: '' } }, methods:{ send_msg(){ bus.$emit('suibian',this.msg) } } }) Vue.component('child2', { template: `
我收到的内容是:{{recv_msg}}
`
, data() { return { recv_msg:'' } }, mounted(){ bus.$on('suibian',msg=> { this.recv_msg=msg }) } }) var vm = new Vue({ el: '#box', data: {}, methods: {} })
script> html>

3.8 动态组件和 keep-alive 使用

1 <component> 元素,动态地绑定多个组件到它的 is 属性
2 <keep-alive> 保留状态,避免重新渲染


<keep-alive>
    <component :is="who">component>
keep-alive>
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="js/vue.js">script>
head>
<body>
<div id="box">


    <button @click="who='Home'">首页button>
    <button @click="who='User'">用户button>
    <button @click="who='Order'">订单button>

    <keep-alive>
        <component :is="who">component>
    keep-alive>

div>
body>
<script>

    Vue.component('Home', {
        template: `
        
首页
`
, data() { return {} }, }) Vue.component('User', { template: `
用户组件
`
, data() { return { name: '' } }, }) Vue.component('Order', { template: `
订单页面
`
, data() { return {} }, }) var vm = new Vue({ el: '#box', data: { who: 'Home' }, })
script> html>

四、 插槽

a. 单个slot 
b. 具名slot
	*混合父组件的内容与子组件自己的模板-->内容分发
	*父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Titletitle>
    <script src="js/vue.js">script>
head>
<body>
<div id="box">
	
    <Home>aaaHome>
    
	
    <Order>
        <button slot="b" @click="handleClick">我是个按钮button>
    Order>


div>
body>
<script>

    Vue.component('Home', {
        template: `
        
首页
`
, data() { return {} }, }) Vue.component('Order', { template: `
订单页面
我是一行数据
`
, data() { return {} }, }) var vm = new Vue({ el: '#box', data: { who: 'Home' }, methods:{ handleClick(){ console.log('我被点了') } } })
script> html>

你可能感兴趣的:(vue,vue)