03-修饰符-监听属性-Ajax请求-组件-动态组件-keep-alive-插槽-生命周期钩子

事件修饰符

事件修饰符 作用
.stop 只处理自己的事件,父控件冒泡的事件不处理(阻止事件冒泡),一般用在子元素类上
.self 只处理自己的事件,子控件冒泡的事件不处理,一般用在父元素上
.prevent 阻止a连接的跳转
.once 事件只会触发一次(适用于抽奖页面)

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生

  • v-on:click.prevent.self 会阻止所有的点击
  • v-on:click.self.prevent 只会阻止对元素自身的点击

冒泡的概念

什么是冒泡呢?以下面这个例子,比如有一个蕃茄色父盒子,里面包裹了一个白色子盒子,分别绑定点击事件将输出不同内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <style>
        .outer {
            width: 300px;
            height: 300px;
            padding: 10px;
            border: 2px solid black;
            margin: auto;
            background-color: tomato;
        }

        .inner {
            width: 150px;
            height: 50px;
            margin: auto;
            text-align: center;
            line-height: 50px;
            background-color: snow;
        }
    </style>
</head>
<body>
    <div id="app">
        <div class="outer" @click="outerEvent">
            <div class="inner" @click="innerEvent">不要点我啊 >_<</div>
        </div>
    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        methods: {
            outerEvent(){
                console.log("父亲");
            },
            innerEvent(){
                console.log("儿子");
            }
        },
    })
</script>
</html>

效果如下,可以发现,当点击子盒子时,不仅子盒子事件被触发,连同父盒子的事件也被触发了。而只点父盒子时,只有父盒子事件触发。这就是冒泡,事件会向上级DOM元素传递,由内而外,依次触发。

img

stop (停止冒泡) 一般添加到子元素使用

当使用 .stop 事件修饰符时就能很简单的阻止冒泡了,用法如下,直接给子盒子的点击事件后加上.stop即可:

<div class="outer" @click="outerEvent">
    <div class="inner" @click.stop="innerEvent">不要点我啊 >_<</div>
</div>

img

self (点击自己才会执行) 一般加到父元素

<div class="outer" @click.self="outerEvent">
    <div class="inner" @click="innerEvent">不要点我啊 >_<</div>
</div>

img

prevent (阻止默然行为)

阻止默认事件触发。默认事件指对DOM的操作会引起自动执行的动作,比如点击a标签超链接的时候会进行默认进行页面的跳转等等。

  • a连接的自动跳转。
  • 表单的自动提交等。
<!-- 正常HTML代码 -->
<p><a href="#" @click.prevent="handleA">点我选壁纸</a></p>

<script>
    // vue
    let vm = new Vue({
        el: "#app",
        methods: {
            handleA(){
                console.log("处理完成,允许访问。");
                location.href = "https://snake.timeline.ink/home"
            }
        },
    })
</script>

img

事件只执行一次 .once

抽奖页面大概率都是使用了这个

<div class="outer" @click.self="outerEvent">
    <div class="inner" @click.once="innerEvent">不要点我啊 >_<</div>
</div>

img

用capture后,是从上到下的。

按键修饰符

keyup

vue2写法:keyup.具体的键位

vue3写法:keyup.键位对应的数字 推荐

在Vue.js中,keyup是一个按键修饰符,它可以用来监听键盘的keyup事件。当您在模板中使用@keyup时,您可以指定一个键盘按键,以便在用户释放该按键时触发相应的事件处理函数。例如,您可以这样使用:

<input @keyup.enter="submitForm">

Keycode对照表(键码对照表):https://segmentfault.com/a/1190000005828048

<!-- vue2中 -->
<input type="text" @keyup.enter="showMsg" v-model="text"> --- <span>{{text}}</span>

<!-- vue2中 -->
<input type="text" @keyup.13="showMsg" v-model="text"> --- <span>{{text}}</span>

如果要获取具体的按键 可以通过下面的方式

<body>
    <div id="app">
        <input type="text" @keyup="showMsg" v-model="text"> --- <span>{{text}}</span>
    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            text: ""
        },
        methods: {
            showMsg(e){
                console.log(`你刚刚按下了  ${e.key}  `);
            }
        },
    })
</script>

img

表单控制

在Vue.js中,:valuev-model之间的关系是这样的::value用于向v-model绑定的数据传递值。当使用:value时,它决定了输入元素(比如input或checkbox)的值,而这个值会影响到v-model绑定的数据。换句话说,:value提供了输入元素的值,而v-model则负责将这个值与数据进行双向绑定。

input属性 v-model绑定 完整案例 说明
checkbox 单选:布尔值remember:true, 多选:数组 hobby:[] 需要指定value <label>欺负小满<input type="checkbox" v-model="hobby" value="qfxm"></label> 单选:data里面设置布尔值,多选,设定数组。
radio 字符串 gender: "" 需要指定value <label>女<input type="radio" v-model="gender" value="girl"></label> data里面设置字符串
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <style>
        span {
            color: tomato;
        }
    </style>
</head>

<body>
    <div id="app">
        <h3>checkbox单选就是true和false</h3>
        <label>用户名:<input type="text" v-model="username"></label><br>
        <label>密码:<input type="password" v-model="password"></label><br>
        <label>记住密码:<input type="checkbox" v-model="remember"></label><br>
        <p>用户信息:username: <span>{{username}}</span> password: <span>{{password}}</span> 记住密码: <span>{{remember}}</span>
        </p>
        <hr>

        <h3>checkbox多选就是选value,v-model是数组</h3>
        爱好:
        <label>逃课<input type="checkbox" v-model="hobby" value="tk"></label>
        <label>抢人头<input type="checkbox" v-model="hobby" value="qrt"></label>
        <label>欺负小满<input type="checkbox" v-model="hobby" value="qfxm"></label>
        <p>爱好:<span>{{hobby}}</span></p>
        <hr>

        <h3>raido单选也是value,v-model是字符串</h3>
        性别:
        <label for="">男<input type="radio" v-model="gender" value="boy"></label>
        <label for="">女<input type="radio" v-model="gender" value="girl"></label>
        <p>性别:<span>{{gender}}</span></p>
    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            username: '',
            password: '',
            remember: false,
            hobby: [],
            gender: ""
        },
    })
