首页 > 其他分享 >Vue

Vue

时间:2024-05-08 17:15:02浏览次数:25  
标签:Vue console log vue data name

VUE2

(1)介绍

VUE是渐进式框架

可以一点一点地使用它,只用一部分,也可以整个工程都使用它

Vue特点

易用

  • 通过 HTML、CSS、JavaScript构建应用

灵活

  • 不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩。

高效

  • 20kB min+gzip 运行大小
  • 超快虚拟 DOM
  • 最省心的优化

image

(2)引入vue

vue2

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

vue3

<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

(3)M-V-VM思想

(1)介绍

MVVM 是Model-View-ViewModel 的缩写,它是一种基于前端开发的架构模式,是一种事件驱动编程方式

  • Model :vue对象的data属性里面的数据,这里的数据要显示到页面中
  • View :vue中数据要显示的HTML页面,在vue中,也称之为“视图模板” (HTML+CSS)
  • ViewModel:vue中编写代码时的vm对象,它是vue.js的核心,负责连接 View 和 Model数据的中转,保证视图和数据的一致性,所以前面代码中,data里面的数据被显示中p标签中就是vm对象自动完成的(双向数据绑定:JS中变量变了,HTML中数据也跟着改变)

image

MVVM的特性

  • 低耦合视图(View)可以独立于Model变化和修改,1个ViewModel可以绑定到不同的View上,当View变化的时候 Model可以不变,当Model变化的时候,View也可以不变
  • 可复用:可以把一些视图逻辑放在1个ViewModel中,让很多View重用这端视图的逻辑(以此减少代码冗余)
  • 独立开发开发人员可以专注于业务逻辑数据的开发(ViewModel),设计人员可以专注于页面设计
  • 可测试:界面元素是比较难以测试的,而现在的测试可以针对ViewModel来编写

MVVM的逻辑

image

组件化开发、单页面开发

组件化开发

类似于DTL中的include每一个组件的内容都可以被替换复用

image

单页面开发

只需要1个页面,结合组件化开发来替换页面中的内容

页面的切换只是组件的替换,页面还是只有1个index.html

(4)简单使用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="firstdiv">
    {{name}}
</div>
</body>

<script>
    var vm = new Vue({
        'el': '#firstdiv',
        'data': {
            name: 'heart'
        }
    })

</script>
</html>

image

(5)模板语法

(1)插值语法

语法:{{ 变量、js语法、三目表达式 }}

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>

<div id="test">
    <h1>字符串:{{name}}</h1>
    <h1>数值:{{age}}</h1>
    <h1>数组:{{list1}} 取值:{{list1[0]}}</h1>
    <h1>对象:{{obj1}} 取值:{{obj1.age}}</h1>
    <h1>字符串:{{link1}}</h1>
    <h1>运算:{{10 + 20 + 30 + 40}}</h1>
    <h1>三目运算符:{{10 > 20 ? '是' : '否'}}</h1>
</div>

</body>
<script>
    let vm = new Vue({
        el: '#test', // 在test这个div中可以写 vue的语法
        data: {
            name: 'heart', // 字符串
            age: 18, // 数值
            list1: [1, 2, 3, 4],   // 数组
            obj1: {name: 'god', age: 19}, // 对象
            link1: '<a href="https://www.baidu.com">百度一下 你就知道</a>'
        }
    })
</script>
</html>

image

(6)指令

(1)文本指令

  • vue中 以v-xx开头的都是vue的指令系统
  • 指令都放在标签上
指令 释义
v-html 让HTML渲染成页面
v-text 标签内容显示js变量对应的值
v-show 放1个布尔值:为真 标签就显示;为假 设置标签属性为display: none
v-if 放1个布尔值:为真 标签就显示;为假 直接注释掉标签
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>

<div id="test">
    <h1 v-text="name"></h1>
    <h1 v-html="link1"></h1>
    <h1 v-html="name"></h1>
    <hr>
    <img src="1.jpg" alt="" v-show="showIf" style="height: 300px;width: 300px">
    <img src="2.jpg" alt="" v-if="showShow" style="height: 300px;width: 300px">

</div>

</body>
<script>
    let vm = new Vue({
        el: '#test', // 在test这个div中可以写 vue的语法
        data: {
            name: 'heart', // 字符串
            link1: '<a href="https://www.baidu.com">百度一下 你就知道</a>',
            showIf: true,
            showShow: true
        }
    })
</script>
</html>

image

(2)事件指令

点击事件,双击事件,拖动事件,得到焦点,失去焦点...

v-on:click='函数'
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="div1" style="background-color: pink;width: 200px;height: 200px" v-on:click="handleClick">
</div>
</body>
<script>
    var vm = new Vue({
        el: '#div1',
        methods: {
            handleClick: function () {
                alert('美女')
            }
        }
    })
</script>
</html>

还有一种写法,直接用@代替 v-on:

<div id="div1" style="background-color: pink;width: 200px;height: 200px" @click="handleClick">

事件指令-->函数有参数

  • 不传参数,函数有参数的情况下,会自动把事件对象传入(event)
<body>
<div id="app01">
    <button @click="handlefunc1">不传参数,函数有参数</button>
</div>
</body>
<script>
    var vm = new Vue({
        el: '#app01',
        data: {
            name: 'heart'
        },
        methods: {
            handlefunc1(event) {
                // 如果在事件中触发函数,没有传参数,会自动把事件对象传入
                console.log(event)
                //PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …}
            }
        }
    })
</script>
</html>
  • 传参数,函数有参数的情况下,打印出传入的参数,也可以传对象...
  • 如果传入 isShow 会打印出 true
<body>
<div id="app01">
    <button @click="handlefunc2('heart')">传参数,函数有参数</button>
</div>
</body>

<script>
    var vm = new Vue({
        el: '#app01',
        methods: {
            handlefunc2(event){
                console.log(event) // 控制台打印出 : heart
            }
        }
    })
</script>

</html>
  • 传参数,函数有参数,把事件传入,固定写法$event,也会打印出事件对象
<body>
<div id="app01">
    <button @click="handlefunc3($event)">传参数,函数有参数,传入事件</button>
</div>
</body>

<script>
    var vm = new Vue({
        el: '#app01',
        data: {
            name: 'heart'
        },
        methods: {
            handlefunc3(event){
                console.log(event)
                // PointerEvent {isTrusted: true, pointerId: 1, width: 1, height: 1, pressure: 0, …}
            }
        }
    })
</script>
  • 传参数,有多个参数,少传

    • 不加括号,第一个参数会打印event对象
    • 加了括号,不会自动传入event,只会显示undefined
  • 传参数,多个参数多传,不影响,只会打印出函数上的参数

(3)属性指令

使用变量动态设置属性的值

v-bind:属性名='变量',可以简写成 :属性名='变量',只要写冒号就是绑定

<body>
<div id="app">
    <img :src="url" alt="">
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            url: '../img/godfather.jpg'
        }
    })
</script>
</body>

图片1s切换一张小案例

<body>
<div id="app">
    <img :src="url" alt="" style="height: 300px;width: 300px">
    <button @click="handleChoose">点我换头像</button>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            url: '../img/godfather.jpg',
            url_list: [
                '../img/1.jpg',
                '../img/cj.jpg',
                '../img/zhu.jpg',
            ],
            t: null
        },
        methods: {
            handleChoose() {
                if (this.t != null) {
                    clearInterval(this.t)
                    this.t = null
                } else {
                    var _this = this
                    var count = 0
                    this.t = setInterval(function () {
                        if (count > 2) {
                            count = 0
                        }
                        _this.url = _this.url_list[count]
                        count += 1
                    }, 1000)
                }
            }
        }
    })
</script>
</body>

(7)class和style

(1)class

class属性可以是字符串,数组,对象

字符串 字符串替换控制样式

<style>
    .div1 {
        width: 300px;
        height: 300px;
    }
    .div2 {
        background-color: blue;
    }
    .div3 {
        font-size: 60px;
        color: white;
    }
    .div4 {
        margin: auto;
    }
</style>
<body>
    
<div id="app">
    <h1>class属性</h1>
    <div :class="class_str">heart</div>
    <button @click="handleClick">点我</button>
</div>
    
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            class_str: 'div1 div2'
        },
        methods: {
            handleClick() {
                this.class_str='div1 div2 div3 div4'
            }
        }
    })
</script>
</body>

数组 追加数组,删除数组控制样式

<style>
    .div1 {
        width: 300px;
        height: 300px;
    }
    .div2 {
        background-color: blue;
    }
    .div3 {
        font-size: 60px;
        color: white;
    }
    .div4 {
        margin: auto;
    }
</style>
<body>
<div id="app">
    <h1>class属性</h1>
    <div :class="class_list">heart</div>
    <button @click="handleClick">点我</button>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            class_list : ['div1','div2']
        },
        methods: {
            handleClick() {
                this.class_list.push('div3','div4')
            }
        }
    })
</script>
</body>

对象 里面放true和false,控制样式

<style>
    .div1 {
        width: 300px;
        height: 300px;
    }
    .div2 {
        background-color: blue;
    }
    .div3 {
        font-size: 60px;
        color: white;
    }
    .div4 {
        margin: auto;
    }
</style>
<body>
<div id="app">
    <h1>class属性</h1>
    <div :class="class_obj">heart</div>
    <button @click="handleClick">点我</button>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            class_obj:{div1:true,div2:true,div3:false,div4:true}
        },
        methods: {
            handleClick() {
                this.class_obj.div3=true
            }
        }
    })
</script>
</body>

(2)style

style属性也可以是字符串,数组,对象

字符串 字符串替换控制样式

<body>
<div id="app">
    <h1>style属性</h1>
    <div :style="style_str">heart</div>
    <button @click="handleClick">点我</button>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            style_str :'background-color:blue;height:300px;width:300px;'
        },
        methods: {
            handleClick() {
                this.style_str='background-color:blue;height:300px;width:300px;margin:auto;'
            }
        }
    })
</script>
</body>

数组 追加数组,删除数组控制样式

<body>
<div id="app">
    <h1>style属性</h1>
    <div :style="style_list">heart</div>
    <button @click="handleClick">点我</button>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            style_list: [{'background-color': 'blue'}, {height: '300px'}, {width: '300px'}]
        },
        methods: {
            handleClick() {
                this.style_list.push({margin: 'auto'})
            }
        }
    })
</script>
</body>

对象 根据key修改value控制样式

<body>
<div id="app">
    <h1>style属性</h1>
    <div :style="style_obj">heart</div>
    <button @click="handleClick">点我</button>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            style_obj:{backgroundColor:'red',height:'300px',width:'300px'}
        },
        methods: {
            handleClick() {
                this.style_obj["backgroundColor"]='green'
            }
        }
    })
</script>
</body>

(8)条件渲染if elseif else

  • v-if,v-else-if,v-else
<body>
<div id="app">
    <h1>条件判断</h1>
    <h2>分数是{{score}}</h2>
    <h3 v-if="score>=90&&score<=100">优秀</h3>
    <h3 v-else-if="score>=80&&score<90">良好</h3>
    <h3 v-else-if="score>=60&&score<80">及格</h3>
    <h3 v-else>不及格</h3>

</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            score: 99
        }
    })
</script>
</body>

(9)列表渲染v-for

  • v-for 循环显示多行
  • 还可以循环出索引
  • 在v-for都要在标签上加 :key="key" 但是key必须唯一,会提高虚拟dom的替换效率
