DC's blog DC's blog
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)

DC

愿我一生欢喜,不为世俗所及.
首页
  • 计算机基础
  • linux基础
  • mysql
  • git
  • 数据结构与算法
  • axure
  • english
  • docker
  • opp
  • oop
  • 网络并发编程
  • 不基础的py基础
  • 设计模式
  • html
  • css
  • javascript
  • jquery
  • UI
  • 第一次学vue
  • 第二次学vue
  • Django
  • drf
  • drf_re
  • 温故知新
  • flask
  • 前后端不分离

    • BBS
    • 订单系统
    • CRM
  • 前后端部分分离

    • pear-admin-flask
    • pear-admin-django
  • 前后端分离

    • 供应链系统
  • 理论基础
  • py数据分析包
  • 机器学习
  • 深度学习
  • 华中科大的网课
  • cursor
  • deepseek
  • 杂文
  • 罗老师语录
  • 关于我

    • me
  • 分类
  • 归档
GitHub (opens new window)
  • html

  • css

  • javascript

  • jquery

  • UI库

  • 第一次学vue

    • 基础语法(1)
    • 基础语法(2)
    • Vue生命期钩子
    • 基础语法(3)
      • axios
        • 发送get请求
        • 前端显示电影
      • 计算属性
        • 首字母大写
        • 过滤案例
        • 修改计算属性
      • 监听属性
      • 组件化开发
        • 全局组件
        • 局部组件
      • 组件通信
        • 父子通信之父传子
        • 父子通信之子传父
        • 事例1
        • 事例2
        • ref属性
      • 动态组件
        • 基本使用
        • keep-alive的使用
      • slot插槽
        • 不具名插槽
        • 具名插槽
    • Vue-cli
    • 插件的使用(1)
    • 插件的使用(2)
    • 总结
  • 第二次学vue

  • 前端
  • 第一次学vue
DC
2023-10-16
目录

基础语法(3)

# axios

ajax是前后端交互的一个技术.
原生的js就可以实现发送ajax请求,但存在不同浏览器之间兼容性的问题. jquery实现的ajax了解决这个问题.
但在vue里不推崇使用jquery.. 所以在vue里一般使用第三方的axios模块实现向后端发送ajax请求!!
Ps: 第三方模块fetch 不是所有浏览器都支持, 无需掌握.

扩展: xml - json, 还有一个ProtoBuf(微服务中广泛应用,远程调用中会经常使用到)
服务网格istio

# 发送get请求

后端代码

这里使用flask来实现后端.. 因为简单的案例使用轻量的flask比较方便.

from flask import Flask, jsonify, make_response

app = Flask(__name__)


@app.route('/')
def index():
    obj = make_response(jsonify({"name": "lqz", "age": 19}))
    obj.headers['Access-Control-Allow-Origin'] = '*'  # -- 在请求头里加入数据,解决跨域问题
    return obj


if __name__ == '__main__':
    app.run()
    
"""若是Django,也需要在请求头中进行配置
def index(request):
    res = JsonResponse({"name":"lqz","age":19})
    res['Access-Control-Allow-Origin'] = '*'  # 允许任何域(协议+域名+端口)向我发送请求!
    return res
"""
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>跟后端交互</title>
    <script src="./js/vue.js"></script>
    <!-- 引入axios的CDN  -->
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="box">
    <button @click="handleClick">获取数据</button>
    <p>姓名:{{name}}</p>
    <p>年龄:{{age}}</p>