</script>

</html>

img

购物车案例

需要留意的几个问题:

  1. 全选/全不选和下面的复选框并不是一起的,所以需要单独起一个函数去控制。

  2. 一般情况下true和false事件第一事件想到的就应该是change事件。

  3. 只要下面复选框不是全部选中,那么全选复选框应该是非选中状态。

    判断长度,只要下面商品选中的长度之和等于列表长度,那么全选设置为true,否则设置为false

  4. 在JavaScript中,字符串是可以和数字进行乘法操作的,但是不建议,还是建议严谨一些,使用number类型。

  5. 传递的时候,传递对象才可以同步去修改,传递数字不可以,就相当于python中的可变数据类型。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <style>
        table {
            border: 1px solid black;
            border-collapse: collapse;
        }

        tr, th, td {
            border: 1px solid black;
            padding: 10px;
        }

        .to-center {
            text-align: center;
            align-items: center;
        }

    </style>
</head>

<body>
    <div id="app">
        <table>
            <caption>峡谷商品清单</caption>
            <tr>
                <th>id</th>
                <th>名称</th>
                <th>数量</th>
                <th>价格</th>
                <!-- 
                    全选 全不选,需要绑定一个change事件,v-model需要设置成一个布尔值,因为这是单个复选框 
                    核心点:这个复选框和下面的复选框并不是一起的,所以是需要单独去控制
                -->
                <th>全选/全不选 <input type="checkbox" @change="changeEvent" v-model="checkAll"></th>
            </tr>
            <tr v-for="item in good_list">
                <td>{{item.id}}</td>
                <td>{{item.name}}</td>
                <td><button @click="minus(item)">-</button> {{item.count}} <button @click="item.count++">+</button></td>
                <td>{{item.price}}</td>
                <td class="to-center"><input type="checkbox" @change="changeOnce"  v-model="checkGoods" :value="item"></td>
            </tr>
        </table>
        <p>全选:<span style="color:red">{{checkAll}}</span></p>
        <p>商品的总价格为:<span :style="{color: 'red'}">{{totalPrice}}</span> 元</p>
        <!-- {{checkGoods}} -->
    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            good_list: [
                { id: 1001, name: '红buff', price: 273, count: 25 },
                { id: 1002, name: '蓝buff', price: 237, count: 23 },
                { id: 1003, name: '人头', price: 5999, count: 2 },
                { id: 1004, name: '摸鱼手环', price: 1002, count: 3 },
                { id: 1005, name: '野怪', price: 249, count: 11 },
                { id: 1005, name: '河蟹', price: 308, count: 45 },
            ],
            // 循环出来的对象放进去数组里面
            checkGoods: [],
            // 全选的复选框
            checkAll: false,
        },
        methods: {
            // 控制商品数量的减少 小于0 alert
            minus: function(item){
                if (item.count > 1){
                    return item.count--
                }else{
                    alert("不能再减啦!")
                }
            },
            // 全选/不选商品
            changeEvent(){
                if (this.checkAll){
                    this.checkGoods = this.good_list
                }else{
                    this.checkGoods = []
                }
            },
            // 修复全选全部选的bug
            // 只要全部商品的总长度,等于列表的长度,那么全选就设置成true,除开这种情况都是false
            changeOnce(){
                if (this.checkGoods.length === this.good_list.length){
                    this.checkAll = true
                }else{
                    this.checkAll =  false
                }
            }
        },
        computed: {
            // 返回选择商品的价格
            totalPrice: function(){
                let total = 0
                for (let good of this.checkGoods) {
                    total += good.price * good.count
                }
                return total
            },
            
        }

    })
</script>

</html>

img

v-model进阶用法(也是修饰符)

修饰符 说明
v-model.trim 同JavaScript语法,它用于自动过滤用户输入的首尾空格。
v-model.lazy 将输入事件从默认的 input 事件改为 change 事件。即输入框的值不会实时更新到数据,而是在失去焦点或按下回车键时才会更新到绑定的数据中。
v-model.number 如果是按数字开头,保留全部数字,放弃英文字符。如果是英文开头,都保留。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <style>
        span {
            border: 1px solid black;
        }
    </style>
</head>
<body>
    <div id="app">
        <h3>常规写法(未使用lazy)</h3>
        <input type="text" v-model="t0"> -- <span>{{t0}}</span>

        <h3>演示v-mode.lazy</h3>
        <input type="text" v-model.lazy="t1"> -- <span>{{t1}}</span>

        <h3>演示v-mode.trim</h3>
        <input type="text" v-model.trim="t2"> -- <span>{{t2}}</span>

        <h3>演示v-mode.number</h3>
        <input type="text" v-model.number="t3"> -- <span>{{t3}}</span>
    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            t0: "",
            t1: "",
            t2: "",
            t3: ""
        }
    })
</script>
</html>

img

vue与Ajax

# 1 后端---》提供接口--》json形式--》给前端--》前端拿到再做处理
	-后端接口
    -ajax 发送请求
    
# 2 vue中使用ajax
	-1 jquery的ajax
    -2 js原生的fetch
    	-XMLHTTPRequest--》需要做浏览器兼容
        -fetch方案
    -3 第三方axios(最多)
    
    
# 3 写个后端接口--》django----》flask简单


# 4 前后端交互---》跨越问题---》后端处理
	-Access-Control-Allow-Origin

因为后续用的最多的是fetch和axios,所以只列出这两种。

之前的博客:https://www.cnblogs.com/ccsvip/p/18090680