v-for="(item,index) in goods_list" :key="index"
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>

<body>
<div id="app">
    <table class="table">
        <thead>
        <tr>
            <th scope="col">id</th>
            <th scope="col">名字</th>
            <th scope="col">价格</th>
            <th scope="col">数量</th>
        </tr>
        </thead>
        <tbody>
        <tr v-for="item in goods_list">
            <td>{{item.id}}</td>
            <td>{{item.name}}</td>
            <td>{{item.price}}</td>
            <td>{{item.count}}</td>
        </tr>
        </tbody>
    </table>
</div>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            goods_list:[
                {id:1001,name:'键盘',price:'1999',count:2},
                {id:1002,name:'鼠标',price:'1599',count:3},
                {id:1003,name:'鼠标垫',price:'199',count:4},
                {id:1004,name:'耳机',price:'666',count:5},
                {id:1005,name:'电脑',price:'99999',count:1}
            ]
        }
    })
</script>
</body>

image

(10)input数据绑定 v-model

只针对的是input标签

(1)单向绑定

  • 在input中输入值,变量不会改变
<body>
<div id="app">
    <input type="text" :value="name">
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            name:'heart'
        }
    })
</script>
</body>

(2)双向绑定

  • 在input中输入值,变量也会跟着变
<body>
<div id="app">
    <input type="text" v-model='name'>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            name:'heart'
        }
    })
</script>
</body>

image

(3)v-model修饰符

  • v-model 是 Vue.js 中用于实现双向数据绑定的指令,它能够自动将表单控件的值与 Vue 实例中的数据进行同步。v-model 修饰符是用来修改 v-model 的行为,以满足特定需求。以下是一些常用的 v-model 修饰符:
  1. .lazy 修饰符:失去焦点(change)触发。
<input v-model.lazy="message">
  1. .number 修饰符:将用户输入的值转换为数值类型。
<input v-model.number="age" type="number">
  1. .trim 修饰符:自动过滤用户输入的首尾空白字符。
<input v-model.trim="username">

这些修饰符可以单独使用,也可以组合使用,以满足不同的需求。

(11)input的事件

  • input : 当输入框进行输入的时候,触发

  • change : 当元素值发生改变,触发

  • blur : 当输入框失去焦点,触发

  • focus : 当获得焦点,触发

(1)input

输入触发

<body>
<div id="app">
    <input type="text" v-model="name" @input="handleInput">{{name}}
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            name:''
        },
        methods:{
            handleInput(){
                console.log('输入了')
            }
        }
    })
</script>
</body>

image

(2)change

修改触发

<body>
<div id="app">
    <input type="text" v-model="name" @change="handleChange">{{name}}
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            name:''
        },
        methods:{
            handleChange(){
                console.log('change了')
            }
        }
    })
</script>
</body>

image

(3)blur

失去焦点触发

<body>
<div id="app">
    <input type="text" v-model="name" @blur="handleBlur">{{name}}
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            name: ''
        },
        methods: {
            handleBlur() {
                console.log('失去焦点了')
            }
        }
    })
</script>
</body>

(4)focus

获得焦点触发

<body>
<div id="app">
    <input type="text" v-model="name" @focus="handleFocus">{{name}}
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            name: ''
        },
        methods: {
            handleFocus() {
                console.log('获得焦点了')
            }
        }
    })
</script>
</body>

(12)过滤

filter() 方法的语法如下:

let newArray = array.filter(callback(element[, index[, array]])[, thisArg])
  • array:要操作的原始数组。
  • callback:用来测试数组的每个元素的函数,接受三个参数:
    • element:当前正在处理的数组元素。
    • index(可选):当前正在处理的数组元素的索引。
    • array(可选):调用 filter 方法的数组。
  • thisArg(可选):执行 callback 函数时的 this 值。

filter() 方法会对数组中的每个元素调用 callback 函数,并根据 callback 函数的返回值来决定是否保留该元素。如果 callback 返回 true,则保留该元素,如果返回 false,则过滤掉该元素。

最终,filter() 返回一个新的数组,其中包含所有满足条件的元素。

例如:

const numbers = [1, 2, 3, 4, 5];

const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // 输出 [2, 4]

在这个例子中,evenNumbers 将包含数组 numbers 中所有偶数元素。

案例

<body>
<div id="app">
    <input type="text" v-model="name" @input="handleInput">
    <hr>
    <ul>
        <li v-for="item in newdata_list">{{item}}</li>
    </ul>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            name: '',
            data_list: ['h', 'he', 'hea', 'go', 'god', 'heart', 'ze', 'zeus'],
            newdata_list: ['h', 'he', 'hea', 'go', 'god', 'heart', 'ze', 'zeus']
        },
        methods: {
            handleInput() {
                var _this = this
                this.newdata_list = this.data_list.filter(function (item) {
                    if(item.indexOf(_this.name)>=0){
                        return true
                    }else{
                        return false
                    }
                })
            }
        }
    })
</script>
</body>

优化版

<body>
<div id="app">
    <input type="text" v-model="name" @input="handleInput">
    <hr>
    <ul>
        <li v-for="item in newdata_list">{{item}}</li>
    </ul>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            name: '',
            data_list: ['h', 'he', 'hea', 'go', 'god', 'heart', 'ze', 'zeus'],
            newdata_list: ['h', 'he', 'hea', 'go', 'god', 'heart', 'ze', 'zeus']
        },
        methods: {
            handleInput() {
                var _this = this
                this.newdata_list = this.data_list.filter(function (item) {
                    return item.indexOf(_this.name)>=0
                })
            }
        }
    })
</script>
</body>

箭头函数版

<body>
<div id="app">
    <input type="text" v-model="name" @input="handleInput">
    <hr>
    <ul>
        <li v-for="item in newdata_list">{{item}}</li>
    </ul>
</div>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            name: '',
            data_list: ['h', 'he', 'hea', 'go', 'god', 'heart', 'ze', 'zeus'],
            newdata_list: ['h', 'he', 'hea', 'go', 'god', 'heart', 'ze', 'zeus']
        },
        methods: {
            handleInput() {
                this.newdata_list = this.data_list.filter((item)=>item.indexOf(this.name)>=0)
            }
        }
    })
</script>
</body>

(13)箭头函数

箭头函数(Arrow Functions)是ES6引入的一种函数表达式,提供了一种更简洁的语法来定义函数。下面是箭头函数的主要用法:

基本语法

// 无参数的箭头函数
const func1 = () => {
  // 函数体
};

// 一个参数的箭头函数,可以省略括号
const func2 = arg => {
  // 函数体
};

// 多个参数的箭头函数
const func3 = (arg1, arg2) => {
  // 函数体
};

// 箭头函数直接返回一个表达式时,可以省略花括号和 return 关键字
const func4 = () => expression;

// 与传统函数不同,箭头函数没有自己的 this 值,它会继承外层作用域中的 this 值

箭头函数作为回调函数

// 传统函数作为回调函数
array.map(function(item) {
  return item * 2;
});

// 箭头函数作为回调函数
array.map(item => item * 2);

箭头函数与解构赋值结合

const arr = [1, 2, 3];

// 使用传统函数和解构赋值
arr.map(function(element) {
  return element * 2;
});

// 使用箭头函数和解构赋值
arr.map(({ prop }) => prop * 2);

箭头函数和数组方法结合

const numbers = [1, 2, 3, 4, 5];

// 使用传统函数
const evenNumbers = numbers.filter(function(num) {
  return num % 2 === 0;
});

// 使用箭头函数
const evenNumbers = numbers.filter(num => num % 2 === 0);

注意事项

  • 箭头函数没有自己的 this 值,它会继承外层作用域中的 this 值。
  • 箭头函数不能用作构造函数,因为它没有 prototype 属性。
  • 箭头函数不能使用 arguments 对象,但可以使用剩余参数(rest parameters)来获取所有传入的参数。
  • 箭头函数不能使用 yield 关键字,因此不能用作 Generator 函数。
  • 如果箭头函数只有一个参数,并且函数体只有一行代码,那么连参数的括号和函数体的花括号都可以省略。

(14)事件修饰符

Vue.js 提供了一些事件修饰符,用于在处理 DOM 事件时提供额外的控制或语法糖。以下是一些常用的 Vue.js 事件修饰符:

  1. .stop

只处理自己的事件,父控件冒泡的事件不处理(阻止事件冒泡)

<button @click.stop="handleClick">阻止冒泡</button>
  1. .prevent

阻止a链接的跳转

<a href="https://www.baidu.com" @click.prevent="handleA">点我</a>
  1. .self

只处理自己的事件,子控件冒泡的事件不处理

<div @click.self="handleClick">只有自身触发</div>
  1. .once

事件只会触发一次

<button @click.once="handleClick">只触发一次</button>

(15)按键事件、修饰符

Vue.js 中的按键修饰符允许监听键盘事件时指定特定的按键。这些修饰符用于在触发事件时过滤按键,以便只在特定的按键被按下时才触发对应的事件处理函数。以下是 Vue.js 中常用的按键修饰符:

  1. .enter

只在回车键按下时触发事件。

<input @keyup.enter="handleEnter">
  1. .tab

只在 Tab 键按下时触发事件。

<input @keyup.tab="handleTab">
  1. .delete / .backspace

只在删除键或退格键按下时触发事件。

<input @keyup.delete="handleDelete">
  1. .esc

只在 Esc 键按下时触发事件。

<input @keyup.esc="handleEsc">
  1. .space

只在空格键按下时触发事件。

<input @keyup.space="handleSpace">
  1. .up

只在上箭头键按下时触发事件。

<input @keyup.up="handleUp">
  1. .down

只在下箭头键按下时触发事件。

<input @keyup.down="handleDown">
  1. .left

只在左箭头键按下时触发事件。

<input @keyup.left="handleLeft">
  1. .right

只在右箭头键按下时触发事件。

<input @keyup.right="handleRight">

这些按键修饰符可以用于 keyupkeydown 事件。帮助我们更精确地控制在特定按键按下时触发事件的情况。

(16)表单控制

在Vue.js中,可以通过使用v-model指令来轻松地实现表单控件的双向数据绑定。这意味着当用户在表单控件中输入内容时,Vue.js会自动更新相关的数据,并且当数据发生改变时,表单控件也会自动更新。

  • checkbox v-model 一定要加value
    • 布尔:选中没选中
    • 数组:多选
  • radio v-model
    • 字符串:value的值
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

</head>
<body>
<div id="app">
    <h1>表单控制</h1>
    <p>用户名: <input type="text" v-model="name"></p>
    <p>密码: <input type="text" v-model="password"></p>
    <p>记住密码: <input type="checkbox" v-model="isChecked"></p>
    <p>爱好: 篮球<input type="checkbox" v-model="hobby" value="篮球">
        足球<input type="checkbox" v-model="hobby" value="足球">
        羽毛球<input type="checkbox" v-model="hobby" value="羽毛球">
    </p>
    <p>性别: 男<input type="radio" v-model="sex" value="男">
        女<input type="radio" v-model="sex" value="女">
    </p>
    <button @click="handleSubmit">登录</button>
</div>
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            name: '',
            password: '',
            isChecked: false,
            hobby: [],
            sex:''
        },
        methods: {
            handleSubmit() {
                console.log(this.name, this.password, this.isChecked, this.hobby,this.sex)
            }
        }
    })

</script>
</html>

购物车案例