</div>
</body>
<script>
    let vm = new Vue({
        el: '#box',
        data: {
            name: "",
            age: 0,
        },
        methods: {
            handleClick() {
                // 用axios向后端发送get请求. res就是返回的数据
                // 报错:csrf跨域问题.虽然前端和后端地址都是127.0.0.1,但端口号不一样. --浏览器的安全策略.
                //     前后端混合发送get请求没有报错,是因为前后端的ip端口是同一个.
                // 浏览器为啥要有这个安全策略?若无此策略,可只写前端去其它服务器偷数据.Hhh
                // 解决:在后端处理跨域问题.需要往响应头里加东西.
                axios.get('http://127.0.0.1:5000/').then(res => {
                    // 我们需要的数据/后端给的数据 在res这个对象的data属性里,no why.
                    console.log(res.data) // {age: 19, name: 'lqz'}
                    this.name = res.data.name
                    this.age = res.data.age
                // 出了异常执行catche中的代码
                }).catche(res=>{})
            }
        }
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 前端显示电影

a.json

{
  "status": 0,
  "data": {
    "films": [
      {
        "filmId": 6165,
        "name": "阿凡达:水之道",
        "poster": "https://pic.maizuo.com/usr/movie/fceeb41a1660d097d02fbcbda3191d8f.jpg",
        "actors": [
          {
            "name": "詹姆斯·卡梅隆",
            "role": "导演",
            "avatarAddress": "https://pic.maizuo.com/usr/movie/4da6b697aabe63657edd65aa1b660a04.jpg"
          },
          {
            "name": "萨姆·沃辛顿",
            "role": "杰克·萨利 Jake Sully",
            "avatarAddress": "https://pic.maizuo.com/usr/movie/c0802754994c52632632fa14a9d8b2c6.jpg"
          },
        ],
        "director": "詹姆斯·卡梅隆",
        "category": "动作|冒险|科幻",
      },
      {
        "filmId": 6179,
        "name": "绝望主夫",
        "poster": "https://pic.maizuo.com/usr/movie/495ff91096e9de224acc3746ec42d002.jpg",
        "actors": [
          {
            "name": "张琦",
            "role": "导演",
            "avatarAddress": "https://pic.maizuo.com/usr/movie/6a74150ccda394799bea5762f100a458.jpg"
          },
          {
            "name": "郭祥鹏",
            "role": "王富球",
            "avatarAddress": "https://pic.maizuo.com/usr/movie/7560bab5eaef8e60ecfc333a49c082d8.jpg"
          }
        ],
        "director": "张琦",
        "category": "喜剧",
      }
    ],
    "total": 21
  },
  "msg": "ok"
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

后端代码

from flask import Flask, jsonify, make_response
import json

app = Flask(__name__)


@app.route('/')
def index():
    with open('a.json', 'r', encoding='utf-8') as f:
        res = json.load(f)
    obj = make_response(jsonify(res))
    obj.headers['Access-Control-Allow-Origin'] = '*'
    return obj


if __name__ == '__main__':
    app.run()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>显示电影</title>
    <script src="./js/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="box">
    <ul>
        <li v-for="item in dataList">
            <p>电影标题 - {{item.name}}</p>
            <p>电影主演 - {{item.director}}</p>
            <img :src="item.poster" alt="" style="height: 100px">
        </li>
    </ul>
</div>
</body>
<script>
    let vm = new Vue({
        el: '#box',
        data: {
            dataList: []
        },
        // 在生命周期函数create里向后端发送请求拿电影数据!
        // 在mounted里发不好,因为mounted已经加载页面了,拿到数据后是更新.会消耗资源.
        created() {
            axios.get('http://127.0.0.1:5000/').then(res => {
                console.log(res.data)
                this.dataList = res.data.data.films
            })
        }
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36


# 计算属性

计算属性是基于它们的依赖 进行缓存 的. 计算属性只有在它的相关依赖发生改变时才会重新求值.
这就意味着只要 msg2 未发生改变, 多次访问 getMsg 计算属性会立即返回之前的计算结果,而不必再次执行函数.

在页面中出现多次,只会出现一次, 该方法当属性用!!方法内会return值.
既然当属性用,就可以v-for v-if

其实, 看官方文档是最直接的. 我看了一遍, 很好理解!! https://cn.vuejs.org/guide/essentials/computed.html

# 首字母大写

把用户输入的字符串首字母变大写并显示.
如果使用普通的方法去显示, 那么每次其他地方的数据更新时, 这个方法也会执行, why? (实验下来,确实如此.)
"即使用函数的方式实现, 只要页面更新/页面中有地方变化, 就会再次执行页面中有的函数!!"

所以就需要用到计算属性..

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算属性</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
    {{one()}}
    <!-- 方式一:直接在插值中使用js语法实现..-->
    <input type="text" v-model="msg">
    <p>js语法实现:{{msg.substring(0,1).toUpperCase()+msg.substring(1)}}</p>
    <br>
    <!-- 方式二:写成一个函数..-->
    <!-- getMsg函数返回什么,这里就显示什么.-->
    <input type="text" v-model="msg1">
    <p>{{getMsgMethod()}} {{getMsgMethod()}}</p>
    <br>
    <!-- 方式三:使用计算属性..-->
    <input type="text" v-model="msg2">
    <p>{{getMsg}} {{getMsg}}</p>
</div>
</body>
<script>
    let vm = new Vue({
        el: '#box',
        data: {
            msg: "lqz",
            msg1: "dc",
            msg2: "egon",
        },
        methods: {
            getMsgMethod() {
                console.log('func do.')
                return this.msg1.substring(0, 1).toUpperCase() + this.msg1.substring(1)
            },
            one() {
                console.log('hello')
            }
        },
        computed: {
            getMsg() {  // 依赖的状态改变了,才会重新计算 getMsg这个计算属性相关的依赖就是msg2这个变量
                console.log('attr do.')
                return this.msg2.substring(0, 1).toUpperCase() + this.msg2.substring(1)
            }
        }
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

注意观察, html中代码写了两个 {/{getMsg}},但只打印了一个 ‘attr do’. 证明, 计算属性相对于函数的方式节约了资源!!

Ps: 针对截图中的疑问, 不用纳闷纠结为什么, 只需要知道用函数方式实现, 很耗费资源, 所以就有了计算属性!!

# 过滤案例

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

相比以前的写法.
1> 不需要在input标签中写@input事件,因为 相关依赖改变, 计算属性会重新执行一遍!
2> 不需要额外定义newDataList变量.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>过滤案例</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
    {{datalist}}
    <p><input type="text" v-model="my_text"></p>
    <ul>
        <!-- 计算属性newList,newList函数返回啥,newList就是啥 -->
        <li v-for="data in newList">{{data}}</li>
    </ul>
</div>
</body>
<script>
    let vm = new Vue({
        el: '#box',
        data: {
            my_text: '',
            datalist: ['aaa', 'abc', 'abcde', 'abcdef', 'bbb', 'bac'],
        },
        computed: {
            newList() {
                /*
                let newList = this.datalist.filter(item => {
                    return item.indexOf(this.my_text) > -1
                })
                return newList
                 */
                // 只要input框中my_text数据发生变化,newList就会重新计算
                // 只要一重新运算,虚拟dom会重新渲染补丁,v-for重新循环,实现联动.
                return this.datalist.filter(item => item.indexOf(this.my_text) > -1)
            },
        },
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 修改计算属性

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>计算属性</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
    firstText: <input type="text" v-model="firstText"> <br>
    lastText: <input type="text" v-model="lastText"> <br>
    computed Only read: <input type="text" v-model="mergeText1"> <br>
    computed Read And write: <input type="text" v-model="mergeText2">
</div>
</body>
<script>
    let vm = new Vue({
        el: '#box',
        data: {
            firstText: "Hello",
            lastText: "world",
        },
        computed: {
            mergeText1() {
                return this.firstText + ' ' + this.lastText;
            },
            mergeText2: {
                get() {
                    return this.firstText + ' ' + this.lastText;
                },
                set(newValue) {
                    console.log(newValue);
                    [this.firstText, this.lastText] = newValue.split(' ')
                }
            }
        }
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

image-20231008130614940


# 监听属性

监听属性, 即vue对象中data中的变量发生了变化就会执行对应函数, 函数名要用变量名.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>监听属性</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
    <input type="text" v-model="name">
</div>
</body>
<script>
    let vm = new Vue({
        el: '#box',
        data: {
            name: ""
        },
        watch: {
            name() {
                console.log('name值发生了变化')
            }
        }
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

应用场景: 分类筛选时使用.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>监听属性</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
    <span @click="categoryType='美女'">美女</span> |
    <span @click="categoryType='帅哥'">帅哥</span> |
    <span @click="categoryType='其他'">其他</span>
</div>
</body>
<script>
    let vm = new Vue({
        el: '#box',
        data: {
            categoryType: ""
        },
        watch: {
            categoryType(val) {
                console.log('categoryType值发生了变化')
                console.log(val)
                // ★ 在此处向后端发送请求,得到相应分类的数据,在页面上通过for循环进行展示!!
            }
        }
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

image-20231007170203657


# 组件化开发

1> 自定义组件需要有一个root element, 一般包裹在一个div中 模版的内容有且仅只能包裹在一个标签里
2> 父子组件的data是无法共享 -- 所以需要 组件通信 !
3> 组件可以有data,methods,computed等, 但是data 必须是一个函数

经过实验, 根组件vm要写在子组件后面.. 别问为啥, 就是这么一个现象.

# 全局组件

全局组件即整个页面中都可以使用的组件. 注意,多次复用的话,它们是相互隔离,互不影响的!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组件化开发</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box1">
    <child></child>
    <br>
    <child></child>
</div>
<div id="box2">
    <child></child>
</div>
</body>
<script>
    obj = {
        // ★ 注意 - 模版的内容有且仅只能包裹在一个标签里!!当然不一定非得是div.
        template: `
          <div>
            <h3>我是子组件</h3>
            <button @click="handleClick">点击我!-{{ name }}</button>
          </div>
        `,
        // ★ data必须是个函数,只不过这里用es6语法简写了, data:function(){}
        // ★ 并且该函数必须返回一个对象!
        /* why?
           因为该组件可以在多个地方使用,若data是一个对象,那么这多个地方使用的是同一个引用/同一内存地址,数据容易混乱
           但若写成函数,每次都返回一个新的对象/一份新的数据,就不会出现数据混乱的问题!!
        */
        data() {  // 相当于vue实例中的data
            return {  // return里面写变量
                name: 'lqz'
            }
        },
        methods: {
            handleClick() {  // 其余的定义与vue实例一样
                console.log('Hello World!')
            }
        }
    }
    // -- 定义一个全局组件
    //    参数一:组件名字;参数二:传一个对象(有模版、数据、方法、生命周期钩子函数、计算属性等),此处单独提出来写了.
    Vue.component('child', obj)

    let vm1 = new Vue({
        el: '#box1',
        data: {},
    })

    let vm2 = new Vue({
        el: '#box2',
        data: {},
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 局部组件

局部组件只能在某个组件中使用,即定义它的vue对象绑定的标签中使用.

示例代码是在全局组件中定义了一个局部组件, 当然你可以在 vue实例中定义一个局部组件!!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>组件化开发</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
    <child></child>
</div>
</body>
<script>
    // 在全局组件中定义一个局部组件
    Vue.component('child', {
        template: `
            <div>
                <h3>我是子组件</h3>
                <button @click="handleClick">点击我!-{{name}}</button>
                <header1></header1>
            </div>
        `,
        data() {
            return {
                name: 'lqz'
            }
        },
        methods: {
            handleClick() {
                console.log('Hello World!')
            }
        },
        // 定义局部组件,可以写多个.
        // 此处的局部组件只能在名为'child'的全局组件中使用
        /* 举一反三: 
           在该名为header1的局部组件中,再定义一个名为header2的局部组件
           那么名为header2的局部组件《只能在header1的局部组件的模版中》通过<header2></header2>的方式使用*/
        components: {
            // 'header1'的引号可省略.
            'header1': {
                template: `<h6>我是局部组件!-{{msg}}</h6>`,
                data() {
                    return {
                        msg:'SB.'
                    }
                },
                methods: {},
            }
        }
    })

    let vm = new Vue({
        el: '#box',
        data: {},
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57


# 组件通信

# 父子通信之父传子

通过 自定义属性 实现!

需求: 子组件child中想使用vm父组件中的数据msg和age.
直接在子组件child中通过{//{msg}}、{//{age}}来调用,是会报错的,报错没有定义.

step1: 在子组件标签上自定义一个属性,属性名随便起,通过属性指令绑定父组件中的一个变量.
step2: 在子组件中定义一个props,它是一个数组,在其中进行注册,写子组件标签上["自定义的属性名"].
step3: 可通过{\{自定义的属性名}} 的方式在子组件中使用!
此处在子组件中注册了两个变量my_msg、my_age, 对应父组件中的msg、age!!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>父传子</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
    <!-- 在组件上自定义属性,通过属性指令绑定好变量!-->
    <child :my_msg="msg" :my_age="age"></child>
</div>
</body>
<script>
    Vue.component('child', {
        template: `
            <div>
                <h3>我是子组件</h3>
                父组件传递到子组件的内容是:>><br> 
                {{my_msg}} .. {{my_age}}
            </div>
        `,
        methods: {},
        // 在props进行注册
        props: ['my_msg', 'my_age'],
        // ★ 扩展:还可以写成对象形式,进行属性认证,限制自定义属性类型
        //       若父组件传递过来的数据不是指定的类型,会warn.但也会显示.
        // props: {
        //     my_msg: String, // 意味着接受父组件传过来的my_msg,必须是String类型的数据!!S是大写的!!
        //     my_age: Number,
        // }
    })

    let vm = new Vue({
        el: '#box',
        data: {
            msg: "我是父组件的数据!",
            age: 19,
        },
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 父子通信之子传父

通过 自定义事件 实现!

step1: 在子组件标签上自定义一个事件,该事件绑定一个函数; 固定写法 @自定义事件名="函数名" (该事件函数是编写在父组件里的)             该函数定义在父组件里,定义时需要接受子组件传递过来的参数.子组件传递了几个参数该函数定义时就有多少个形参!
step2: 点击子组件中的按钮, 在该点击事件中, 触发父组件中自定义事件对应函数的执行,并且传入当前子组件需要传给父组件的变量.
            如何实现呢? 固定写法 this.$emit('自定义事件名', 自定义事件绑定方法所需参数1, 参数2)

# 事例1
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子传父</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box" style="border: 1px solid red;width: 270px;height: 250px">
    <h4>父组件接受到子组件传递的值:{{parentName}}</h4>
    <!-- myevent是随便起的一个事件名,其值直接写函数名即可!! -->
    <!--
      虽然handleReceive函数需要接受值,但这里写成handleReceive(childName)不得行!!
      因为父组件中没有childName变量,会报错未定义.
      经过实验,这里写成handleReceive()也不得行!! ★ so,切记,子传父时,此处写个函数名即可!固定用法.
     -->
    <child @myevent="handleReceive"></child>
</div>
</body>
<script>
    Vue.component('child', {
        template: `
          <div style="border: 1px solid orange;width: 250px;height: 160px;margin-left: 10px">
            <input type="text" v-model="childName"> -->  {{ childName }}
            <br>
            <button @click="handleClick">点击我</button>
            <br>
            <div style="color: lightcoral">
              1> 输入框中输入值,输入框里的内容双向绑定到子组件的childName变量里 <br>
              2> 再点击按钮,将该变量传递给父组件!
            </div>
          </div>
        `,
        data() {
            return {
                childName: ""
            }
        },
        methods: {
            handleClick(childName) {
                // 点击该按钮,触发父组件中自定义事件handleReceive的执行,并且传入当前子组件中的变量childName
                // 如何做? 记住,固定写法 this.$emit('自定义事件名', 自定义事件绑定方法所需参数1, 参数2)
                this.$emit('myevent', this.childName)
            }
        }
    })

    new Vue({
        el: '#box',
        data: {
            parentName: ""
        },
        methods: {
            handleReceive(childName) {
                this.parentName = childName
            }
        }
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

image-20231007213951918

# 事例2

需求: 想点击按钮,让子组件消失.Hhh -- 普通方式;子传父的方式.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子传父</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
    <div>
        <!-- **普通方式-->
        <button @click="isShow_0=!isShow_0">点击隐藏显示</button>
        <child v-show="isShow_0"></child>
    </div>

    <div>
        <!-- **子传父方式-->
        <!-- 通过自定义事件实现,事件名随便起,事件绑定方法 -->
        <!-- ★ 注意:尽管绑定的方法需要参数,这里也只写方法名即可,子组件会传过去的!! -->
        <child v-if="isShow" @myevent="handleShow"></child>
    </div>

</div>
</body>
<script>
    Vue.component('child', {
        template: `
            <div>
                <h3>我是子组件</h3>
                <button @click="handleClick">点击子组件消失.</button>
            </div>
        `,
        data() {
            return {
                b: false
            }
        },
        methods: {
            handleClick() {
                // 想点击子组件里的按钮,触发父组件中子组件标签里自定义的myevent事件的执行!!
                // myevent绑定的函数需要几个参数,就可以传几个参数
                this.$emit('myevent', this.b)  // 把子组件中的变量b传入myevent事件对应的方法中
                // this.$emit('myevent', false)  // 直接传递bool值false
            }
        },
    })
    let vm = new Vue({
        el: '#box',
        data: {
            isShow_0: true,
            isShow: true,
        },
        methods: {
            handleShow(b) {
                this.isShow = b
            }
        }
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

# ref属性

在Vue中通过 this.$refs.ref属性的属性值 拿到的是:
        如果 普通标签 设置ref属性, 拿到的就是 原生节点/普通标签本身, 可以执行原生的dom操作; (用的很少)
        如果 子组件 设置ref属性, 拿到的就是 子组件对象
                - 即通过子组件对象.直接获取修改子组件的变量,直接执行子组件的方法,子组件的方法有参数就传值,有返回值就接收.

ref属性很常用,也很好用.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ref属性</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="box">
    <input type="text" ref="myinput" name="lqz" v-model="msg">
    <child ref="mychild"></child>
    <button @click="handleClick">点击我试一试!</button>
</div>
</body>
<script>
    Vue.component('child', {
        template: `
            <div>
                <h3>我是子组件</h3>
                {{b}}
            </div>
        `,
        data() {
            return {
                b: true
            }
        }, 
        methods: {
            handle1(msg){
                console.log('执行子组件的方法handle1!')
                console.log(msg)
                return 'hello'
            }
        },
    })

    let vm = new Vue({
        el: '#box',
        data: {
            msg: 'Hello',
            xxx: '',
        },
        methods: {
            handleClick() {
                // -- 放到普通标签上
                // this.$refs.myinput就是input标签
                console.log(this.$refs.myinput)  // <input type="text" name="lqz">
                // 可以拿到input框里的内容和input的name属性的值 -- 原生js就支持这么做
                console.log(this.$refs.myinput.value, this.$refs.myinput.name)  // Hello lqz

                // -- 放到子组件标签上
                // this.$refs.mychild就是子组件对象,相当于拿到了子组件中的this!! 就无需纠结子传父还是父传子了.
                console.log(this.$refs.mychild)
                // 拿到子组件对象中的变量
                console.log(this.$refs.mychild.b)  // true
                // 可以改子组件对象中的变量的值
                this.$refs.mychild.b = !this.$refs.mychild.b
                // 当然可以将子的b给了父的xxx
                this.xxx = this.$refs.mychild.b
                // 在父组件中直接调用子组件对象的方法 传值,接收返回值
                let res = this.$refs.mychild.handle1("致命打鸡")
                console.log(res)
            }
        }
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67


# 动态组件

# 基本使用

动态切换组件主要通过component配合is属性, 决定哪一个组件显示.
<component :is='组件名'></component>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>动态组件</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="box" style="margin: 10px">
    <button @click="who='index'">首页</button>&nbsp;&nbsp;
    <button @click="who='girl'">美女</button>&nbsp;&nbsp;
    <button @click="who='boy'">帅哥</button>
    <div style="border: orange 1px solid;width: 123px;height: 50px;margin-top: 10px">
        <!-- 可以用v-if来实现组件的显示与否,但这种方式不好,我们可以用动态组件来实现 -->
        <!-- is属性的值是哪个组件名,就显示哪个组件的内容!  -->
        <component :is="who"></component>
    </div>
</div>
</body>
<script>
    Vue.component('index', {template: `<div>这是首页</div>`,})
    Vue.component('girl', {template: `<div>这是美女页面</div>`,})
    Vue.component('boy', {template: `<div>这是帅哥页面</div>`,})
    new Vue({
        el: '#box',
        data: {
            who: 'index'
        },
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

PS: 该需求的实现方案有很多, 比如还可以通过 if-else来实现, 但不如 动态组件写起来简便.

# keep-alive的使用

页面内容保留.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>keep-alive</title>
    <script src="./js/vue.js"></script>
</head>
<body>
<div id="box" style="margin: 10px">
    <button @click="who='index'">首页</button>&nbsp;&nbsp;
    <button @click="who='girl'">美女</button>&nbsp;&nbsp;
    <button @click="who='boy'">帅哥</button>
    <div style="border: orange 1px solid;width: 158px;height: 50px;margin-top: 10px">
        <keep-alive>
            <component :is="who"></component>
        </keep-alive>
    </div>
</div>
</body>
<script>
    Vue.component('index', {template: `<div>这是首页</div>`,})
    Vue.component('girl', {
        template: `<div>这是美女页面 <input type="text"></div>`,
    })
    Vue.component('boy', {template: `<div>这是帅哥页面</div>`,})
    new Vue({
        el: '#box',
        data: {
            who: 'index'
        },
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


# slot插槽

# 不具名插槽

默认插槽: 将子组件标签包裹的所有内容,放到solt标签所在的位置!!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>插槽</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
    <home>
        <!-- 若无插槽,子标签里的html代码是不会在页面上显示的 --> 
        <div>人类终将毁灭,世界属于三体.</div>
    </home>
    <hr>
    <home>
        <!-- 若无插槽,子标签里的html代码是不会在页面上显示的 --> 
        <div>愿我一生欢喜,不为世俗所及.</div>
    </home>
</div>
</body>
<script>
    Vue.component('home', {
        template:`
            <div>
                <h4>This is home.</h4>
                <slot></slot>
            </div>
        `
    })
    new Vue({
        el: '#box',
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

image-20231008140727198

# 具名插槽

标签属性slot的值对应slot标签name属性的值!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>插槽</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
    <home>
        <div slot="top">哇哦!</div>
        <div slot="bottom">起飞!</div>
        <!-- PS:若无不具名插槽,那么该行代码不会在页面上渲染显示出来;有不具名插槽的话,会显示在不具名插槽处! -->
        <div>...</div>
    </home>
</div>
</body>
<script>
    Vue.component('home', {
        template:`
            <div>
                <slot name="top"></slot>
                <h4>This is home.</h4>
                <slot name="bottom"></slot>
            </div>
        `
    })
    new Vue({
        el: '#box',
    })
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

image-20231008141243959


Vue生命期钩子
Vue-cli

← Vue生命期钩子 Vue-cli→

最近更新
01
deepseek本地部署+知识库
02-17
02
实操-微信小程序
02-14
03
教学-cursor深度探讨
02-13
更多文章>
Theme by Vdoing | Copyright © 2023-2025 DC | One Piece
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式