网友的文章:https://developer.baidu.com/article/details/2766440

解决跨域

// 响应头中添加,服务端设置 'Access-Control-Allow-Origin' = "*"

fetch发送Ajax请求

在第一个 .then 中,应该返回 response.json(),以便将其传递给下一个 .then

此外,在第二个 .then 中,应该接收到 data 参数,而不是直接从 response 对象中获取数据。

# 后端代码
from flask import Flask, jsonify, make_response


app = Flask(__name__)

@app.route("/")
def index():
    data = {"name": "小满", "age": 3}
    response = make_response(jsonify(data))
    # 解决跨域用的
    response.headers['Access-Control-Allow-Origin'] = "*"    
    return response

if __name__ == "__main__":
    app.run(debug=True)
<script>
    // 复杂的写法
    fetch("http://127.0.0.1:5000/")
        .then(function(response){
            return response.json()
        }).then(
            function(data){
                console.log(data);
            }
        ).catch(function(error){
            console.log(["Error", error]);
        })
</script>


<script>
    // 通过fetch发送Ajax请求 简单的写法
    fetch("http://127.0.0.1:5000/")
        .then(response => response.json())
        .then(data => console.log(data))
        .catch(error => console.log(['Error', error]))
</script>

image-20240426203231069

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
    <div id="app">
        <button @click="loadData">获取个人信息</button>
        <p>姓名:{{name}}</p>
        <p>年龄:{{age}}</p>
    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            name: "",
            age: ""
        },
        methods: {
            loadData(){
                fetch("http://127.0.0.1:5000/")
                .then(response => response.json())
                .then((data)=>{
                    this.name = data.name
                    this.age = data.age
                })
                .catch(error => console.log(['Error', error]))
            }
        },
    })

</script>
</html>

axios发送Ajax请求

<script>
    // 通过axios发送请求
    axios.get("http://127.0.0.1:5000/")
        .then((response)=>{
        // 数据从 response.data 中获取
        data = response.data
        console.log(data);
    })
        .catch(error => console.log(["Error", error]))
</script>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
</head>
<body>
    <div id="app">
        <button @click="loadData">查看个人信息</button>
        <p>姓名:{{name}}</p>
        <p>年龄:{{age}}</p>
        <p>爱好:{{hobby}}</p>
    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            name: "",
            age: "",
            hobby: ""
        },
        methods: {
            loadData(){
                axios.get("http://127.0.0.1:5000/")
                .then((response)=>{
                    data = response.data
                    this.name = data.name
                    this.age = data.age
                    this.hobby = data.hobby
                })
                .catch(error => alert('发生了一些错误', error))
            }
        },

    })
</script>
</html>

通过axios发送Ajax请求接口案例(获取电影数据)

# 后端
import json
from flask import Flask, jsonify, make_response


app = Flask(__name__)

with open("./movies.json", "rt", encoding="utf-8") as file:
    data = json.load(file)

@app.route("/")
def index():
    response = make_response(jsonify(data))
    # 解决跨域问题
    response.headers['Access-Control-Allow-Origin'] = "*"    
    return response

if __name__ == "__main__":
    app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
    <style>
        ul {
            list-style: none;
        }
    </style>
</head>
<body>
    <div id="app">
        <button @click="loadFilm">加载电影数据</button>
        <ul v-for="item in films">
            <li>名称:{{item.name}}</li>
            <li>类型:{{item.category}}</li>
            <li>简介:{{item.synopsis}}</li>
            <li>导演:{{item.director}}</li>
            <li>评分:{{item.grade}}</li>
            <li>地址:{{item.nation}}</li>
            <li><img :src="item.poster" width="100"></li>
            <hr>
        </ul>
    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            films: null
        },
        methods: {
            loadFilm(){
                let url = "http://127.0.0.1:5000/"
                axios.get(url).then((response)=>{
                    let dataObj = response.data.result
                    let filmArr = []
                    for (const item of dataObj) {
                        let filmData = {
                            name: item.name,
                            synopsis: item.synopsis,
                            director: item.director,
                            nation: item.nation,
                            poster:item.poster,
                            grade: item.grade,
                            category: item.category
                        }
                        filmArr.push(filmData)
                    }
                    this.films = filmArr
                })
            }
        },
        computed: {
            
        }
    })
</script>
</html>

img

排序问题

如果要排序,是前端发送排序请求给后端,后端去完成排序请求,然后拿到数据渲染到页面,而不是前端去完成排序。(虽然前端也可以)

监听属性 watch

监听住一个属性,只要这个属性发生变化,就执行函数.

这种自动更新是通过Vue.js的响应式系统实现的,它会追踪每个属性的变化,并在属性值发生变化时,自动更新相关的视图。

image-20240502141925372

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
    <style>
        .box {
            display: flex;
            justify-content: center;
        }

        .box-course {
            width: 200px;
            height: 50px;
            background-color: tomato;
            text-align: center;
            line-height: 50px;
            margin: 10px;
            border: 2px solid yellow;
            outline: 2px solid black;
        }
    </style>
</head>
<body>
    <div id="app">
        <div class="box">
            <!-- 我这里使用的是鼠标滑动事件 mousemove  你也可以使用click点击事件 -->
            <div @mousemove="courseType='Python'" class="box-course">Python</div>
            <div @mousemove="courseType='JavaScript'" class="box-course">JavaScript</div>
            <div @mousemove="courseType='Dart'" class="box-course">Dart</div>
        </div>

        <p>选中的课程是:<span :style="{color:'red'}">{{content}}</span></p>
    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            courseType: "",
            content: ""
        },
        watch: {
            // 可以放两个参数,第一个是老参数,第二个是新参数
            // 打印的时候,新参数在前面
            courseType(oldvalue, newValue){
                this.content = this.courseType 
                console.log(oldvalue, newValue);
            }
        }
    })
</script>
</html>

img

监听属性完整写法

image-20240502155234562