for循环渲染出来数据,可以增加商品数量,可以全选,单选,计算总价

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <link rel="stylesheet" href="../css/Bootstrap.css">
    <script src="../js/Bootstrap.js"></script>
</head>

<body>
<div id="app">
    <div class="row">
        <div class="container d-flex justify-content-center">
            <div class="col-6">
                <h1 class="text-center">购物车</h1>
                <table class="table">
                    <thead>
                    <tr>
                        <th scope="col">id</th>
                        <th scope="col">name</th>
                        <th scope="col">price</th>
                        <th scope="col">count</th>
                        <th scope="col">全选 <input type="checkbox" v-model="isChecked" @change="CheckAll"></th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr v-for="item in goods_list">
                        <td>{{item.id}}</td>
                        <td>{{item.name}}</td>
                        <td>{{item.price}}</td>
                        <td>
                            <button @click="btnJian(item)">-</button>
                            {{item.count}}
                            <button @click="item.count++">+</button>
                        </td>
                        <td><input type="checkbox" v-model="goods" :value="item" @change="CheckOne"></td>
                    </tr>
                    </tbody>
                </table>
                总价:{{price_count()}}
            </div>
        </div>
    </div>
</div>
    
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            goods_list: [
                {id: 1001, name: '键盘', price: '1', count: 2},
                {id: 1002, name: '鼠标', price: '2', count: 3},
                {id: 1003, name: '鼠标垫', price: '3', count: 4},
                {id: 1004, name: '耳机', price: '6', count: 5},
                {id: 1005, name: '电脑', price: '9', count: 1}
            ],
            goods: [],
            isChecked: false
        },
        methods: {
            price_count() {
                let count = 0
                for (let item of this.goods) {
                    count += item.price * item.count
                }
                return count
            },
            CheckAll() {
                if (this.isChecked) {
                    this.goods = this.goods_list
                } else {
                    this.goods = []
                }
            },
            CheckOne() {
                if (this.goods.length == this.goods_list.length) {
                    this.isChecked = true
                } else {
                    this.isChecked = false
                }
            },
            btnJian(item) {
                if (item.count > 1) {
                    item.count--
                } else {
                    alert('不能再少了')
                }
            }
        }
    })
</script>
</html>

image

(17)vue和ajax

1 后端-->提供接口-->json形式-->给前端-->前端拿到处理
	-后端接口
    -ajax发送请求
    
2 vue中使用ajax
	1 jquery的ajax
    2 js原生的fetch
    3 第三方axiox(使用最多)

前后端交互,一提交会报错Access-Control-Allow-Origin,这是跨域问题

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app01">
    <h1>vue与ajax</h1>
    <p>姓名:{{name}}</p>
    <p>年龄:{{age}}</p>
    <button @click="handleLoad">点击返回数据</button>
</div>
</body>

<script>
    var vm = new Vue({
        el: '#app01',
        data: {
            name: '',
            age: '',
        },
        methods: {
            handleLoad() {
                $.ajax({
                    url: 'http://127.0.0.1:5000/',
                    method: 'get',
                    success: data => {
                        console.log(data)
                    }
                })
            }
        }
    })
</script>
</html>

image

需要在后端的请求头中配置res.headers['Access-Control-Allow-Origin']='*',由于我使用的是flask框架,所以是这样配,数据正常返回

# -*- coding: utf-8 -*-
# author : heart
# blog_url : https://www.cnblogs.com/ssrheart/
# time : 2024/4/26

from flask import Flask,jsonify

app = Flask(__name__)


@app.route('/')
def index():
    res = jsonify({
        'code':200,
        'msg':'成功',
        'userinfo':{
            'name':'heart',
            'age':18
        }
    })
    res.headers['Access-Control-Allow-Origin']='*'
    return res

if __name__ == '__main__':
    app.run()

image

但是现在一般不使用jquery这种处理数据!!!!

methods: {
    handleLoad() {
        $.ajax({
            url: 'http://127.0.0.1:5000/',
            method: 'get',
            success: data => {
                this.name=data.userinfo.name
                this.age=data.userinfo.age
            }
        })
    }
}

image

使用js原生fetch XMLHTTPRequest 需要做浏览器兼容 所以出了fetch方案

methods: {
    handleLoad() { fetch('http://127.0.0.1:5000/').then(response=>response.json()).then(myJson=>{console.log(myJson);})
            }
        }

使用第三方axiox

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

语法:

发送 GET 请求

axios.get(url, {
  params: {
    key1: 'value1',
    key2: 'value2'
  },
  headers: {
    'Authorization': 'Bearer token123',
    'Content-Type': 'application/json'
  },
  timeout: 5000,
  responseType: 'json'
})
.then(response => {
  console.log(response.data);
})
.catch(error => {
  console.error('Error:', error);
});
  • params 用于指定 GET 请求的 URL 参数。当你需要将数据附加到 GET 请求的 URL 中时,可以使用 params 配置选项。这些参数会被添加到 URL 的末尾,形成查询字符串(query string),例如 https://api.example.com/data?key1=value1&key2=value2。在 Axios 中,params 是一个对象,其中键值对表示参数名和参数值。
  • headers 用于设置请求头(Headers)信息。请求头是发送给服务器的额外信息,例如身份验证信息、内容类型等。在 Axios 中,headers 是一个对象,其中键值对表示请求头的名称和值。你可以在 headers 对象中设置自定义的请求头,例如 AuthorizationContent-Type 等。

发送 POST 请求

使用 Axios 发送 POST 请求通常需要指定要发送的数据和要发送到的 URL。下面是 Axios 发送 POST 请求的基本用法:

axios.post(url, data, config)
  .then(response => {
    // 请求成功时执行的操作
    console.log('请求成功:', response.data);
  })
  .catch(error => {
    // 请求失败时执行的操作
    console.error('请求失败:', error);
  });

在这个示例中,axios.post() 函数接收三个参数:

  1. url:表示要发送请求的 URL。
  2. data:表示要发送的数据,通常是一个 JavaScript 对象。
  3. config(可选):表示请求的配置,比如请求头、超时时间等。

接着,我们使用 .then() 方法和 .catch() 方法来处理请求的响应和错误:

  • .then() 方法用于处理请求成功时的响应,接收一个回调函数作为参数,该回调函数接收一个 response 对象作为参数,其中包含了服务器返回的数据等信息。
  • .catch() 方法用于处理请求失败时的错误,接收一个回调函数作为参数,该回调函数接收一个 error 对象作为参数,其中包含了请求失败的相关信息。

以下是一个完整的示例,演示了如何使用 Axios 发送 POST 请求:

// 定义要发送的数据
const postData = {
  username: 'exampleUser',
  password: 'examplePassword'
};

// 发送 POST 请求
axios.post('http://example.com/api/login', postData)
  .then(response => {
    // 请求成功时执行的操作
    console.log('登录成功:', response.data);
  })
  .catch(error => {
    // 请求失败时执行的操作
    console.error('登录失败:', error);
  });

在这个示例中,我们发送了一个 POST 请求到 http://example.com/api/login,并发送了一个包含用户名和密码的数据对象。当请求成功时,我们打印出了服务器返回的数据,当请求失败时,我们打印出了错误信息。

其他常用方法:

  • axios.get(url[, config]): 发送GET请求。

  • axios.post(url[, data[, config]]): 发送POST请求。

  • axios.put(url[, data[, config]]): 发送 PUT 请求。

  • axios.delete(url[, config]): 发送 DELETE 请求。

  • axios.patch(url[, data[, config]]): 发送 PATCH 请求。

显示电影案例

点击按钮,加载最新电影

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app01">
    <div v-for="item in filmsList">
        <h1>电影信息</h1>
        <p>电影名:{{item.name}}</p>
        <p>海报:<img :src="item.poster" alt="" style="height: 300px;width: 300px"></p>
        <p>简介:{{item.synopsis}}</p>
    </div>
    <button @click="submitdy">点我获取电影信息</button>
</div>
<script>
    var vm = new Vue({
        el: '#app01',
        data: {
            filmsList: []
        },
        methods: {
            submitdy() {
                axios.get('http://127.0.0.1:5000/films').then(
                    response => {
                        console.log(response.data.data.films)
                        this.filmsList=response.data.data.films
                    }
                )
            }
        }
    })
</script>
</body>
</html>s

backend.py

import json
from flask import Flask, jsonify
app = Flask(__name__)

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

if __name__ == '__main__':
    app.run()

image

(18)计算属性computed

  1. 计算属性是基于它们的依赖进行缓存的
  2. 计算属性只有在它的相关依赖发生改变时才会重新求值
  3. 计算属性就像Python中的property,可以把方法/函数伪装成属性
  4. 写在computed中,必须返回值,返回值才是属性,以后当属性用,都能被for循环
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <link rel="stylesheet" href="../css/Bootstrap.css">
    <script src="../js/Bootstrap.js"></script>
</head>
<body>
<div id="app01">
<!--    <input type="text" v-model="name">{{handleToUpper()}}-->
    <input type="text" v-model="name">{{newName}}
    <br>
    <input type="text" v-model="name1">{{name1}}
</div>

</body>
<script>
    var vm = new Vue({
        el: "#app01",
        data: {
            name: '',
            name1: '',
        },
        methods: {
            handleToUpper() {
                return this.name.substring(0, 1).toUpperCase() + this.name.substring(1)
            }
        },
        computed: {
            newName() {
                return this.name.substring(0, 1).toUpperCase() + this.name.substring(1)
            }
        }
    })
</script>
</html>

(19)监听属性watch

  • 监听一个属性,只要这个属性发生变化,就执行函数
  • 在Vue.js中,watch选项用于监听data对象中定义的数据属性。当watch对象中列出的任何属性发生变化时,将执行相应的处理程序函数。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <link rel="stylesheet" href="../css/Bootstrap.css">
    <script src="../js/Bootstrap.js"></script>
</head>
<body>
<div id="app">
    <span @click="content_type='java'">java</span>
    <span @click="content_type='go'">go</span>
    <span @click="content_type='python'">python</span>
    <div>
    {{content}}
    </div>
</div>


</body>
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            content_type: '',
            content: ''
        },
        watch: {
            content_type() {
                this.content = this.content_type
            }
        }
    })

</script>

</html>

监听函数

export default {
  data() {
    return {
      count: 0,
    };
  },
  methods: {
    // 定义一个函数
    increment() {
      this.count++;
    }
  },
  created() {
    // 监听函数的变化
    this.$watch('increment', (newValue, oldValue) => {
      console.log('increment 函数被调用了');
    });
  }
};

(20)组件使用component

  • 组件就是:扩展HTML元素,封装可重用的代码,目的是复用
  • 例如:有一个轮播图,可以在很多页面中使用,一个轮播有js,css,html
  • 组件把js,css,html放到一起,有逻辑,有样式,有html
  • 局部组件和全局组件
    • 局部组件:只能在当前页面中使用 components
    • 全局组件:全局都可以用 Vue.component

(1)全局组件

<组件名></组件名>

Vue.component('组件名',{
	template:``,
	data(){},
	methods:{}
})
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <link rel="stylesheet" href="../css/Bootstrap.css">
    <script src="../js/Bootstrap.js"></script>
</head>
<body>
<div id="app">
    <h1>组件使用</h1>
    <hr>
    <Child></Child>

    <hr>

</div>

