VUE2
(1)介绍
VUE是渐进式框架
可以一点一点地使用它,只用一部分,也可以整个工程都使用它
Vue特点
易用
- 通过 HTML、CSS、JavaScript构建应用
灵活
- 不断繁荣的生态系统,可以在一个库和一套完整框架之间自如伸缩。
高效
- 20kB min+gzip 运行大小
- 超快虚拟 DOM
- 最省心的优化
(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中数据也跟着改变)
MVVM的特性
- 低耦合:
视图
(View)可以独立于Model变化和修改
,1个ViewModel可以绑定到不同的View上,当View变化的时候 Model可以不变,当Model变化的时候,View也可以不变 - 可复用:可以把一些视图逻辑放在1个ViewModel中,让很多View
重用这端视图的逻辑
(以此减少代码冗余) - 独立开发:
开发
人员可以专注于业务逻辑
和数据的开发
(ViewModel),设计
人员可以专注于页面设计
- 可测试:界面元素是比较难以测试的,而现在的测试可以
针对ViewModel
来编写
MVVM的逻辑
组件化开发、单页面开发
组件化开发
类似于DTL中的include
,每一个组件的内容都可以被替换和复用
单页面开发
只需要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>
(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>
(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>
(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>
(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>
(3)v-model修饰符
v-model
是 Vue.js 中用于实现双向数据绑定的指令,它能够自动将表单控件的值与 Vue 实例中的数据进行同步。v-model
修饰符是用来修改v-model
的行为,以满足特定需求。以下是一些常用的v-model
修饰符:
.lazy
修饰符:失去焦点(change)触发。
<input v-model.lazy="message">
.number
修饰符:将用户输入的值转换为数值类型。
<input v-model.number="age" type="number">
.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>
(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>
(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 事件修饰符:
.stop
只处理自己的事件,父控件冒泡的事件不处理(阻止事件冒泡)
<button @click.stop="handleClick">阻止冒泡</button>
.prevent
阻止a链接的跳转
<a href="https://www.baidu.com" @click.prevent="handleA">点我</a>
.self
只处理自己的事件,子控件冒泡的事件不处理
<div @click.self="handleClick">只有自身触发</div>
.once
事件只会触发一次
<button @click.once="handleClick">只触发一次</button>
(15)按键事件、修饰符
Vue.js 中的按键修饰符允许监听键盘事件时指定特定的按键。这些修饰符用于在触发事件时过滤按键,以便只在特定的按键被按下时才触发对应的事件处理函数。以下是 Vue.js 中常用的按键修饰符:
.enter
只在回车键按下时触发事件。
<input @keyup.enter="handleEnter">
.tab
只在 Tab 键按下时触发事件。
<input @keyup.tab="handleTab">
.delete
/.backspace
只在删除键或退格键按下时触发事件。
<input @keyup.delete="handleDelete">
.esc
只在 Esc 键按下时触发事件。
<input @keyup.esc="handleEsc">
.space
只在空格键按下时触发事件。
<input @keyup.space="handleSpace">
.up
只在上箭头键按下时触发事件。
<input @keyup.up="handleUp">
.down
只在下箭头键按下时触发事件。
<input @keyup.down="handleDown">
.left
只在左箭头键按下时触发事件。
<input @keyup.left="handleLeft">
.right
只在右箭头键按下时触发事件。
<input @keyup.right="handleRight">
这些按键修饰符可以用于 keyup
和 keydown
事件。帮助我们更精确地控制在特定按键按下时触发事件的情况。
(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>
(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>
需要在后端的请求头中配置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()
但是现在一般不使用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
}
})
}
}
使用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
对象中设置自定义的请求头,例如Authorization
、Content-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()
函数接收三个参数:
url
:表示要发送请求的 URL。data
:表示要发送的数据,通常是一个 JavaScript 对象。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()
(18)计算属性computed
- 计算属性是基于它们的依赖进行缓存的
- 计算属性只有在它的相关依赖发生改变时才会重新求值
- 计算属性就像Python中的property,可以把方法/函数伪装成属性
- 写在
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 组件的生命周期钩子是一组在组件创建、更新和销毁阶段调用的钩子函数,它们允许你在特定阶段执行代码。这些钩子函数可以用来执行一些任务,例如初始化数据、侦听事件、发送网络请求等。
钩子函数 | 描述 |
---|---|
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 的生命周期钩子:
- beforeCreate: 在实例初始化之后,数据观测 (data observer) 和事件配置 (event/watcher setup) 之前被调用。
- created: 实例已经创建完成之后被调用,此时实例已完成数据观测 (data observer),属性和方法的运算,watch/event 事件回调已经准备好,但是挂载阶段还未开始。
- beforeMount: 在挂载开始之前被调用:相关的 render 函数首次被调用。
- mounted: el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。
- beforeUpdate: 数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。
- updated: 由于数据更改导致的虚拟 DOM 重新渲染和打补丁后调用。
- beforeDestroy: 实例销毁之前调用。在这一步,实例仍然完全可用。
- destroyed: 实例销毁后调用。此时,所有的事件监听器和子实例都已被移除。
Vue 3.x 的生命周期钩子:
在 Vue 3.x 中,生命周期钩子的名称与 Vue 2.x 中基本相同,但是有两个重大的更改:
- beforeCreate 和 created 钩子保持不变。
- beforeMount 和 mounted 钩子保持不变。
- beforeUpdate 和 updated 钩子保持不变。
- beforeDestroy 钩子变为 beforeUnmount。 在组件实例从 DOM 中卸载之前调用。
- 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>
<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
let
和const
关键字用于声明变量和常量,取代了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
(2)router-link
组件跳转
使用<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
}
这时候路径就会变成这个样子
方式一
<router-link to="/about/23">
<button>点我跳转到about</button>
</router-link>
取值需要在params
中取
this.$route.params
方式二
<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
注意,这个地方一定要在自己的里面也写入data
和methods
混入的导入: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>
(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
(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