组件的使用

注意!所有的组件必须套在1个标签里面

在Vue.js中,组件名称应该是小写的

// 组件就是:扩展 HTML 元素,封装可重用的代码,目的是复用
    例如:有一个轮播图,可以在很多页面中使用,一个轮播有js,css,html
    组件把js,css,html放到一起,有逻辑,有样式,有html
    
    
// 局部组件和全局组件
	-局部组件:只能在当前页面中使用
    -全局组件:全局都可以用
    
/*
    1 使用Vue.component 定义全局组件
    2 在组件中通过components配置项定义局部组件
    3 局部组件只能用在组件内部
    4 组件中的数据,事件都是独立
*/

全局组件 component

全局组件是指在Vue应用程序中注册的组件,可以在应用程序的任何地方使用。这意味着一旦注册了全局组件,它就可以在整个应用程序范围内的任何Vue实例中使用,而不需要在每个实例中单独注册或导入。这样可以使组件在整个应用程序中变得可用,提高了组件的复用性和可维护性。

注意:组件也需要放在根组件管理的DOM中

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
</head>
<body>
    <div id="app">
        
    <h2>组件首页</h2>
    <hr>
    <!-- 这个Child 就是我们自己定义的全局组件 -->    
    <Child></Child>
    <hr>
        
    </div>
</body>
<script>
    // 定义全局组件 Vue.component
    // 给组件起一个名字 就是第一个参数
    Vue.component("Child",{
        // 第二个参数是一个对象
        // 对象里面必须包含几个东西 1. template 2.data  3. methods
        // template 放HTML内容,这里只做一个简单的演示,后续写入到文件的vue后直接引用就行了。  这里的template和根组件的el是一个意思
        // 这个组件有自己的HTML内容
        template: `<div>
                        <button @click="handleClick">{{name}}</button>
                    </div>`,
                
        // data就是之前的data,只不过并不是是直接放一个对象,而是放一个函数,返回一个对象
        data(){
            return {
                name: "小满"
            }
        },
        methods: {
            handleClick(){
                alert(this.name)
            }
        }

    })
    let vm = new Vue({
        el: "#app",

    })
</script>
</html>

局部组件 components

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
</head>

<body>
    <div id="app">
        <my-div>
    </div>
</body>
<script>
    // 公共的局部组件,也就是局部和全局组件都会使用
    let myDiv = {
        template: `<div>
                        <img src="http://pic.netbian.com/uploads/allimg/240416/002020-1713198020e46e.jpg" width="420" alt='图片加载失败'>
                    </div>`}

    let vm = new Vue({
        el: "#app",
        // 定义局部组件,和定义全局组件一样,只不过是使用components,参数第一个是组件名称,后面comonents: {"组件名称", {这里和全局组件一样}}
        components: {myDiv},
    })
</script>

</html>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
</head>

<body>
    <div id="app">
        <h2>组件的详细使用</h2>
        <h3>全局组件</h3>
        <!-- 一次定义,可以多处使用 -->
        <child1></child1>
        <br>
        <child1></child1>

        <h3>局部组件</h3>
        <my-div>



    </div>
</body>
<script>
    // 公共的局部组件,也就是局部和全局组件都会使用
    let myDiv = {
        template: `<div>
                        <img src="http://pic.netbian.com/uploads/allimg/240416/002020-1713198020e46e.jpg" width="420" alt='图片加载失败'>
                    </div>`}

    // 定义全局组件
    let child1 = {
        template: `<div class="box" style="display:flex;justify-content:space-between;width:400px;border: 1px solid black;padding:10px;">
                        <div @click="handleBack">上一张</div>
                        <div @click="changeTitle">{{title}}</div>
                        <div @click="handleForward">下一张</div>

                        <my-div></my-div>
                        

                    </div>
                    
                    `,
        data() {
            return {
                title: "child1",
                // myImg: "./img/1.jpg"
            }
        },
        components: {
          myDiv  
        },
        methods: {
            // 上一张
            handleBack() {
                alert("上一张")
            },

            // 下一张
            handleForward() {
                alert("下一张")
            },

            // 修改文字
            changeTitle() {
                this.title = "小满"
            }

        },
    }

    Vue.component("child1", child1)
    // 定义全局组件结束


    let vm = new Vue({
        el: "#app",
        // 定义局部组件,和定义全局组件一样,只不过是使用components,参数第一个是组件名称,后面comonents: {"组件名称", {这里和全局组件一样}}
        components: {myDiv},
        // data() {
        //     return {
        //         myImg: "./img/1.jpg"
        //     }
        // }
    })
</script>

</html>

组件通信之父传子 props

父子组件通信中的父传子是指父组件向子组件传递数据或者方法的过程。在Vue.js中,父组件可以通过props向子组件传递数据,子组件通过props接收父组件传递的数据。父组件可以传递任何类型的数据给子组件,包括基本类型、对象、数组等。子组件接收到父组件传递的数据后,就可以在自己的模板中直接使用这些数据了。

什么是props?

在 Vue.js 中,props 是用于从父组件向子组件传递数据的一个自定义属性。通过 props,父组件可以向子组件传递数据,子组件可以接收这些数据并在自己的模板中使用。

在本案例中演示,属性的传递方法:

  1. 父组件的data中定义必要的属性,比如data:{url: "./img/1.jpg"}
  2. 在页面的视图中,子组件通过属性接受变量,<child1 :myurl="url"></child1>,这样在子组件中就可以通过props去接受了。
  3. 在子组件中,获取到的属性(本案例)会放在props数组中,可以直接通过this.对应的值去拿到数据,进一步去处理。
# 1 在父组件中定义变量
    data: {
            'url': './img/a.jpg'
            }
# 2 把变量传递个子组件--》myurl 自定义属性
	<Child1 :myurl="url"></Child1>
    
# 3 在子组件中,拿到属性
	props:['myurl']
    