</body>
<script>
    // 定义全局组件
    Vue.component('Child',{
        // 放html的内容 必须使用反引号
        template:`
          <div>
            <button @click="handleClick">{{ title }}</button>
          </div>
          `,

        // 必须要写成函数的样子,必须return
        data(){
            return {
                title:'首页'
            }
        },
        methods:{
            handleClick(){
                alert('点我了')
            }
        }
    })
    // 根组件
    var vm = new Vue({
        el: '#app',
        data: {
            content_type: '',
            content: ''
        },
    })
</script>
</html>

(2)局部组件

<body>
<div id="app">
    <mycom></mycom>
    <!--    <mycom/> 还可以这样写 -->

</div>
</body>
<script>
    // 也可以这样写
	// let myDiv=...
    var vm = new Vue({
        el: '#app',
        data: {},
        // components可以有多个组件,在一个根组件中可以有多个局部组件,只能在被el定义的那个里面使用。
        components: {
            mycom: {
                template: `
                  <div>
                    <input type="text" v-model="mytext">
                  </div>`,
                data() {
                    return {
                        mytext: 'heart'
                    }
                }
            }
        }
    })

</script>

(21)生命周期钩子

  • Vue.js 组件的生命周期钩子是一组在组件创建、更新和销毁阶段调用的钩子函数,它们允许你在特定阶段执行代码。这些钩子函数可以用来执行一些任务,例如初始化数据、侦听事件、发送网络请求等。

image

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

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

setTimeout()
setInterval()

setTimeout:

  • setTimeout 用于在指定的时间后执行一次函数或一段代码。
  • 语法:setTimeout(callback, delay)
    • callback: 要执行的函数或代码块。
    • delay: 延迟的时间,以毫秒为单位。
  • 示例:
    setTimeout(() => {
      console.log('This will be executed after 1000 milliseconds.');
    }, 1000);
    
  • setTimeout 只执行一次指定的函数,即使指定的延迟时间过去后页面在这段时间内处于不活动状态。

setInterval:

  • setInterval 用于在指定的时间间隔内重复执行函数或一段代码。
  • 语法:setInterval(callback, delay)
    • callback: 要执行的函数或代码块。
    • delay: 重复执行的时间间隔,以毫秒为单位。
  • 示例:
    setInterval(() => {
      console.log('This will be executed every 2000 milliseconds.');
    }, 2000);
    
  • setInterval 会根据指定的时间间隔重复执行指定的函数,直到调用 clearInterval 来清除定时器或者页面被关闭。

setTimeout 只执行一次指定的函数,而 setInterval 会重复执行。

setTimeout 在指定的时间后执行,而 setInterval 在每个指定的时间间隔后重复执行。

对于需要重复执行的任务,应该使用 setInterval;对于只需要执行一次的任务,应该使用 setTimeout

测试代码

<!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: `
            <div>
                {{name}}
                <button @click="name='Darker1'">更新数据1</button>
                <button @click="name='Darker2'">更新数据2</button>
            </div>`,
        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)
        },
        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)
        },


    })
    let vm = new Vue({
        el: '#box',
        data: {
            isShow: true
        },
        methods: {
            terminate() {
                this.isShow = false
            },
            reborn() {
                this.isShow = true
            }
        }
    })
</script>
</html>

(1)vue2和vue3的生命周期钩子

Vue 2.x 的生命周期钩子:

  1. beforeCreate: 在实例初始化之后,数据观测 (data observer) 和事件配置 (event/watcher setup) 之前被调用。
  2. created: 实例已经创建完成之后被调用,此时实例已完成数据观测 (data observer),属性和方法的运算,watch/event 事件回调已经准备好,但是挂载阶段还未开始。
  3. beforeMount: 在挂载开始之前被调用:相关的 render 函数首次被调用。
  4. mounted: el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。
  5. beforeUpdate: 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。
  6. updated: 由于数据更改导致的虚拟 DOM 重新渲染和打补丁后调用。
  7. beforeDestroy: 实例销毁之前调用。在这一步,实例仍然完全可用。
  8. destroyed: 实例销毁后调用。此时,所有的事件监听器和子实例都已被移除。

Vue 3.x 的生命周期钩子:

在 Vue 3.x 中,生命周期钩子的名称与 Vue 2.x 中基本相同,但是有两个重大的更改:

  1. beforeCreate 和 created 钩子保持不变。
  2. beforeMount 和 mounted 钩子保持不变。
  3. beforeUpdate 和 updated 钩子保持不变。
  4. beforeDestroy 钩子变为 beforeUnmount。 在组件实例从 DOM 中卸载之前调用。
  5. destroyed 钩子变为 unmounted。 在组件实例从 DOM 中卸载后调用。

(22)父子间通信

(1)父传子(自定义属性名)props

在组件中自定义属性名,然后通过在组件中的 props 关键字传数据

<Child :myurl="url"></Child>
props: ['myurl']
<body>
<div id="app">
    <Child :myurl="url"></Child>
</div>

</body>

<script>
    Vue.component('Child', {
        template: `
          <div>
            <img :src="url" alt="" style="height: 300px;width: 300px;">
            <button @click="handleCheck">点我切换图片</button>
          </div>`,
        data() {
            return {
                url: '../img/1.jpg',
            }
        },
        props: ['myurl'],
        methods: {
            handleCheck() {
                this.url = this.myurl
            }
        }

    })

    var vm = new Vue({
        el: '#app',
        data: {
            url: '../img/godfather.jpg'
        },
    })

</script>

(2)子传父(自定义事件)emit

固定用法,使用this.$emit(自定义事件名, 参数),然后要在父中接收到这个参数,赋值即可

<body>
<div id="app">
    <Child @myevent="handleEvent"></Child>
    {{text}}
</div>
</body>
<script>
    Vue.component('Child', {
        template: `
          <div>
            <input type="text" v-model="Mytext">
            <button @click="handleCheck">点我传数据</button>
          </div>`,
        data() {
            return {
                Mytext: ''
            }
        },
        methods: {
            handleCheck() {
                this.$emit('myevent', this.Mytext)
            }
        }

    })

    var vm = new Vue({
        el: '#app',
        data: {
            text: ''
        },
        methods: {
            handleEvent(ChildText) {
                this.text = ChildText
            }
        }
    })
</script>

(3)ref属性(this.$refs)

ref是个属性,可以放在普通标签上,也可以放在组件上,在方法中console.log(this.$refs) 打印出来的是一个dom对象,可以通过点修改值...

普通标签

<body>
<div id="app">
    <input type="text" ref="text1">
    <button @click="handleClick">点我看控制台</button>
</div>
    
</body>

<script>
    var vm = new Vue({
        el: '#app',
        data: {
            text1:''
        },
        methods: {
            handleClick(){
                console.log(this.$refs) //{text1: input}
                
                this.$refs.text1.value='heart'
            }
        }
    })
</script>
</html>

组件 会是一个 VueComponent 对象,可以进行.操作进行修改值等操作

<body>
<div id="app">
    <Child @myevent="handleEvent" ref="mycomref"></Child>
    <button @click="handleClick">点我看控制台</button>
</div>

</body>

<script>
    Vue.component('Child', {
        template: `
          <div>
            <input type="text" v-model="Mytext">
          </div>`,
        data() {
            return {
                Mytext: ''
            }
        }
    })

    var vm = new Vue({
        el: '#app',
        data: {
            text: '',
        },
        methods: {
            handleClick() {
                console.log(this.$refs) // 是一个vue的dom对象 {mycomref: VueComponent}
                //可以在父中对子的数据修改
                this.$refs.mycomref.Mytext = 'god'
            }
        }
    })

</script>

</html>

补充:

this.$parent可以在子组件中拿到父组件对象

​ 但是如果一个组件会被很多次引用,根本找不到父亲是谁,所以不建议使用

(23)动态组件&keep-alive

<component :is="属性值"></component>
<body>
<div id="app">
    <div>
        <div>
            <span @click="current='goods'">商品</span>
        </div>
        <div>
            <span @click="current='order'">订单</span>
        </div>
        <div>
            <span @click="current='user'">用户</span>
        </div>
    </div>
<!--    没使用动态组件-->
<!--    <goods v-if="current=='goods'"></goods>-->
<!--    <order v-else-if="current=='order'"></order>-->
<!--    <user v-else></user>-->

<!--    使用动态组件-->
    <keep-alive>
        <component :is="current"></component>
    </keep-alive>


</div>


</body>
<script>
    Vue.component('goods', {
        template: `<div>
                <h3>商品</h3>
                </div>`
    })

    Vue.component('order', {
        template: `<div>
                <h3>订单</h3>
                </div>`
    })

    Vue.component('user', {
        template: `<div>
                <h3>用户</h3>
                <input type="text">
                </div>`
    })

    var vm = new Vue({
        el: '#app',
        data: {
            current: 'goods'
        },

    })
</script>


</html>

keep-alive 用来做缓存,避免切换的时候数据丢失

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

(24)插槽slot(相似于block)

其实就是block

一般情况下,编写完一个组件之后,组件的内容都是写死的,需要加数据,只能去组件中修改,扩展性很差

然后就出现了插槽这个概念,只需要在组件中添加,就可以在body的组件标签中添加内容了

使用插槽

<body>
<div id="app">
    <goods>
        <input type="text">
        <button>点我</button>
    </goods>
</div>

</body>
<script>
    Vue.component('goods', {
        template: `<div>
                <h3>商品</h3>
                <slot></slot>
                </div>`
    })
</script>
</html>

命名插槽

<body>
<div id="app">
    <goods>
        <div slot="a">
            <input type="text">
            <button>点我</button>
        </div>
        <div slot="b">
            <button>别点我</button>
        </div>
    </goods>
</div>

</body>
<script>
    Vue.component('goods', {
        template: `<div>
                <slot name="a"></slot>
                <h3>商品</h3>
                <slot name="b"></slot>
                </div>`
    })
</script>

组件中使用插槽

testslot.vue 组件

<template>
  <div class="helloworld">
      <h1>hello world</h1>
      <slot></slot>
      <h1>heart</h1>
  </div>
</template>

AboutView.vue 页面组件

<template>
    <div class="about">
        <h1>about</h1>
        <testslot>
            <h3>你好</h3>
        </testslot>
    </div>
</template>

<script>
import testslot from "@/components/testslot.vue";

export default {
    name: 'about',
    data() {
        return {}
    },
    methods: {},
    components: {
        testslot
    }
}

</script>

组件中使用命名插槽

testslot.vue

<template>
  <div class="helloworld">
      <h1>hello world</h1>
      <slot name="a"></slot>
      <h1>heart</h1>
  </div>
</template>
<template>
    <div class="about">
        <h1>about</h1>
        <testslot>
            <template v-slot:a>
                <h3>我是slota</h3>
            </template>
        </testslot>
    </div>
</template>


<script>
import testslot from "@/components/testslot.vue";
export default {
    name: 'about',
    data() {
        return {}
    },
    methods: {},
    components: {
        testslot
    }
}

</script>

(25)vue项目创建&目录结构

创建项目

vue create 项目名

运行项目

npm run serve

目录结构

