Vue2基础四、生命周期

本文详细介绍了Vue2的生命周期,包括创建、挂载、更新和销毁四个阶段,并通过生命周期钩子函数展示了在各个阶段执行代码的时机。此外,文章提供了两个实际应用案例:一个是利用`mounted`钩子使输入框自动获取焦点,另一个是实现一个小黑记账清单功能,包括数据渲染、添加、删除和饼图展示功能。
摘要由CSDN通过智能技术生成

零、文章目录

Vue2基础四、生命周期

1、生命周期

  • Vue生命周期:一个Vue实例从 创建销毁 的整个过程。
  • 生命周期四个阶段:① 创建 ② 挂载 ③ 更新 ④ 销毁
    • 创建阶段:创建响应式数据
    • 挂载阶段:渲染模板
    • 更新阶段:修改数据,更新视图
    • 销毁阶段:销毁Vue实例

1682065937815

2、生命周期钩子

  • Vue生命周期过程中,会自动运行一些函数,被称为【生命周期钩子】
  • 让开发者可以在【特定阶段】运行自己的代码

1682066040295

<!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>Document</title>
</head>

<body>

    <div id="app">
        <h3>{{ title }}</h3>
        <div>
            <button @click="count--">-</button>
            <span>{{ count }}</span>
            <button @click="count++">+</button>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                count: 100,
                title: '计数器'
            },
            // 1. 创建阶段(准备数据)
            beforeCreate() {
                console.log('beforeCreate 响应式数据准备好之前', this.count)
            },
            created() {
                console.log('created 响应式数据准备好之后', this.count)
                    // this.数据名 = 请求回来的数据
                    // 可以开始发送初始化渲染的请求了
            },

            // 2. 挂载阶段(渲染模板)
            beforeMount() {
                console.log('beforeMount 模板渲染之前', document.querySelector('h3').innerHTML)
            },
            mounted() {
                console.log('mounted 模板渲染之后', document.querySelector('h3').innerHTML)
                    // 可以开始操作dom了
            },

            // 3. 更新阶段(修改数据 → 更新视图)
            beforeUpdate() {
                console.log('beforeUpdate 数据修改了,视图还没更新', document.querySelector('span').innerHTML)
            },
            updated() {
                console.log('updated 数据修改了,视图已经更新', document.querySelector('span').innerHTML)
            },

            // 4. 卸载阶段
            beforeDestroy() {
                console.log('beforeDestroy, 卸载前')
                console.log('清除掉一些Vue以外的资源占用,定时器,延时器...')
            },
            destroyed() {
                console.log('destroyed,卸载后')
            }
        })
    </script>
</body>

</html>

3、案例-mounted获取焦点

  • mounted应用:输入框获取焦点

image-20230706161107976

<!DOCTYPE html>
<html lang="zh-CN">

<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>
    <!-- 初始化样式 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reset.css@2.0.2/reset.min.css">
    <!-- 核心样式 -->
    <style>
        html,
        body {
            height: 100%;
        }
        
        .search-container {
            position: absolute;
            top: 30%;
            left: 50%;
            transform: translate(-50%, -50%);
            text-align: center;
        }
        
        .search-container .search-box {
            display: flex;
        }
        
        .search-container img {
            margin-bottom: 30px;
        }
        
        .search-container .search-box input {
            width: 512px;
            height: 16px;
            padding: 12px 16px;
            font-size: 16px;
            margin: 0;
            vertical-align: top;
            outline: 0;
            box-shadow: none;
            border-radius: 10px 0 0 10px;
            border: 2px solid #c4c7ce;
            background: #fff;
            color: #222;
            overflow: hidden;
            box-sizing: content-box;
            -webkit-tap-highlight-color: transparent;
        }
        
        .search-container .search-box button {
            cursor: pointer;
            width: 112px;
            height: 44px;
            line-height: 41px;
            line-height: 42px;
            background-color: #ad2a27;
            border-radius: 0 10px 10px 0;
            font-size: 17px;
            box-shadow: none;
            font-weight: 400;
            border: 0;
            outline: 0;
            letter-spacing: normal;
            color: white;
        }
        
        body {
            background: no-repeat center /cover;
            background-color: #edf0f5;
        }
    </style>
</head>

<body>
    <div class="container" id="app">
        <div class="search-container">
            <img src="./img/logo.png" alt="">
            <div class="search-box">
                <input type="text" v-model="words" id="inp">
                <button>百度一下</button>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                words: ''
            },
            // 核心思路:
            // 1. 等input框渲染出来 mounted 钩子
            // 2. 让input框获取焦点 inp.focus()
            mounted() {
                document.querySelector('#inp').focus()
            }
        })
    </script>

</body>

</html>

4、案例-小黑记账清单

(1)功能需求

image-20230706162228312

(2)实现细节

1.基本渲染

  • 拿到数据,存到data的响应式数据中
  • 结合数据,进行渲染 v-for
  • 消费统计 —> 计算属性