# 4 以后再子组件中使用属性
	this.myurl
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
</head>

<body>
    <div id="app">
        <h2>组件通信-父传子-通过属性</h2>
		<!-- 第二步 -->
        <child1 :myurl="url"></child1>

    </div>
</body>
<script>
    let child1 = {
        template: `<div>
                        <div class="box" style="display:flex;justify-content:space-between;width:400px;border: 1px solid black;padding:10px;">
                            <div @click="handleBack">上一张</div>
                            <div @click="changeTitle">{{title}}</div>
                            <div @click="handleForward">下一张</div>
                        </div>
                        <br/>
                        <div>
                            <img :src="myImg" width="420" alt='图片加载失败'>
                        </div>
                    </div>
                    
                    `,
        // 第三步
        props: ["myurl"],
        data() {
            return {
                title: "child1",
                myImg: "http://pic.netbian.com/uploads/allimg/240416/002020-1713198020e46e.jpg"
            }
        },
        methods: {
            // 上一张
            handleBack() {
                alert("上一张")
            },

            // 下一张
            handleForward() {
                // 第四步
                this.myImg = this.myurl
                this.title = "图片切换成功"
            },

            // 修改文字
            changeTitle() {
                this.title = "小满"
            }

        },
    }

    Vue.component("child1", child1)



    let vm = new Vue({
        el: "#app",
        data: {
            // 第一步
            url: "./img/1.jpg"
        }
    })
</script>

</html>

props传递对象

如果没有按照要求传值,页面并不会报错,控制台会报错。

props:{name: string} // 必须是string 限定类型
props:{
    name: string; //必须是string
    requered:true;// 必须传
    default:"小满"// 给一个默认值
}

img

项目中使用props通信

image-20240504113502422

prop可以传递任意数量、任意类型

image-20240504122415724

组件通信之子传父 $emit

核心,子组件要想办法触发自定义的事件。

  • 应该在触发事件的地方使用 this.$emit('ss', this.hobby)

在子组件的事件绑定中,应该使用kebab-case 格式来定义事件名。

  1. 子传父,应该在子组件中定义一个点击事件
<p><button class="btn btn-outline-info" @click="toFather">给父组件</button></p>
  1. 父组件中, ss就是自定义事件的名称。
<child-view @ss="recv"></child-view>
  1. 自组件触发点击事件后,写上this.$emit('自定义事件名字',要传递的数据)
toFather(){
    this.$emit("ss", this.hobby)
}
  1. 父组件定义recv函数,见第二条,其中函数的第一个参数,就是子组件传递过来的数据,拿到数据后自行处理即可。
function recv(data) {
    alert(data);
}

项目中操作

image-20240504114842017

img

props校验 以后都简写写对象的形式

类型校验

// 父组件的data
age: 'xx',
// 子组件的props
props: {
	age: Number
}

// 语法
props: {
    校验的属性名: 类型 // String Number Boolean ...
}

image-20240504123651676

自定义校验

props: {
    校验的属性名: {
      type: 类型, // Number String Boolean ...
      require: true, // 是否必填
      default: 默认值, // 默认值
      // 这个value就是传递过来的值
      validator(value){
        // 自定义校验逻辑
        // 如果没有通过校验,可以自定义错误提示
          console.error('错误提示信息')
        return 是否通过校验
      }
    }
  }

image-20240504125218139

image-20240504125249221

父子传递遵循单向数据流

如果对传递过来的数据直接修改,会报错。

应该遵循谁的数据,就让谁去修改的原则,把数据通过this.$emit传递给父亲,让父亲去修改。

image-20240504131248667

正确的写法

image-20240504131713875

组件总结

  1. 组件的名称,不能和自带的标签名称冲突。
  2. 组件的名称,建议使用'a-b'的方式连接,比如:'my-div',它这样写等同于myDiv,也就是你组件中写了my-div,使用的使用写了myDiv,也是可以的。
  3. 组件可以使用单标签的形式,比如:<myDiv>,等同于<my-div></my-div>,一般在页面内部写的时候,都建议使用斜杠链接的形式,而不是驼峰体。
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
    <!-- bootstrap5 -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-/mhDoLbDldZc3qpsJHpLogda//BVZbgYuw6kof4u2FrCedxOtgRZDTHgHUhOCVim" crossorigin="anonymous"></script>
    <style>
        div.box {
            margin: 30px;
        }
        span.text {
            color: tomato;
        }
    </style>
</head>

<body>
    <div id="app" class="box">
        <h2>组件通信-子传父-通过事件-子组件写事件</h2>
        <!-- 子组件 -->
        <child @sent-text="gettextEvnt"></child>
        <hr>
        <!-- 父组件 -->
        收到的数据:<span class="text">{{text}}</span>
    </div>
</body>
<script>
    Vue.component("child", {
        template: `<div style="margin: 20px;">
                        <input type="text" v-model="mytext">
                        <button type="button" class="btn btn-primary" @click="sentText">点我把数据传给父亲</button>
                        
                    </div>`,
        data(){
            return {
                mytext: ""
            }
        },
        methods: {
            sentText(){
                // 这里的参数,第一个是事件的名称
                // <child @sendText="gettextEvnt"></child> 事件名称就是 sendText
                // 后面跟的是参数,可以是一个或多个参数。
                // 参数需要先定义

                // 1 子组件中,要触发---> 自定义事件执行--sent-text 然后会触发--gettextEvnt执行
                this.$emit('sent-text', this.mytext); // 会触发 sent-text--> gettextEvnt执行执行并且把this.mytext传入
            }
        },
    })

    let vm = new Vue({
        el: "#app",
        data: {
            text: ""
        },
        methods: {
            gettextEvnt(childText){
                this.text = childText
            }
        }
    })
</script>

</html>

img

ref属性(父子通信) this.$refs