myfirstvue        # 项目名
	-node_modules # 等同于python的venv--》虚拟环境-->里面有很多js,项目的依赖-》可以删除---》项目就不能运行了--》在你本地--》cnpm install--》根据package.json项目的依赖,再重新安装--》又可以运行了
    -public       # 文件夹,一般不动
        -favicon.ico # 小图标
        -index.html  # spa--》单页面应用--》整个vue项目,就只有这一个html-如果禁用了js--》整个vue都用不了
        
     -src        # 文件夹---》核心代码
        -assets  #文件夹,都放静态文件--》图片,css,js。。。
        	-logo.png # 静态图片
        -components  # 小组件,给页面组件使用
            HelloWorld.vue # HelloWorld 组件
        -views       # 页面组件,页面跳转,实现像 html跳转一样的效果
            AboutView.vue # 关于页面
            HomeView.vue  # 首页
        -store            # vuex--》状态管理器
            index.js
        -router            # vue-router---》路由配置文件
            index.js
        -App.vue           # 根组件
		-main.js           # 整个项目入口
        
   -.gitignore    # git忽略文件,学了git就会了
   -babel.config.js # 装了bable配置文件--》把高版本es语法转成es5
   -jsconfig.json # 不管
   -package.json  # 项目依赖文件--》项目依赖--》npm install--》根据他装
   -package-lock.json # 锁定文件,之前项目中使用模块版本
   -README.md     # 项目介绍
   -vue.config.js # vue整体配置文件   

vue项目运行机制

# 1 main.js--->指定了index.html--->id为app的div---》根App.vue 这个组件做了关联
# App是 个组件
new Vue({
  render: h => h(App)  # 代指 el
}).$mount('#app')

new Vue({
    el:'#app'
})

组件写法

<!--template 写之前我们放在template标签的模版字符串-->
<template>
  <div id="app">
    <h1>我是根组件</h1>
    <button @click="haneldShow">点我弹alert</button>
  </div>
</template>

<!--script标签--》原来js代码都写在这里-->
<script>
export default {
  name: 'HelloWorld', // 组件名字
  data() {
    return {}
  },
  methods: {
    haneldShow() {
      alert('111')
    }
  }
}
</script>


#style
<style>

button{
  background-color: aqua;
}
</style>

(26)ES6

(1)let 和 const

  • letconst 关键字用于声明变量和常量,取代了 var
  • let 声明的变量具有块级作用域,而 var 声明的变量具有函数级作用域。
  • const 声明的常量在声明后不能再被重新赋值
# 在ES6之前,我们都是用var来声明变量,而且JS只有函数作用域和全局作用域,没有块级作用域,所以{}限定不了var声明变量的访问范围。

# ES6 新增了let命令,用来声明局部变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效,而且有暂时性死区的约束

# "暂时性死区"(Temporal Dead Zone,简称 TDZ)是指在 ES6 中使用 let 或 const 声明变量时,变量存在但无法访问的区域。这种行为是为了在 JavaScript 中引入块级作用域而设计的。

# 在 JavaScript 中,使用 var 声明的变量在其声明语句之前就可以被访问,这种行为称为"变量提升"。而在使用 let 或 const 声明变量时,变量虽然存在于作用域中,但是在声明语句之前访问这些变量会导致引发 ReferenceError 异常。

# 暂时性死区的产生原因是,let 和 const 声明的变量在进入作用域时就已经被创建,并且被绑定到了该作用域中,但是在变量的声明语句之前,访问这些变量会进入暂时性死区,因为此时变量尚未初始化

(2)let与var的区别

(1)全局作用域

# 1 var 和 let 声明的变量在全局作用域中被定义时,两者非常相似

# 2 被let声明的变量不会作为全局对象window的属性,而被var声明的变量却可以

let a = 'let的a';
var b = 'var的b'; 
console.log(window.a);  //undefined
console.log(window.b);  // 'var的b'

(2)函数作用域

# 1 var 和 let 在函数作用域中声明一个变量,两个变量的意义是相同的
# 2 var 声明的变量,在整个函数都有效,即便输出语句在定义之前(变量提升)
function  demo01(){
    let a = 'let的a'; // 函数作用域中的变量
    console.log(b)    // 不会报错
    var b = 'var的b'; // 函数作用域中的变量
}

(3)块作用域

# 1 let只在for()循环中可用,而 var是对于包围for循环的整个函数可用
function  demo02(){
    # i 对于for循环外的范围是不可见的(i is not defined)
    for(let i = 1; i<5; i++){
        #  i只有在这里是可见的
    }
    # i 对于for循环外的范围是不可见的(i is not defined)
}
function demo03(){
    # i 对于for循环外的范围是可见的
    for(var i = 1;i<5; i++){
        # i 在for 在整个函数体内都是可见的
    }
    # i 对于for循环外的范围是可见的
}

(4)重新声明

# var允许在同一作用域中声明同名的变量,而let不可以
let a  = 'foo';
let a  = 'bar'; # 报错


var a = 'foo';
var a = 'bar'; # 可以

(3)const

#1 const和let都是在声明的块作用域中有效,但是let声明的变量可变,值和类型都可以改变,没有限制。
#2  const声明额变量不能改变,所以,const一旦声明一个变量,就必须马上初始化,不能留到以后赋值

(4)箭头函数

# 箭头函数是一种更简洁的函数声明方式,可以减少函数声明的冗余代码。
# 使用箭头函数可以避免 this 绑定的问题,箭头函数的 this 继承自外层作用域
let f=()=>{}

(1)this指向问题

# 1 在全局上下文中,this 指向全局对象,在浏览器环境中通常是 window 对象,在 Node.js 中是 global 对象
    console.log(this) # window 对象
    
# 2 函数调用:
    # 2.1 如果函数作为普通函数调用,this 指向全局对象(在严格模式下为 undefined)
    # 2.2 如果函数作为对象的方法调用,this 指向调用该方法的对象。

# 3 构造函数:
	在构造函数中,this 指向新创建的实例对象
    
# 4 箭头函数:
箭头函数的 this 指向定义时所在的作用域的 this 值,而不是调用时的 this 值。换句话说,箭头函数的 this 是词法作用域,而不是动态作用域

# 5 DOM 事件处理函数:
在 DOM 事件处理函数中,this 指向触发事件的 DOM 元素

# ES6 类方法:
在 ES6 类方法中,this 指向调用该方法的对象实例

# 案例1 
function demo01(){
    console.log(this) # window对象
}
demo01()
# 案例2
let user={
    name:'heart',
    showName:function (){
        console.log(this.name) // user对象
    }
}
user.showName()
# 案例3
let user={
    name:'heart',
    showName:function (){
        console.log(this.name) // user对象
        function inner(){
            console.log("函数内this:",this) // 普通函数,window对象
        }
        inner()
    }
}
user.showName()

(5)模版字符串

# 1 模板字符串允许在字符串中插入变量和表达式,使用 ${} 语法。
# 2 模板字符串支持多行字符串,可以直接换行而不需要使用 \n

# 案例
let name='heart'
let age =18
let s=`我的名字是:${name},我的年龄是:${age}`
console.log(s)

(6)解构赋值

#1  解构赋值允许从数组或对象中提取数据,并将其赋值给变量。
#2  解构赋值可以方便地交换变量的值,同时还支持默认值

# 案例1 
let user={name:'heart',age:19,hobby:['抽烟','喝酒']}
let {name,hobby}=user
console.log(name,hobby)

# 案例2 
function getuserInfo() {
    return {name: 'heart', age: 19, hobby: ['抽烟', '喝酒']}
}

let {name, hobby} = getuserInfo()
console.log(name, hobby)

# 案例3
function getuserInfo() {
    return {name: 'heart', age: 19, hobby: ['抽烟', '喝酒']}
}

let {name1='1', hobby} = getuserInfo()
console.log(name1, hobby)

(7)默认参数

# ES6 允许在函数参数中设置默认值,当调用函数时未提供参数时,将使用默认值

# 案例
function demo01(name,age=19) {
    console.log(name,age)
}
demo01('heart')

(8)展开运算

#1 展开运算符 ... 可以将可迭代对象(如数组、字符串、对象)展开为多个参数或元素。
#2 也可以用于函数参数

# 案例1 
let a={age:18,hobby:'喝酒'}
let user={name:'heart',age:20,...a}
console.log(user)

# 案例2
let l=[1,2,3]
let l1=[44,55,66,...l]
console.log(l1)

# 案例3
function demo01(a,...b){
    console.log(a)
    console.log(b)
}
demo01(1,2,34,4)
let l=[44,5,66,7]
demo01(...l)

(27)导入导出语法

(1)默认导出和导入

导出 export default

const name='heart'
function demo01(){
    console.log('demo01')
}
export default {
    name,
    demo01
}

导入 import utils from "./utils.js"

// 导入
<script type="module">
    import utils from "./utils.js"
    console.log(utils.name)
    utils.demo01()
</script>

(2)命名导出和导入

命名导出

export let name='heart'
export function add(a,b){
    return a+b
}
export const age=100

命名导入

// 2.1 命名导出的导入
import {add,age} from './heart/utils.js'
console.log(add(8,9))
console.log(age)

// 2.2 命名导出的导入
<script type="module">
    import * as xx from './heart/utils.js'
    console.log(xx.add(8,9))
    console.log(xx.age)
</script>

// 2.3 命名导出的导入
<script type="module">
    import {add as myadd}  from './heart/utils.js'
    console.log(myadd(8,9))
</script>

如果在文件夹下有个index.js,只要导到文件夹一层即可

## 1 导出
export default {
    name:'heart',
    showAge:function (){
        console.log('age',this.name)
    },
    showName:()=>{
        console.log(this.name) # 箭头函数this 有问题
    },
    showHobby(){
        console.log('hobby',this.name)
    }
}

## 2 导入
<script type="module">
    import heart from './heart'
    console.log('----',heart.name)
    heart.showAge()
    heart.showHobby()
</script>

(3)组件的使用

vue项目中,组件的使用

App.vue的script中先导入组件,再在components里面注册该组件

<template>
  <div id="app">
    <Test></Test> # 引用
  </div>
</template>

<script>
    # 导入组件
import Test from "@/components/test.vue";

export default {
  name: 'app',
  data() {
    return {}
  },
  components: {
    Test # 注册组件
  }
}
</script>

(28)vue-router

单页面应用,就无法实现页面的跳转

借助于vue-router实现组件切换,效果就是页面跳转

使用的话,App.vue为固定写法

cnpm install -S vue-router

(1)router-view

App.vue

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

src/router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
import AboutView from '../views/AboutView.vue'

Vue.use(VueRouter)

# 只需要修改这个配置路由即可
const routes = [
    {
        path: '/',
        name: 'home',
        component: HomeView
    },
    {
        path: '/heart',
        name: 'heart',
        component: AboutView
    },
]

登录验证跳转案例

使用 this.$router.push('路径') 方法进行路由跳转

使用 this.$router.push(对象) 方法进行路由跳转

首页 src/views/HomeView.vue

<template>
  <div class="home">
    <h1>hello 点击按钮登录</h1>
    <button @click="handleClick">去登录</button>
  </div>
</template>

<script>
export default {
  name: 'home',
  methods: {
    handleClick() {
      // 方式一 写路径
      this.$router.push('/login')
      
      // 方式二 写对象
      this.$router.push({
          name: 'home' // 这个name要和router里的name相对应
      })
      // 方式三 写path
      this.$router.push({
          path: 'home' // 这个path要和router里的path相对应
      })
      
    }
  }
}
</script>

登录页 src/views/LoginView.vue