2.添加功能

  • 收集表单数据 v-model,使用指令修饰符处理数据
  • 给添加按钮注册点击事件,对输入的内容做非空判断
  • 添加成功后,对文本框内容进行清空

3.删除功能

  • 注册点击事件,获取当前行的id
  • 根据id删除数据

4.饼图渲染

  • 初始化一个饼图 echarts.init(dom) mounted钩子中渲染
  • 根据数据试试更新饼图 echarts.setOptions({…})
(3)代码实现
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <!-- CSS only -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" />
    <style>
        .red {
            color: red!important;
        }
        
        .search {
            width: 300px;
            margin: 20px 0;
        }
        
        .my-form {
            display: flex;
            margin: 20px 0;
        }
        
        .my-form input {
            flex: 1;
            margin-right: 20px;
        }
        
        .table> :not(:first-child) {
            border-top: none;
        }
        
        .contain {
            display: flex;
            padding: 10px;
        }
        
        .list-box {
            flex: 1;
            padding: 0 30px;
        }
        
        .list-box a {
            text-decoration: none;
        }
        
        .echarts-box {
            width: 600px;
            height: 400px;
            padding: 30px;
            margin: 0 auto;
            border: 1px solid #ccc;
        }
        
        tfoot {
            font-weight: bold;
        }
        
        @media screen and (max-width: 1000px) {
            .contain {
                flex-wrap: wrap;
            }
            .list-box {
                width: 100%;
            }
            .echarts-box {
                margin-top: 30px;
            }
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="contain">
            <!-- 左侧列表 -->
            <div class="list-box">

                <!-- 添加资产 -->
                <form class="my-form">
                    <input v-model.trim="name" type="text" class="form-control" placeholder="消费名称" />
                    <input v-model.number="price" type="text" class="form-control" placeholder="消费价格" />
                    <button @click="add" type="button" class="btn btn-primary">添加账单</button>
                </form>

                <table class="table table-hover">
                    <thead>
                        <tr>
                            <th>编号</th>
                            <th>消费名称</th>
                            <th>消费价格</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr v-for="(item, index) in list" :key="item.id">
                            <td>{{ index + 1 }}</td>
                            <td>{{ item.name }}</td>
                            <td :class="{ red: item.price > 500 }">{{ item.price.toFixed(2) }}</td>
                            <td><a @click="del(item.id)" href="javascript:;">删除</a></td>
                        </tr>
                    </tbody>
                    <tfoot>
                        <tr>
                            <td colspan="4">消费总计: {{ totalPrice.toFixed(2) }}</td>
                        </tr>
                    </tfoot>
                </table>
            </div>

            <!-- 右侧图表 -->
            <div class="echarts-box" id="main"></div>
        </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.0/dist/echarts.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        const app = new Vue({
            el: '#app',
            data: {
                list: JSON.parse(localStorage.getItem('list')) || [],
                name: '',
                price: ''
            },
            computed: {
                totalPrice() {
                    return this.list.reduce((sum, item) => sum + item.price, 0)
                }
            },
            mounted() {
                this.myChart = echarts.init(document.querySelector('#main'))
                this.myChart.setOption({
                    // 大标题
                    title: {
                        text: '消费账单列表',
                        left: 'center'
                    },
                    // 提示框
                    tooltip: {
                        trigger: 'item'
                    },
                    // 图例
                    legend: {
                        orient: 'vertical',
                        left: 'left'
                    },
                    // 数据项
                    series: [{
                        name: '消费账单',
                        type: 'pie',
                        radius: '50%', // 半径
                        data: [
                            // { value: 1048, name: '球鞋' },
                            // { value: 735, name: '防晒霜' }
                        ],
                        emphasis: {
                            itemStyle: {
                                shadowBlur: 10,
                                shadowOffsetX: 0,
                                shadowColor: 'rgba(0, 0, 0, 0.5)'
                            }
                        }
                    }]
                })

                this.refreshChart()
            },
            watch: {
                //数据变化存入本地
                list: {
                    deep: true,
                    handler(newValue) {
                        // 需要将变化后的 newValue 存入本地 (转JSON)
                        localStorage.setItem('list', JSON.stringify(newValue))
                    }
                }
            },
            methods: {
                // 更新图表
                refreshChart() {
                    this.myChart.setOption({
                        // 数据项
                        series: [{
                            data: this.list.map(item => ({
                                value: item.price,
                                name: item.name
                            }))
                        }]
                    })
                },
                add() {
                    if (!this.name) {
                        alert('请输入消费名称')
                        return
                    }
                    if (typeof this.price !== 'number') {
                        alert('请输入正确的消费价格')
                        return
                    }

                    this.list.push({
                        id: new Date,
                        name: this.name,
                        price: this.price
                    })

                    // 重新渲染图标
                    this.refreshChart()

                    this.name = ''
                    this.price = ''
                },
                del(id) {

                    //删除数据
                    this.list = this.list.filter(item => item.id != id)

                    // 重新渲染图标
                    this.refreshChart()
                }
            }
        })
    </script>
</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李宥小哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值