ref 是 Vue.js 提供的一个特殊属性,用于在子组件上注册引用信息。通过 ref,可以在父组件中直接访问子组件实例,或者访问子组件中的 DOM 元素。简单总结如下:

  1. 在子组件上使用 ref 属性,给子组件命名:

    <child ref="refChild"></child>
    
  2. 在父组件中通过 $refs 访问子组件:

    this.$refs.refChild
    
  3. 通过 $refs 可以访问子组件的实例或者 DOM 元素。

这样,就可以实现父子组件之间的直接通信。

需掌握的地方:

  1. ref是一个属性,不仅可以用在普通标签上,也可以用在组件上面
  2. 网页内容中并不会体现到ref字样
  3. $refs可以获取到数据,并且放在一个对象中,可以通过this.$refs.key,这个key就是你之前传入的ref=""时候的数据,比如ref="reference",那么此时的key就是reference
  4. 普通标签拿到的数据是一个DOM对象,<></>
  5. 组件对象拿到的数据是一个组件对象,一样可以通过组件.xx去操作数据。

ref在普通标签上使用

<img src="./img/2.jpg" ref="reference" width="500">

image-20240428181200298

<!-- 视图 -->
<img src="./img/2.jpg" ref="reference" width="500">
<input type="text" ref="myInput">
<button type="button" class="btn btn-primary" @click="handleClick">查看控制台</button>

<script>
    let vm = new Vue({
        el: "#app",
        methods: {
            handleClick(){
                console.log(this.$refs);
                console.log(this.$refs.reference);
            }
        },
    })
</script>

img

通过this.$refs.xx = xx 能修改数据

原生DOM操作

<!-- 视图 -->
<img src="./img/2.jpg" ref="reference" width="500">
<input type="text" ref="myInput">

<script>
    methods: {
        handleClick(){
            this.$refs.reference.src = "./img/3.jpg"
            this.message = "图片成功修改"
        }
    },
</script>

img

<!-- 视图 -->
<img src="./img/2.jpg" ref="reference" width="500">
<input type="text" ref="myInput">

<script>
    methods: {
        handleClick(){
            this.$refs.myInput.value = "没有看到!"
            this.message = "value属性成功修改"
        }
    },
</script>

img

ref在组件上使用

<body>
    <div id="app" style="margin: 30px;">
        <h2>组件的数据传递-通过ref的方式</h2>
        <xm ref="xmref"></xm>
        <hr>
        <input type="text" v-model="text">
        <button type="button" class="btn btn-success" @click="clickEvent">传递数据给子组件</button>
    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            text: ""
        },
        components: {"xm": {
            template: `
                        <div>
                            <p>来自父组件的数据:<span style="color:tomato">{{fromFather}}</span></p>
                            <img :src="src" width="400">
                        </div>`,
            data() {
                return {
                    fromFather: "注意我",
                    src: "./img/2.jpg"
                }
            },
            methods: {
                changeImg(url){
                    this.src = url
                }
            }
        }},


        methods: {
            clickEvent(){
                // this是当前vue的实例
                // this.$refs 是在组件中所有标签设置了ref属性的对象 {xmref:组件对象, xmimg:组件对象}
                // 拿到组件对象,就可以通过组件对象.属性 组件对象.方法 操作数据了
                console.log(this.$refs.xmref.fromFather); // 注意我
                // 在父中修改子的属性,父传子
                this.$refs.xmref.fromFather = this.text
                // 修改图片 操作属性
                // this.$refs.xmref.src = "./img/3.jpg"

                // 修改图片通过ref操作子的方法
                this.$refs.xmref.changeImg("./img/1.jpg")
            }
        },
    })
</script>

</html>

img

动态组件 component

为什么要使用动态属性?

先看看下面的案例,这还是比较少的情况。

<goods v-if="contentType=='商品'"></goods>
<xm-order v-else-if="contentType=='订单'"></xm-order>
<user v-else="contentType=='用户'"></user>
<!-- 想办法优化掉判断 -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
    <style>
        .box {
            display: flex;
            justify-content: center;
        }

        .box-inner {
            width: 200px;
            height: 50px;
            background-color: tomato;
            text-align: center;
            line-height: 50px;
            margin: 10px;
            border: 2px solid yellow;
            outline: 2px solid black;
        }
    </style>
</head>

<body>
    <div id="app">
        <div class="box">
            <!-- 我这里使用的是鼠标滑动事件 mousemove  你也可以使用click点击事件 -->
            <div class="box-inner" @mousemove="contentType='商品'">商品</div>
            <div class="box-inner" @mousemove="contentType='订单'">订单</div>
            <div class="box-inner" @mousemove="contentType='用户'">用户</div>
        </div>

        <p>目前操作的是:<span :style="{color:'red'}">{{content}}</span></p>
        <goods v-if="contentType=='商品'"></goods>
        <xm-order v-else-if="contentType=='订单'"></xm-order>
        <user v-else="contentType=='用户'"></user>

    </div>
</body>
<script>
    let vm = new Vue({
        el: "#app",
        data: {
            contentType: "商品",
            content: "用户",
        },

        components: {
            // 商品组件
            "goods": {
                template: `<p>xx商品热销中</p>`
            },

            // 订单组件
            "xm-order": {
                template: `
                         <label>请输入订单号查询:<input type="text" v-model="num"></label>
                    `
                ,
                data() {
                    return {
                        num: ""
                    }
                }
            },

            // 用户组件
            "user": {
                template: `<h3>尊贵的摸鱼VIP用户 <span style="color:red">{{username}}</span> 欢迎。</h3>`,
                data() {
                    return {
                        username: "小满"
                    }
                }
            }
        },
        watch: {
            contentType() {
                this.content = this.contentType
            }
        }
    })
</script>

</html>

img

使用动态组件优化

注意:如果要使用动态组件,这个名称不能是别的名称,一定要是你的组件名称!