<template>
  <div class="login">
    <h1>登录页面</h1>
    <p>用户名: <input type="text" v-model="username"></p>
    <p>密码: <input type="password" v-model="password"></p>
    <p>
      <button @click="handleLogin">登录</button>
    </p>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  name: 'login',
  data() {
    return {
      username: '',
      password: ''
    }
  },
  methods: {
    handleLogin() {
      axios.post('http://127.0.0.1:8000/app01/login/', {
        username: this.username,
        password: this.password
      }).then(res => {
        if (res.data.code == 200) {
          alert(res.data.msg)
          this.$router.push('/films')
        } else {
          alert(res.data.msg)
        }
      })
    }
  }
}
</script>

电影页 src/views/FilmsView.vue

<template>
  <div class="login">
    <h1>电影页面</h1>
    <div v-for="item in films_list">
      <p>{{ item.id }}</p>
      <p>{{ item.name }}</p>
      <p><img :src="item.poster" alt="" width="300px" height="300px"></p>
      <hr>
    </div>
  </div>
</template>

<script>
import axios from 'axios';


export default {
  name: 'films',
  data() {
    return {
      films_list: []
    }
  },
  created() {
    axios.get('http://127.0.0.1:8000/app01/films/').then(
        res => {
          this.films_list = res.data.result.data.films
        }
    )
  }
}

</script>

App.vue

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

路由 src/router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
import LoginView from "@/views/LoginView.vue";
import FilmsView from "@/views/FilmsView.vue";

Vue.use(VueRouter)

const routes = [
    {
        path: '/',
        name: 'home',
        component: HomeView
    },
    {
        path: '/login',
        name: 'login',
        component: LoginView
    },
    {
        path: '/films',
        name: 'films',
        component: FilmsView
    },
]

const router = new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
})

export default router

image

image

image

组件跳转

使用<router-link to="">跳转 to里面填写路由地址

<router-link to="/about">
    <button>点我跳转</button>
</router-link>

(3)路由跳转携带数据

router-link

以?形式携带

方式一

<router-link to="/about?name=heart">
    <button>点我跳转到about</button>
</router-link>

方式二

用配置方式传参

<router-link :to="{path:'about',query:{name:'heart'}}">
    <button>点我跳转到about</button>
</router-link>

在另一个页面组件中取:会获取到object对象,以?带过来的数据,都会在query中

this.$route.query

export default {
    name: 'AboutView',
    created() {
        console.log(this.$route)
        // {name: 'about', meta: {…}, path: '/about', hash: '', query: {…}, …}
    }
}

js跳转

this.$router.push('/about?name=heart&age=18')
this.$router.push({name:'about',query:{name:'heart',age:18}})

取数据 : this.$route.query

以 /路径/数据/ 跳转

router-link

必须在路由中写 路径后带/数据

{
    path: '/about/:id',
    name: 'about',
    component: AboutView
}

这时候路径就会变成这个样子

image

方式一

<router-link to="/about/23">
    <button>点我跳转到about</button>
</router-link>

取值需要在params中取

this.$route.params

image

方式二

<router-link :to="{name:'about',params:{id:23}}">
    <button>点我跳转到about</button>
</router-link>

取值需要在params中取

this.$route.params

js跳转

this.$router.push('/about/23')
this.$router.push({name:"about",params:{id:23}})

this.$route.params

(29)elementui

# 1 开源的样式库,方便在vue中使用
	-elementui:饿了么团队开源的  web端
    	https://element.eleme.cn/#/zh-CN
    -vant:有赞团队,移动端
    	https://vant-ui.github.io/vant/#/zh-CN
    -ant design:阿里团队
    	https://1x.antdv.com/docs/vue/introduce-cn/
    -iView
    	https://v2.iviewui.com/components/grid
    -nutui:京东团队
    	https://nutui.jd.com/2x/#/dialog
        
# 2 项目中集成
	1 安装:cnpm i element-ui -S
    2 集成到项目:main.js 中加入
    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';
    Vue.use(ElementUI); // 使用插件
    3 去官网,找样式,复制,粘贴

(30)混入 mixin

可以把多个组件共用的配置提取成一个混入对象,不需要在每个组件中都写

(1)局部使用

定义混入

mixin/index.js

const hunru = {
    data() {
        return {
            title: '首页'
        }
    },
    methods: {
        handleClick() {
            this.title = this.title + 'heart'
        }
    }
}

export default hunru

注意,这个地方一定要在自己的里面也写入datamethods

混入的导入:mixins:[]

<template>
    <div class="about">
        <h1>{{title}}</h1>
        <button @click="handleClick">点我变标题</button>
    </div>
</template>

<script>
import hunru from '@/mixin'
export default {
    name: 'about',
    data() {
        return {
            title:'about'
        }
    },
    methods: {},
    mixins: [hunru]
}
</script>

(2)全局使用

main.js中定义,就不用在每个页面中导入了

import hunru from "@/mixin";

Vue.mixin(hunru)
// 如果要使用多个,要多次定义
// Vue.mixin(hunru1)
// Vue.mixin(hunru2)

(31)插件 install

  • 功能:用于增强Vue
  • 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据

使用步骤

一定要写install()

prototype是原型链,一般定义在原型中的变量,都用$开头,防止定义同名属性冲突

plugins/index.js

import Vue from "vue";
import axios from "axios";
import hunru from "../../src_mixin/mixin";

export default {
    install(a) {
        Vue.prototype.$axios = axios
        Vue.prototype.$name='heart'
        Vue.mixin(hunru)
    }
}

需要在main.js中注册使用

import my from '@/plugins'
Vue.use(my)

在组件中使用

还可以使用混入

<template>
    <div class="home">
        <h1>{{title}}</h1> <!--使用混入-->
        <button @click="handleShow">点我</button>
    </div>
</template>

<script>

export default {
    name: 'HomeView',
    data() {
        return {}
    },
    methods: {
        handleShow() {
            console.log(this.$axios) 
            // ƒ wrap() {
            //     return fn.apply(thisArg, arguments);
            // }
            // this.$axios 获取到axios对象
            this.$axios.get('http://127.0.0.1:8000/app01/login')
            console.log(this.$name) // heart
        }
    },
}
</script>

(32)本地存储

loaclStorage : 永久生效,除非代码删除或者清空浏览器缓存

sessionStorage : 当前浏览器生效,关闭浏览器将就没有了

cookie : 登录信息存放在这里,有过期时间,一旦过期就没了

使用cookie前提是要安装

cnpm install vue-cookies -S

然后在main.js中注册

import VueCookies from 'vue-cookies'

# Vue.prototype.$cookies = VueCookies 两种方式都可以 最终都指向this.$cookies
Vue.use(VueCookies)
<template>
    <div class="home">
        <h1>home</h1>
        <button @click="handleSetlocalStorage">设置localStorage</button>
        <button @click="handleGetlocalStorage">获取localStorage</button>
        <button @click="handleDeletelocalStorage">删除localStorage</button>
        <br>
        <hr>
        <button @click="handleSetsessionStorage">设置sessionStorage</button>
        <button @click="handleGetsessionStorage">获取sessionStorage</button>
        <button @click="handleDeletesessionStorage">删除sessionStorage</button>
        <br>
        <hr>
        <button @click="handleSetCookies">设置cookies</button>
        <button @click="handleGetCookies">获取cookies</button>
        <button @click="handleDeleteCookies">删除cookies</button>
    </div>
</template>

<script>
export default {
    name: 'HomeView',
    data() {
        return {}
    },
    methods: {
        handleSetlocalStorage(){
            localStorage.setItem('name','heart')
        },
        handleGetlocalStorage(){
            console.log(localStorage.getItem('name'))
        },
        handleDeletelocalStorage(){
            localStorage.clear()
        },
        
        
        handleSetsessionStorage(){
            sessionStorage.setItem('name','god')
        },
        handleGetsessionStorage(){
            console.log(sessionStorage.getItem('name'))
        },
        handleDeletesessionStorage(){
            sessionStorage.clear()
        },
        
        
        handleSetCookies(){
            this.$cookies.set('name','godfather','1d')
        },
        handleGetCookies(){
            console.log(this.$cookies.get('name'))
        },
        handleDeleteCookies(){
            this.$cookies.remove('name')
        },
    }
}
</script>

(33)vuex

  • 在vue2中,大量使用,到vue3中使用pinia
  • vuex作用:集中式状态管理,组件有自己的数据,放在组件中,有了状态管理器,多个组件可以共同操作这个状态管理器

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
    state: {
        count: 0
    },
    getters: {},
    mutations: {
        addOne(state,num) {
            state.count += num
        }
    },
    actions: {
        addCount(context, num) {
            // 这里context其实就是state对象
            context.commit('addOne', num) // 触发mutations中的addOne方法
        }
    },
    modules: {}
})
  • context context 是一个包含了 Vuex store 中的 state、getters、commit 和 dispatch 方法的对象。通过 context,可以在 actions 中访问 state 中的状态、调用 getters、提交 mutations 或者分发其他 actions。context 提供了一个统一的接口,使得可以在 actions 中进行状态的读取和修改,而不需要直接访问 Vuex store 对象。在以上代码中,context 参数在 addCount 方法中使用,用于提交 addOne mutation。
actions: {
    addCount(context, num) {
        context.commit('addOne', num)
    }
}
  • state state 是 Vuex store 中的状态对象,用于存储应用中的各种数据。在 Vuex store 中,state 是唯一的、可响应的数据源。可以通过 state 来访问和修改 store 中的状态。在 mutations 和 getters 中,可以直接接收 state 参数来读取状态或者修改状态。在以上代码中,state 参数在 addOne mutation 中使用,用于修改 count 状态的值。
mutations: {
    addOne(state, num) {
        console.log(num)
        state.count += num
    }
}

HomeView

<template>
    <div class="home">
        <h1>home</h1>
        <shopping></shopping>
        <goods_list></goods_list>
    </div>
</template>

<script>
import goods_list from "@/components/goods_list.vue";
import shopping from "@/components/shopping.vue";

export default {
    name: 'HomeView',
    data() {
        return {}
    },
    methods: {

    },
    components: {
        goods_list, shopping
    }

}
</script>

shooping.vue

<template>
    <h2>购物车数量:{{$store.state.count}}</h2>
</template>

<script>
export default {
    name: "shopping"
}
</script>

goods_list.vue

<template>
    <div>
        <p>商品信息:笔记本 价格:9999</p>
        <button @click="handleClick">加入购物车</button>
        <p>商品信息:电脑 价格:10000</p>
        <button @click="handleClick">加入购物车</button>
        <p>商品信息:笔 价格:2</p>
        <button @click="handleClick">加入购物车</button>
    </div>
</template>

<script>
export default {
    name: "goods_list",
    methods: {
        handleClick() {
            // 方式一 直接(不建议)
            this.$store.state.count++
            
            // 方式二 间接通过 actions
            this.$store.dispatch('addCount', 1)
            
            // 方式三 间接通过 mutations
            this.$store.commit('addOne',1)
        }
    }
}
</script>
  • state: 用于存储应用中的状态数据。
  • mutations: 包含了一些用于修改 state 的同步方法。
  • actions: 包含了一些用于提交 mutations 的异步方法,适合通过后端校验数据。

(34)相关API

  • this.$router.push(path) : 相当于点击路由链接(可以返回到当前路由界面)
  • this.$router.replace(path) : 用新路由替换当前路由(不可以返回到当前路由界面)
  • this.$router.back() : 请求(返回)上一个记录路由
  • this.$router.go(-1) : 请求(返回)上一个记录路由
  • this.$router.go(1) : 请求下一个记录路由

(35)多级路由

HomeView

<template>
    <div class="home">
        <div class="left">
            <router-link to="/home/index"><p>首页</p></router-link>
            <router-link to="/home/user"><p>用户</p></router-link>
            <router-link to="/home/goods"><p>商品</p></router-link>
        </div>
        <div class="right">
            <router-view>
            </router-view>
        </div>
    </div>
</template>

router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'
import AboutView from "@/views/AboutView.vue";
import IndexView from "@/views/IndexView.vue";
import UserView from "@/views/UserView.vue";
import GoodsView from "@/views/GoodsView.vue";

Vue.use(VueRouter)

const routes = [
    {
        path: '/home',
        name: 'home',
        component: HomeView,
        children: [
            {
                path: 'index', // 此处一定不要带 / 斜杠
                component: IndexView
            },
            {
                path: 'user',
                component: UserView
            },
            {
                path: 'goods',
                component: GoodsView
            }

        ]
    },
    {
        path: '/about/',
        name: 'about',
        component: AboutView
    }
]

const router = new VueRouter({
    mode: 'history',
    base: process.env.BASE_URL,
    routes
})

export default router

App.vue

<template>
    <div id="app">
        <router-view></router-view>
    </div>
</template>

image

(36)路由守卫

全局守卫、独享守卫、组件内守卫

全局守卫

router.beforeEach((to,from,next)=>{
	console.log('前置路由守卫',to,from)
    if(localStorage.getItem('name')==='heart'){
        next()
    }else{
        alert('名不对,无权限查看!')
    }
})

//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
	console.log('后置路由守卫',to,from)
	document.title = to.meta.title || 'heart系统'
})

路由两种工作模式

1 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
2 hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
3 hash模式:
地址中永远带着#号,不美观 。
若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
兼容性较好。
4 history模式:
地址干净,美观 。
兼容性和hash模式相比略差。
应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题

VUE3

vue2的所有操作vue3都兼容
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>

(1)vite & vue3项目创建

vue-cli创建

## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version
## 安装或者升级你的@vue/cli
npm install -g @vue/cli
## 创建
vue create vue_test
## 启动
cd vue_test
npm run serv

配置npm本地镜像站

npm config set registry https://registry.npmmirror.com
npm config get registry

vite创建

官方文档:https://v3.cn.vuejs.org/guide/installation.html#vite

vite官网:https://vitejs.cn

介绍:https://cn.vitejs.dev/guide/why.html#the-problems

  • 什么是vite?—— 新一代前端构建工具。
  • 优势如下:
    • 开发环境中,无需打包操作,可快速的冷启动。
    • 轻量快速的热重载(HMR)。
    • 真正的按需编译,不再等待整个应用编译完成。

创建

npm create vite@latest
# 指定名字创建
cnpm create vite@latest 名字

# 创建完还需要安装依赖
npm install

# 运行项目
npm run dev

(2)setup

初级写法

<template>
    <div class="home">
        <h1>home</h1>
        <p>{{ name }}</p>
        <p>{{ age }}</p>
        <button @click="handleAdd">age+1</button>
        <button @click="handleChange">点击变彭于晏</button>
    </div>
</template>

<script>
import {ref} from "vue";

export default {
    name: 'HomeView',
    setup() {
        const name = ref('heart')
        const age = ref(18)

        function handleAdd() {
            age.value += 1
        }

        function handleChange() {
            name.value = '彭于晏'
        }

        return {
            name,
            age,
            handleAdd,
            handleChange
        }
    }

}
</script>

用法

1 生命周期钩子created

直接写在script内部即可

<template>
  <h1>home</h1>
</template>

<script setup lang="js">
console.log('created')

</script>

2 计算属性

<template>
    <h1>home</h1>
  {{ newname }}
</template>

<script setup lang="js">
import {ref, reactive, computed} from "vue";

const name = ref('heart')

const newname = computed(() => {
    return name.value += 'nb'
})
</script>

3 监听属性

<template>
    <h1>home</h1>
  {{ newname }}
</template>

<script setup lang="js">
import {ref, reactive, computed, watch} from "vue";

const name = ref('heart')

const newname = computed(() => {
    return name.value += 'nb'
})

watch(name,()=>{
    console.log('变化了')
})
</script>

4 组件间通信

父传子 自定义属性

defineProps(['自定义属性名'])

父组件 HomeView.vue

<template>
    <h1>home</h1>
  <!--    等号后是需要传入的变量-->
    <Test :msg="testmsg"></Test>
</template>

<script setup lang="js">
import {ref, reactive} from "vue";
import Test from '../components/test.vue'

const testmsg = '你好啊我是heart'
</script>

子组件 test.vue

<template>
    <h1>我是test</h1>
    子:{{msg}}   <!--  子:你好啊我是heart-->
</template>

<script setup>
defineProps(['msg']) // 这个地方是 : 后面的名字
</script>

子传父 自定义事件

defineEmits(['自定义事件名'])

父组件 HomeView.Vue

<template>
    <h1>home</h1>
    <Test @myevent="handletest"></Test>
    {{child_input}}

</template>

<script setup lang="js">
import {ref, reactive} from "vue";
import Test from '../components/test.vue'

const child_input = ref('')

const handletest = (text) => {
    child_input.value = text
}

</script>

子组件 test.vue

<template>
    <h1>我是test</h1>
    <input type="text" v-model="inputtext">{{ inputtext }}
    <br>
    <button @click="handleSend">点我子传父</button>
</template>

<script setup>
import {ref} from "vue";

const inputtext = ref('')
let emit = defineEmits(['myevent'])
const handleSend = () => {
    emit('myevent', inputtext.value)
}
</script>

5 slot插槽

插槽就是在父里面的子组件中加入内容

HomeView.vue

<template>
    <h1>home</h1>
    <Test>
        <template v-slot:a>
            <div>你好我是a</div>
        </template>
        <template v-slot:b>
            <div>你好我是bb</div>
        </template>
    </Test>
</template>

<script setup lang="js">
import {ref, reactive} from "vue";
import Test from '../components/test.vue'

</script>

test.vue

<template>
    <h1>我是test</h1>
    <slot name="a"></slot>
    123
    <slot name="b"></slot>
</template>

<script setup>
import {ref} from "vue";

</script>

6 混入minxin

直接导入导出用 只有局部的了

7 插件一样使用

8 ref属性

拿到组件对象通过.操作

父组件 HomeView.vue

注意:这个地方必须要放在函数内,不然还没挂载是拿不到参数的

ref后面的名字必须要和在script内定义的名字一样

<template>
    <h1>home</h1>
    <Test ref="test3"></Test>
    <button @click="handleClick">点我</button>
</template>

<script setup lang="js">
import {ref, reactive, toRef, handleError} from "vue";
import Test from '../components/test.vue'

let test3 = ref()

const handleClick = () => {
    console.log(test3.value.name)
}

</script>

子组件 test.vue

<template>
    <h1>我是test</h1>
</template>

<script setup>
import {ref} from "vue";

const name = 'heart'
const age = 18

defineExpose({name, age})

</script>

(3)ref和reactive

  • ref : 包裹值类型[数字,字符串,布尔],做成响应式
  • reactive包裹引用类型[对象,数组]
<template>
    <div class="home">
        <h1>home</h1>
        <p>{{ name }}</p>
        <p>{{ age }}</p>
        <button @click="handleAdd">age+1</button>
        <button @click="handleChange">点击变彭于晏</button>

        <hr>
        <p>名字:{{ boy.name }}</p>
        <p>年龄:{{ boy.age }}</p>
        <button @click="handleAddAge">点击年龄加一</button>

    </div>
</template>

<script>
import {ref, reactive} from "vue";

export default {
    name: 'HomeView',
    setup() {
        const name = ref('heart')
        const age = ref(18)
        const boy = reactive({name: 'Y.O.U.N.G', age: 20})


        function handleAdd() {
            age.value += 1
        }

        function handleChange() {
            name.value = '彭于晏'
        }

        const handleAddAge = () => {
            boy.age += 1
        }

        return {
            name,
            age,
            boy,
            handleAdd,
            handleChange,
            handleAddAge
        }
    }

}
</script>

(4)计算属性

<template>
  <p>姓:<input type="text" v-model="person.firstName"></p>
  <p>名:<input type="text" v-model="person.lastName"></p>
  <p>全名:{{ person.fullName }}</p>
  <p>全名修改:<input type="text" v-model="person.fullName"></p>

</template>

<script>

import {ref, reactive} from 'vue'
import {computed} from 'vue'

export default {
  name: 'App',
  setup() {
    const person = reactive({
      firstName: 'god',
      lastName: 'father'
    })

    // let fullName = computed(() => {
    //   return person.firstName + '-' + person.lastName
    // })
    // 或者,传入箭头函数
    // person.fullName=computed(() => {
    //   return person.firstName + '-' + person.lastName
    // })
    // 修改,传入配置项目
    person.fullName = computed({
      get() {
        return person.firstName + '-' + person.lastName
      },
      set(value) {
        const nameArr = value.split('-')
        person.firstName = nameArr[0]
        person.lastName = nameArr[1]
      }
    })
    return {person}
  },
}
</script>
import { defineStore } from 'pinia';
import { computed, reactive, ref } from 'vue';

export const TestStore = defineStore('counter', () => {
    const name = ref('');
    const book_list = reactive({ result: [] });

    const filteredBooks = computed(() => {
        return book_list.result.filter(book => book.price > 23);
    });

    function increment(item) {
        book_list.result = item;
    }

    return { name, increment, filteredBooks, book_list };
});

(5)监听属性

  • 在 Vue 3 中,watch 函数是一个基于函数的 API,用于监视响应式数据的变化,并在数据变化时执行一些逻辑。与 Vue 2 中的 watch 选项相比,Vue 3 中的 watch 函数更加灵活和直观。

监听基础属性

<template>
    <div class="home">
        <h1>home</h1>
        <p>{{ age }}</p>
        <button @click="handleAdd">点我年龄+1</button>
    </div>
</template>

<script>
import {ref, watch, reactive} from "vue";

export default {
    name: 'HomeView',
    setup() {
        let age = ref(18)
        let handleAdd = () => {
            age.value += 1
        }

        watch(age, (newValue, oldValue) => {
            console.log('变化了')
            console.log(newValue, oldValue)
        })

        return {
            age, handleAdd
        }
    }

}
</script>

监听函数属性

<template>
    <div class="home">
        <h1>home</h1>
        <p>{{ user_dict.age }}</p>
        <button @click="handleAdd">点我年龄+1</button>
    </div>
</template>

<script>
import {ref, watch, reactive} from "vue";

export default {
    name: 'HomeView',

    setup() {
        let user_dict = reactive({name: 'heart', age: 18})
        let handleAdd = () => {
            user_dict.age += 1
        }

        watch(() => user_dict.age, (newValue, oldValue) => {
            console.log('变化了')
            console.log(newValue, oldValue)
        })

        return {
            user_dict, handleAdd
        }
    }
}
</script>

(1)watchEffect函数

不用指定监听谁,只要watchEffect内部用了某个变量,某个变量发生变化,就会触发

watchEffect(() => {
    const x1 = sum.value
    const x2 = person.name
    console.log('watchEffect配置的回调执行了')
})

(6)生命周期钩子

配置项API生命周期

beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
beforeUnmount
unmounted