<!-- 把contentType名称改成对应的组件名称即可 -->
<div class="box-inner" @mousemove="contentType='goods'">商品</div>
<div class="box-inner" @mousemove="contentType='xm-order'">订单</div>
<div class="box-inner" @mousemove="contentType='user'">用户</div>

<component :is="contentType"></component>

img

如何使用动态组件(GPT)

动态组件允许在不同的组件之间动态切换。在 Vue 中,可以使用 <component> 元素来实现动态组件的切换。通过在 <component> 元素上使用 :is 属性,可以动态地绑定组件名,从而实现组件的动态切换。

以下是一个示例,演示了如何使用动态组件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>动态组件</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
</head>
<body>
    <div id="app">
        <button @click="currentComponent = 'ComponentA'">显示组件 A</button>
        <button @click="currentComponent = 'ComponentB'">显示组件 B</button>
        <button @click="currentComponent = 'ComponentC'">显示组件 C</button>

        <hr>

        <!-- 动态组件 -->
        <component :is="currentComponent"></component>
    </div>

    <script>
        // 定义组件 A
        const ComponentA = {
            template: '<div>这是组件 A</div>'
        };

        // 定义组件 B
        const ComponentB = {
            template: '<div>这是组件 B</div>'
        };

        // 定义组件 C
        const ComponentC = {
            template: '<div>这是组件 C</div>'
        };

        new Vue({
            el: '#app',
            data: {
                currentComponent: 'ComponentA' // 默认显示组件 A
            },
            components: {
                ComponentA,
                ComponentB,
                ComponentC
            }
        });
    </script>
</body>
</html>

在这个示例中,有三个按钮,分别用于切换不同的组件。currentComponent 数据属性用于存储当前显示的组件名称,通过按钮点击事件,可以改变 currentComponent 的值,从而动态切换显示不同的组件。

keep-alive

keep-alive 是 Vue.js 的一个内置组件,用于缓存动态组件,可以将之前访问过的组件保留在内存中,而不是每次切换都重新渲染。这样可以提高组件切换的性能,并且保持组件的状态。通常在需要频繁切换的组件中使用。

将动态组件,放在keep-alive内部即可。

<keep-alive>
    <component :is="contentType"></component>
</keep-alive>
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
    <style>
        div.outer {
            margin: 30px;
        }

        .box {
            display: flex;
            justify-content: center;
        }

        .box-inner {
            width: 200px;
            height: 50px;
            background-color: tomato;
            text-align: center;
            line-height: 50px;
            margin: 10px;
            border: 2px solid yellow;
            outline: 2px solid black;
        }
    </style>
</head>

<body>
    <div id="app" class="outer">
        <div class="box">
            <!-- 我这里使用的是鼠标滑动事件 mousemove  你也可以使用click点击事件 -->
            <div class="box-inner" @mousemove="contentType='goods'">商品</div>
            <div class="box-inner" @mousemove="contentType='xm-order'">订单</div>
            <div class="box-inner" @mousemove="contentType='user'">用户</div>
        </div>

        <p>目前操作的是:<span :style="{color:'red'}">{{content}}</span></p>
        <!-- <goods v-if="contentType=='商品'"></goods>
        <xm-order v-else-if="contentType=='订单'"></xm-order>
        <user v-else="contentType=='用户'"></user> -->

        <keep-alive>
            <component :is="contentType"></component>
        </keep-alive>

    </div>
</body>
<script>
    // 商品组件
    const goods = {
        template: `<p>xx商品热销中</p>`
    }

    // 订单组件
    const xmOrder = {
                template: `
                         <label>请输入订单号查询:<input type="text" v-model="num"></label>
                    `
                ,
                data() {
                    return {
                        num: ""
                    }
                }
            }
    
    // 用户组件
    const user = {
                template: `<h3>尊贵的摸鱼VIP用户 <span style="color:red">{{username}}</span> 欢迎。</h3>`,
                data() {
                    return {
                        username: "小满"
                    }
                }
            }

    let vm = new Vue({
        el: "#app",
        data: {
            contentType: "商品",
            content: "用户",
        },

        components: {
            goods,
            xmOrder,
            user
        },
        watch: {
            contentType() {
                this.content = this.contentType
            }
        }
    })
</script>

</html>

img

插槽

简单使用

  1. 在组件的template中什么都不需要写,写<slot></slot>即可。
  2. 在视图中,组件内部写上需要的内容,即可展示,通常是写在div标签内部的。

插槽的默认值

插槽的默认值是放在template里面的,如果渲染的时候没有给插槽传递参数,那么会使用插槽的默认值,如果渲染的时候传递了值,就使用传递的值。

<!-- 组件的template里面 -->
<slot><span>这里放内容</span></slot>
<body>
    <div id="app">
        <demo>
            <div>
                <p slot="first">小满三岁啦</p>
                <img src="./img/1.jpg" width="400">
                <img src="./img/1.jpg" width="400">
            </div>
        </demo>
    </div>
</body>
<script>
    // 定义一个基础的demo组件
    // 定义了一次,但是传值传递了两次图片,所以页面显示了两次一样的图片
    const demo = {
        template: `
        <slot></slot>
        `
    }

    let vm = new Vue({
        el: "#app",
        components: {
            demo
        }

    })
</script>

</html>

image-20240428210603185

命名插槽

为什么要使用命名插槽

<demo>
    <div slot="a">
        <img src="./img/1.jpg" width="400">
    </div>
    <div slot="c">
        <img src="./img/2.jpg" width="400">
    </div>
</demo>

<script>
    // 定义一个基础的demo组件
    const demo = {
        template: `
            <div>
                 <slot name="a"></slot>
                 <slot name="c"></slot>
            </div>
        `
    }

    let vm = new Vue({
        el: "#app",
        components: {
            demo
        }

    })
</script>

image-20240428212720238

生命周期钩子

无论是自己定义的组件,还是vue实例,都会有这几个生命周期钩子。