组合式API生命周期

  • Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:
    • beforeCreate===>setup()
    • created=======>setup()
    • beforeMount ===>onBeforeMount
    • mounted=======>onMounted
    • beforeUpdate===>onBeforeUpdate
    • updated =======>onUpdated
    • beforeUnmount ==>onBeforeUnmount
    • unmounted =====>onUnmounted

image

(7)toRefs & toref

  • toRefs简单来说就是全部做成响应式
<template>
    <div class="home">
        <h1>home</h1>
        {{ name }}
        {{ age }}
        {{ height }}
        {{ count }}
    </div>
</template>

<script>
import {ref, reactive, toRefs} from "vue";

export default {
    name: 'HomeView',
    setup() {
        let count = ref(0)
        let user = reactive({name: 'heart', age: 18, height: 180})
        // 其实...toRefs就是把字典解压了
        // 变成{name:'heart',age:18,height:180},直接调用就可以了,前面就不用加前缀(user)了

        return {
            ...toRefs(user), count
        }
    }
}
</script>

如果用setup写法的话

<template>
    <h1>home</h1>
  {{ name }}
  {{ age }}
</template>

<script setup lang="js">
import {ref, reactive, toRefs} from "vue";

const person = reactive({name: 'heart', age: 18})
let {name, age} = toRefs(person)

</script>

toref

指定某一个key值做成响应式

<template>
    <h1>home</h1>
  {{ name }}
  {{ person.age }}
</template>

<script setup lang="js">
import {ref, reactive, toRef} from "vue";

const person = reactive({name: 'heart', age: 18})
const name = toRef(person, 'name')

</script>

(8)axios

基本使用

<template>
    <h1>home</h1>
    <div v-for="item in films_list.result">
        <p>{{ item.name }}</p>
        <p><img :src="item.poster" alt="" style="height: 300px;width: 300px"></p>
    </div>
</template>

<script setup lang="js">
import {ref, reactive, toRef, handleError} from "vue";
import axios from "axios";

const films_list = reactive({result: []})

axios.get('http://127.0.0.1:8000/app01/films/').then(
    res => {
        films_list.result = res.data.data.data.films
    }
).catch(err => {
    console.log(err)
})
</script>

async await

<template>
    <h1>home</h1>
    <div v-for="item in films_list.result">
        <p>{{ item.name }}</p>
        <p><img :src="item.poster" alt="" style="height: 300px;width: 300px"></p>
    </div>
</template>

<script setup lang="js">
import {ref, reactive, toRef, handleError} from "vue";
import axios from "axios";

const films_list = reactive({result: []})

async function load() {
    try {
        let res = await axios.get('http://127.0.0.1:8000/app01/films/');
        console.log(res); // 打印响应对象
        films_list.result = res.data.data.data.films; // 可能会抛出异常的代码
    } catch (error) {
        // 处理异常的代码块
        console.error("异常:", error);
    }
}
    
load()
    
</script>

(9)pinia

1 安装

npm install pinia

2 use

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia()
const app = createApp(App)

app.use(pinia)
app.mount('#app')

3 定义

import { defineStore } from 'pinia'

export const Test = defineStore('test', () => {
  const count = ref(0)
  const name = ref('Eduardo')
  const doubleCount = computed(() => count.value * 2) // 计算属性
  function increment() {
    count.value++
  }

  return { count, name, doubleCount, increment }
})

Setup Stores 中:

  • ref() 成为 state 的属性
  • computed() 变成 getters
  • function() 变成 actions

使用pinia进行存储数据

HomeView.vue

<template>
    <h1>home</h1>
    <router-link to="/about">
        <button @click="handleClick('heart')">点我跳转</button>
    </router-link>
</template>

<script setup lang="js">
import {ref, reactive} from "vue";
import {TestStore} from '../store/index.js'


const store = TestStore()
const handleClick = (item) => {
    // store.name = item  //也可以直接操作数据
    store.increment(item)
}
</script>

AboutView.vue

<template>
    <h1>about</h1>
    <router-link to="/">
        <button>点我跳转</button>
    </router-link>
  {{ store.name }}
</template>

<script setup lang="js">
import {TestStore} from "../store/index.js";

const store = TestStore()
</script>

src/store/index.js

// stores/counter.js
import {defineStore} from 'pinia'
import {ref} from "vue";

// 这个地方 TestStore 和 counter 是唯一的
export const TestStore = defineStore('counter', () => {
    const name = ref('')// 定义变量

    function increment(item) {
        name.value = item
    }

    return {name, increment}
})

(10)vue-router

携带数据跳转 query

放数据 通过在地址栏方式

放数据用router,取数据用route

import {useRouter} from 'vue-router'
let router = useRouter()
<template>
    <h1>home</h1>
    <button @click="handleClick">点我跳转</button>
</template>

<script setup lang="js">
import {useRouter} from 'vue-router'

let router = useRouter()
const handleClick = () => {
    router.push({name: 'about', query: {name: 'heart', age: 18}})
}
</script>

取数据 通过 route.query取

import {useRoute} from 'vue-router'
let route = useRoute()
<template>
    <h1>about</h1>
</template>

<script setup lang="js">
import {useRoute} from 'vue-router'

let route = useRoute()

console.log(route.query) // {"name": "heart", "age": "18" }
</script>

携带数据跳转 params

放数据 通过在路径/后面带值

<template>
    <h1>home</h1>
    <button @click="handleClick">点我跳转</button>
</template>

<script setup lang="js">
import {useRouter} from 'vue-router'

let router = useRouter()
const handleClick = () => {
    router.push({name: 'about', params: {id: 18}})
}
</script>

取数据 通过route.params取

<template>
    <h1>about</h1>
    <button @click="handleClick">点我跳转</button>
</template>

<script setup lang="js">
import {useRoute} from 'vue-router'

let route = useRoute()

console.log(route.params.id) // 18
</script>

补充

es6的对象写法

<script>
    var hobby=['抽烟','烫头']
    var obj={
        name:'heart',
        age:19,
        hobby,
        showName(){
            console.log(this.name)
        }
    }
    console.log(obj)
    obj.showName()
</script>

如果修改属性不成功,用Vue.set(变量,位置,属性)

Vue.set(this.style_list,3,{'margin':'auto'})

js的循环方式

  • let 和 const

    • let定义局部变量

    • const定义常量,不能修改

1 普通索引循环

<script>
    for (let i = 0; i < 10; i++) {
        console.log(i)
    }
</script>

2 基于迭代的循环

of循环 循环出一个值

in循环 循环出索引

<script>
    l = [3, 4, 5, 6]

    for (let item of l) {
        console.log(item)
    }

    for (let index in l) {
        console.log(l[index])
    }
</script>

3 数组的方法实现循环

<script>
    l = [3, 4, 5, 6]

    l.forEach((item,index)=>{
        console.log(item,index)
    })
</script>

nodejs npm安装问题

- 方案一
# 1 清空缓存
npm cache clean --force
# 2 关闭ssl验证
npm config set strict-ssl false
# 3 安装
cnpm ...

- 方案二
# 1 清空缓存
npm cache clean --force
# 2 切换新源
npm config set registry https://registry.npmmirror.com
# 3 查看源是否设置成功
npm config get registry
# 4 安装
cnpm ...

scoped

加在style上,表示样式只在当前vue中生效

Object.assign

object.assign()主要用于对象合并,将源对象中的属性复制到目标对象中,他将返回目标对象。

Object.assign(films_list.result,res.data.data.data.films)

标签:Vue,console,log,vue,data,name
From: https://www.cnblogs.com/ssrheart/p/18180224

相关文章

  • Vue2工程化介绍
    Vue2项目[基于vue-cli]工程化【一】环境搭建06-Vue-cli-刘清政-博客园(cnblogs.com)安装node使用npm/cnpmnpm换源:npmconfigsetregistryhttps://registry.npmmirror.com安装vue-clicnpminstall-g@vue/cli#安装脚手架cnpminstall-g@vue/cli#切换目录......
  • 解决Vue项目在IIS部署中路由不存在导致的404错误问题
    最近Vue项目部署到IIS时遇到了一个问题:当输入不存在的路由时,页面会报下图的404错误,这样会导致我们的信息暴露,非常不安全,解决这个问题也很简单,通过配置网站的url重写即可解决这个问题。参考文章:https://blog.csdn.net/qq_40323256/article/details/124384969解决方法:给IIS部署的......
  • 探索网站支付系统的奥秘,从Vue3和Spring Boot开始(入门级项目实战+在线教程)附赠项目源码
    你是否曾经在购物时,对着电脑屏幕前的“支付成功”四个字感到好奇?这背后的秘密究竟是什么?今天,让我们一起揭开支付系统的神秘面纱,探索其背后的技术实现。在这个基于Vue3和SpringBoot的支付项目实战中,我们将带你一步步了解支付系统的实现思路。这个项目不仅解决了常用支付方式的......
  • vue2-事件总线$bus的使用
    作用实现不同组件之间进行通信(非父子关系)。 原理$bus就是vue原型上添加的一个vue实例,用于存储、监听以及触发事件。 实现步骤在main.js文件中注册事件总线Vue.prototype.$bus=newVue();在需要发送信息的组件中发送事件this.$bus.$emit("eventname")//无参......
  • Vue —兼容 Vue 2.0到 Vue 3.0 的注意事项
    Vue3与Vue2之间存在一些重要的变化和改进,因此在进行兼容性处理时需要注意一些关键点。1.CompositionAPIVue3引入了CompositionAPI,与Vue2的OptionsAPI不同。如果您在Vue2中使用了OptionsAPI,可以继续使用,但建议尝试使用CompositionAPI,因为它提供了更好......
  • vue多页面应用
    多页面应用本身和单页面应用没什么差别,无非是多了几个入口点。入口点多的话,还可以写个函数扫描路径取添加入口点。比较让人好奇的是路径的问题。我们要开发的时候要体现目录层级接口,所以入口文件是一层套一层的。但是部署后访问路径应该很短才行,最好是顶级路径。但这又只能改目......
  • 【vue3入门】-【0】前言
    本人是一名四年的软件测试人员,想努力向测试开发方向发展,因此在学习的道路上不停在探索。软件测试所需要的知识面太过庞大,但感觉好的测试开发都是会写前端的,也算是在模仿前辈们的脚步前进,希望不会让自己太受打击了,哈哈哈。对于前端,其实是断断续续有在接触,包括html、css、js,但是苦......
  • 【vue3入门】-【20】组件注册方式
    组件注册方式一个vue组件在使用前需先被“注册”,这样vue才能在渲染模版是找到其对应的实现。组件注册有两种方式:全局注册和局部注册全局注册在最外层注册一次,在最内层组件都能使用main.jsimport{createApp}from'vue'importAppfrom'./App.vue'importHeaderfrom......
  • 【vue3入门】-【21】 组件传递数据
    组件传递数据_Props静态数据传递组件与组件之间不是完全独立的,而是有交集的,那就是组件与组件之间是可以传递数据的传递数据的解决方案就是propsapp.vue<template><!--主要要生效Header中的样式,需要删除main.json中默认的main.css样式--><!--不需要再次引入,可以直接使......
  • 【vue3入门】-【22】 组件事件
    组件事件在组件的模版表达式中,可以直接使用$emit方法触发自定义事件触发自定义事件的目的是组件之间传递数据,通过组件事件可以实现子级传递参数给父级App.vue<template><ComponentEvent/></template><script>importComponentEventfrom"./components/componentEvent.......