函数 调用时间 其他说明
beforeCreate vue实例初始化之前调用
created vue实例初始化之后调用 这里常用于跟后端交互,因为组件已经渲染完成了,因为这个时候变量已经有了,就发送Ajax请求加载数据,然后给变量后续处理。
beforeMount 挂载到DOM树之前调用
mounted 挂载到DOM树之后调用
beforeUpdate 数据更新之前调用
updated 数据更新之后调用
beforeDestroy vue实例销毁之前调用 这个用的也比较多,比如组件创建后创建一个定时器,组件销毁之前清除定时器。 this..$destroy()
destroyed vue实例销毁之后调用

生命周期钩子

image-20240502203712062

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
    <!-- icon图标 -->
    <script src="https://kit.fontawesome.com/0f0be1c400.js" crossorigin="anonymous"></script>
    <!-- bootstrap5 -->
    <link rel="stylesheet" href="E:\vue\css\bootstrap.min.css">
</head>

<body>
    <div id="app" style="margin: 20px;">
        <h1>{{title}}</h1>
        <button class="btn btn-primary" @click="count--">-</button>
        <span>&emsp;{{count}}&emsp;</span>
        <button class="btn btn-primary" @click="count++">+</button>
    </div>
</body>
<script src="E:\vue\js\bootstrap.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.数据名 = 请求会来的数据
            // 可以开始发送初始化渲染的请求了, 比如Ajax
        },
        // 2 挂载阶段
        beforeMount() {
            console.log('beforeMount 模板渲染之前', document.querySelector("h1").innerHTML);
        },
        mounted() {
            console.log('模板渲染之后', document.querySelector("h1").innerHTML);
            // 可以开始操作dom了
        },
        // 3. 更新阶段
        beforeUpdate() {
            console.log('beforeUpdate 数据修改了,视图还没有更新', document.querySelector('span').innerHTML);
        },
        updated() {
            console.log('updated 数据修改了,视图已经更新', document.querySelector('span').innerHTML);
        },
        // 4. 卸载阶段
        beforeDestroy() {
            // 正常关闭浏览器就卸载了,不过这样就没有办法演示了
            // 卸载并不会清空之前已经渲染好的dom,只是如果操作卸载了那么页面的更vue的所有操作都会失效。
            // 官方提供了一个卸载函数 Vue对象.$destroy()
            console.log('beforeDestroy 卸载前');
            console.log('清除一些vue资源以外的资源占用 比如定时器 延时器等');
        },
        destroyed() {
            console.log('destroyed 卸载后');
        },
    })
</script>

</html>

img

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
</head>
<body>
    <!-- <div id="app">
        <h2>组件的使用</h2>
        <button @click="handleShow">显示/隐藏组件</button>
        <hr>
        <child v-if="isShow"></child>
        <hr>
    </div> -->

    <div id="app">
        <h2>组件的使用</h2>
        <button @click="handleShow">显示/隐藏组件</button>
        <hr>
        <child v-if="isShow"></child>
        <hr>
    </div>
    
</body>
<script>
    let baseAssembly = {
        template: `<div>
                        <button @click="clickEvent">{{title}}</button>
                    </div>`,
        data(){
            return {
                title: "点我",
                name: '小满'
            }
        },
        methods: {
            clickEvent(){
                this.title = "看到大乔了吗?"
                alert("小满三岁啦!")
            }
        },
        // 加载之前
        beforeCreate() {
            console.log('beforeCreate');  // beforeCreate
            console.log(this.name);  // undefined  因为是创建之前,所以还拿不到数据
            console.log(this.$el)  // undefined  注意取模板需要通过 $el去取
        },
        // 
        created() {
            console.log('created');  // created
            console.log(this.name);  // 小满
            console.log(this.$el)  // undefined  
        },

        // 挂载之前
        beforeMount() {
            console.log('beforeMount');  // beforeMount
            console.log(this.name);  // 小满
            console.log(this.$el)  // 有数据了,就是body中自己定义的DOM   
        },

        mounted() {
            console.log('mounted');  // mounted
            console.log(this.name);  // 小满
            console.log(this.$el)  // 有数据了,就是body中自己定义的DOM   
        },

        // 数据发生变化才会执行
        beforeUpdate() {
            console.log("beforeUpdate");
        },

        // 
        updated() {
            console.log("updated");
        },

        // 删除之前
        beforeDestroy() {
            console.log("beforeDestroy");
        },

        // 删除之后
        destroyed() {
            console.log("destroyed");
            console.log("组件已被销毁");
        },
    }

    // 调用全局组件,实际是变量的传参
    Vue.component("child", baseAssembly)

    let vm = new Vue({
        el: "#app",
        data: {
            isShow: true
        },
        methods: {
            handleShow: function(){
                this.isShow = !this.isShow
            }
        }
    })
</script>
</html>

img

生命周期钩子案例(启动计时器,销毁计时器)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>模板</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.5.0/axios.js"></script>
</head>

<body>
    <div id="app">
        <button @click="handleClick">销毁组件</button>
        <child v-if="isShow"></child>
    </div>
</body>
<script>
    let baseAssembly = {
        template: `<div>
                        <p>{{title}}</p>
                    </div>`,
        data() {
            return {
                timer: null,
                title: "一切都是最好的安排"
            }
        },
        created() {
            this.timer = setInterval(function () {
                console.log("小满最棒啦!");
            }, 1000)
        },
        beforeDestroy() {
            clearInterval(this.timer)
            this.timer = null

            console.log("计时器已被销毁!");
        },
    }

    Vue.component("child", baseAssembly)

    // 根组件
    let vm = new Vue({
        el: "#app",
        data: {
            isShow: true
        },
        methods: {
            handleClick(){
                this.isShow = !this.isShow
                
            }
        },


    })
</script>

</html>

img

posted @ 2024-04-28 03:02  小满三岁啦  阅读(5)  评论(0编辑  收藏  举报