是一个js框架
可以简化dom操作
响应式数据驱动
步骤
①导入vue.js
②创建vue实例对象,设置el属性和data属性
③实用简洁的模板语法把数据渲染到页面上
<body>
<div id='app'>
{{message}}
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
message: '你好 luoluo'
}
})
script>
body>
el是设置vue实例挂载的元素
补充:如果el挂载点命中了多个双标签,则只会在第一个双标签生效
vue中用到的数据定义在data中,data中可以写复杂类型的数据,只要在渲染复杂数据时遵守js语法即可
<body>
<div id='app'>
{{message}} <br>
<span>你的家乡在{{home.land}},所属岛天为{{home.daotian}}span>
<div>技能有{{jineng[0]}},{{jineng[1]}},{{jineng[2]}}div>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
message: '你好 luoluo',
home: {
land: '灵帝国',
daotian: 'six'
},
jineng: ['万伥驾驭', '生死玄域', '天命之瞳']
}
})
script>
body>
主要学习使用vue指令
大致可分为
内容绑定,事件绑定
显示切换,属性绑定
列表循环,表单元素绑定
设置文本内容,全部修改,会顶替掉原来的内容
{{}}方法是局部修改
<body>
<div id='app'>
<div>{{message}}灵帝国div>
<div v-text='message'>灵帝国div>
<div v-text='info'>灵帝国div>
<div v-text='info+"补充"'>灵帝国div>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
message: '你好 luoluo',
info: '六重岛天'
}
})
script>
body>
和v-text基本一样,但是v-html能够解析html元素
<body>
<div id='app'>
<div v-text='message'>灵帝国div>
<div v-html='message'>灵帝国div>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
message: '原神'
}
})
script>
body>
补充
cookie简述
cookie可以在f12的application的cookies中找到
可以用cookie editer插件批量处理cookie
刷新cookie是不会丢失的,存于硬盘中
document.cookie获取当前页面的cookie
当data中保存的数据为如下类型时,用v-html渲染,在跳转的时候就会带着本页面的cookie一起走,如果页面的渲染方式为v-html,评论区发送了该数据,且跳转目标位非法者的服务器,就会导致其他点击此链接的用户泄露cookie信息
htm2: 'come here'
所以
v-html有个非常严重的安全性问题,不要随意在网站上动态渲染html内容,要在可信内容上用v-html,不要再用户提交的内容上用
<body>
<div id='app'>
<input type="button" value="v-on指令" v-on:click="dot1">
<input type="button" value="v-on指令简写" @click="dot1">
<input type="button" value="双击事件" @dblclick="dot2">
<h2 v-text="message" @click="change">h2>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
message: '霸天虎'
},
methods: {
dot1: function () {
console.log('五重岛田');
},
dot2: function () {
console.log('六重岛田');
},
change: function () {
this.message = '镇狱兽'
}
}
})
script>
body>
注意:
①v-on用于绑定事件
②简写方法使用@代替
③在方法中使用this可以修改data数据元素
补充
①事件绑定的方法写成函数调用的方式,可以传入自定义参数
②事件后面可以跟上 .修饰符对事件进行限制
③比如@keyup.enter,只有按下回车键时才会触发
<body>
<div id='app'>
<input type="text" @keyup.enter="dot(666)">
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
message: '霸天虎'
},
methods: {
dot: function (p1) {
alert(p1)
},
}
})
script>
body>
案例
计数器
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
#app {
display: flex;
width: 300px;
height: 48px;
font-size: 20px;
border: 0px;
}
#app span {
flex: 1;
text-align: center;
line-height: 48px;
border: 1px solid #999;
}
#app button {
width: 100px;
}
style>
head>
<body>
<div id="app">
<button @click='sub'>-button>
<span v-text="num">span>
<button @click='add'>+button>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: "#app",
data: {
num: 1
},
methods: {
add: function () {
this.num++
},
sub: function () {
this.num--
}
}
})
script>
body>
html>
<body>
<div id='app'>
<input type="button" value="切换显示" @click="ischange">
<img v-show="isShow" src="https://tse3-mm.cn.bing.net/th/id/OIP-C.H1T_sC5zrcopALAu-hAFOQHaHP?pid=ImgDet&rs=1"
alt="">
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
age: 16,
isShow: false
},
methods: {
ischange: function () {
this.isShow = !this.isShow
}
}
})
script>
body>
总结
①v-show指令用于根据真假切换元素现实状态
②原理是修改元素的display,实现显示隐藏
③指令后面的内容,最终都会解析为布尔值
④true显示元素,false隐藏元素
⑤数据改变之后,对应元素的显示状态也会同步更新
①和v-show作用类似,都是根据真假显示隐藏元素
②不同的是,v-show是是操纵样式控制显示和隐藏,而v-if是直接操纵dom元素
③为true,元素存在于dom树,为false,从dom树中移除
④频繁切换用v-show,反之v-if
⑤还有v-else-if,只有在前面的v-if不成立才进行判断,当然还有v-else,这些个是一组
⑥v-if可以和templete搭配,v-show不可以,templete不影响页面结构,即不占用dom空间,当同时要控制两个及以上的div时,放在一个tempplate中进行统一控制
<template v-if='n===1'>
<h2>1h2>
<h2>2h2>
<h2>3h2>
template>
<body>
<div id='app'>
<input type="button" value="切换显示" @click="ischange">
<img v-if="isShow" src="https://tse3-mm.cn.bing.net/th/id/OIP-C.H1T_sC5zrcopALAu-hAFOQHaHP?pid=ImgDet&rs=1"
alt="">
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
isShow: false
},
methods: {
ischange: function () {
this.isShow = !this.isShow
}
}
})
script>
body>
①v-bind用于为元素绑定属性(src,class等)
②完整写法是v-bind:属性名,简写可以省略v-bind
③需要动态增删class可以用对象的方式,下面对象里冒号后面的truefalse决定了class值的有无
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
.active {
border: 1px solid red;
}
style>
head>
<body>
<div id="app">
<img v-bind:src="imgSrc" alt="">
<img :src="imgSrc" alt="" :class="{active:isActive}" @click="change">
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
imgSrc: 'https://www.eayyou.com/upload/resources/image/2020/09/29/327507_600x600.jpg',
isActive: false
},
methods: {
change: function () {
this.isActive = !this.isActive
}
}
})
script>
body>
html>
案例-图片切换
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片切换title>
<style>
a {
text-decoration: none;
width: 25px;
height: 40px;
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
font-size: 18px;
line-height: 40px;
text-align: center;
}
.box {
position: relative;
width: 300px;
height: 240px;
/* background-color: pink; */
margin: 160px auto;
border: 1px solid #ccc;
}
.imgg {
width: 100%;
height: 100%;
}
.prev {
position: absolute;
left: 0;
top: 100px;
}
.next {
position: absolute;
right: 0;
top: 100px;
}
style>
head>
<body>
<div id="app">
<div class="box">
<img :src="imgSrc[index]" alt="" class="imgg">
<a href="javascript:;" class="prev" @click="prev" v-show="index!=0"><a>
<a href="javascript:;" class="next" @click="next" v-show="index" >>a>
div>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
imgSrc: ['https://www.eayyou.com/upload/resources/image/2020/09/29/327507_600x600.jpg',
'https://imgo.hackhome.com/img2020/10/13/14/304373101.png',
'https://tse2-mm.cn.bing.net/th/id/OIP-C.9sMVPeuAGT4uF_G2qTjrBAHaEy?pid=ImgDet&rs=1'
],
index: 0
},
methods: {
prev: function () {
this.index--
},
next: function () {
this.index++
}
}
})
script>
body>
html>
①指令作用是根据数据生成列表结构
②经常和数组一起使用
③语法:(item,index) in 数据
④item和index可以结合其他指令一起用
⑤数组长度的更新会同步刷新到页面上,是响应式的
⑥在使用v-for时,v-bind:key不能省略,一般简写为 :key=“index”
<body>
<div id="app">
<li v-for="(item,index) in arr">下标值为{{index}}的数据为{{item}}li>
<h2 v-for="(item,index) in color">{{item.name}}h2>
<input type="button" @click='add' value="add">
<input type="button" @click='remove' value="remove">
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
arr: [1, 2, 3, 4, 5],
color: [{
name: 'red'
}, {
name: 'origin'
}, {
name: 'yellow'
}]
},
methods: {
add: function () {
this.color.push({
name: 'others'
})
},
remove: function () {
this.color.pop()
}
}
})
script>
body>
①v-model指令的作用是快捷获取和设置表单元素的值
②绑定的数据会和表单元素值相关联,一边修改,两边都会同时变化
<body>
<div id="app">
<input type="button" value="change" @click="change">
<input type="text" v-model="message">
<h2 v-text='message'>h2>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
message: '青空结界'
},
methods: {
change: function () {
this.message = '紫呜怜'
}
}
})
script>
body>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
* {
margin: 0;
padding: 0;
}
body {
background-color: #F3F3F3;
}
.title {
width: 300px;
height: 60px;
margin: 100px auto 30px;
line-height: 60px;
text-align: center;
font-size: 36px;
color: orange;
}
.content {
width: 360px;
/* height: 200px; */
background-color: #fff;
margin: 0 auto;
box-shadow: 5px 5px 5px #ccc;
}
.content input {
width: 350px;
height: 35px;
border: none;
outline: none;
box-shadow: 2px 5px 5px #ccc;
font-size: 18px;
padding-left: 10px;
}
.lr {
width: 100%;
height: 25px;
font-size: 8px;
color: #999;
}
.left {
float: left;
width: 60px;
padding-left: 5px;
margin-top: 5px;
}
.right {
float: right;
width: 35px;
margin-top: 5px;
}
.content p {
width: 345px;
height: 40px;
/* background-color: pink; */
font-size: 20px;
color: #999;
line-height: 40px;
padding-left: 15px;
border-bottom: 1px dashed #ccc;
}
.aaa {
float: right;
display: none;
text-decoration: none;
font-size: 14px;
color: #999;
padding-right: 15px;
}
.content p:hover .aaa {
display: block;
}
style>
head>
<body>
<div id="app">
<div class="title">
小黑记事本
div>
<div class="content">
<input type="text" @keyup.enter="add" v-model="message" placeholder="请输入内容" autofocus="autofocus"
autocomplete="off">
<p v-for="(item,index) in arr">{{index+1}}. {{item}}
<a href="javascript:;" class="aaa" @click="remove(index)">xa>
p>
<div class="lr" v-show="arr.length>0">
<div class="left">{{arr.length}} itemsdiv>
<div class="right" @click="clear">Cleardiv>
div>
div>
div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
message: '',
arr: []
},
methods: {
add: function () {
this.arr.push(this.message)
this.message = ''
},
remove: function (p1) {
this.arr.splice(p1, 1)
},
clear: function () {
this.arr = []
}
}
})
script>
body>
html>
本质是一个特殊属性,vue实例创建并接管容器后,会删掉v-clock属性
配合css可以解决当网速过慢的时候页面出现{{xxx}}的问题
①v-once在所在节点初次渲染后,就视为静态内容了
②以后数据无论发生任何变化都不会引起v-once所在结构的改变
<body>
<div id="app">
<h2 v-once>初始化n值为{{n}}h2>
<h2>现在的n值为{{n}}h2>
<button @click='n++'>点我n+1button>
div>
<script src="../js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
n: 1
}
})
script>
body>
v-pre可以跳过所在节点的编译过程,适用于无需解析渲染的节点
功能强大的网络请求库
①需要先导入再使用
②使用get或post方法发送对应的请求
③then方法的回调函数会在请求成功或失败时触发
④通过回调函数获取相应内容或错误信息
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<input type="button" value="get" class="get">
<input type="button" value="post" class="post">
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
<script>
document.querySelector('.get').onclick = function () {
axios.get('https://autumnfish.cn/api/joke/list?num=3').then(data => {
console.log(data);
}).catch(err => {
console.log(err);
})
}
document.querySelector('.post').onclick = function () {
axios.post('https://autumnfish.cn/api/user/reg', {
username: "图坦卡蒙"
}).then(data => {
console.log(data);
}).catch(err => {
console.log(err);
})
}
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<input type="button" value="get" @click='getjoke'>
<p v-text='joke'>p>
div>
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
var app = new Vue({
el: '#app',
data: {
joke: ''
},
methods: {
getjoke: function () {
axios.get('https://autumnfish.cn/api/joke').then(data => {
console.log(data.data);
this.joke = data.data
}).catch(err => {
console.log(err);
})
}
}
})
script>
body>
html>
是一套用于构建用户界面的渐进式JavaScript框架
特点:
①采用组件化模式,提高代码复用率,让代码更好维护
②声明式编码,让编码人员无需直接操作dom,提高开发效率
(命令式编码就是写一句动一下,声明式,写一下整套流程动到结束)
③使用虚拟DOM和优秀的Diff算法,尽量复用DOM节点
<body>
<div id="app">
<h2>{{name}}h2>
div>
<script src="../js/vue.js">script>
<script>
Vue.config.productionTip = false //阻止vue启动时生成提示
new Vue({
el: '#app',
data: {
name: '笨蛋老虎'
}
})
script>
body>
注意:
①阻止提示可以修改config的属性
②可以直接创建Vue对象,无需赋值给变量
③如果有两个相同的容器,vue只负责第一个,第二个不做渲染
即vue实例与容器是一一对应的,不可一对多,也不能多对一
④双花括号里只能放表达式,才能被解析,否则只能被视作字符串
有插值语法({{ }})和指令语法(v-)两种
其他指令看上面vue简介
注意:
①v-model只能用在表单类元素上,即有value属性的表单元素
1.el
①创建vue时配置
new Vue({
el: '#app',
data: {
name: '笨蛋老虎'
}
})
②先创建,后配置
var app = new Vue({
// el: '#app',
data: {
name: '笨蛋老虎'
}
})
app.$mount('#app')
两种方式想用哪个都可以
2.data
①对象式
var app = new Vue({
// el: ‘#app’,
data: {
name: ‘笨蛋老虎’
}
})
②函数式
var app = new Vue({
el: ‘#app’,
data: function () {
return {
name: ‘笨蛋老虎’
}
}
})
注意:
①在使用组件的时候必须要用函数式
②函数式中的函数调用者是vue,this指向vue实例,所以不要用箭头函数
所有写在data中的数据都会出现在vm模型(vue实例)上,模板语法实际上是去读取vm模型,所以模板语法可以读取到vue实例中出现的所有元素
1.Object.defineProperty函数
3个参数分别是,对象,属性,属性值,用于给对象添加属性
特点
①添加的值不参与遍历(枚举)
②添加的值不能修改和删除
<script>
let person = {
name: '七七',
sex: '女'
}
Object.defineProperty(person, 'age', {
value: 345
})
console.log(person);
person.sex = 'nv'
person.age = 777
console.log(person);
</script>
解决办法:
Object.defineProperty(person, 'age', {
value: 345,
enumerable: true, //控制属性是否可以枚举,默认值为false
writable: true, //控制属性是否可以被修改,默认值为false
configurable: true //控制属性是否可以被删除,默认值为false
})
get和set函数
如果直接在person里让age等于number,可以成功获取number值,但是number之后修改,age不会跟着变化,
采用get方法,可以读取的同时获取,实现同步修改
let number=18
let person = {
name: '七七',
sex: '女'
}
Object.defineProperty(person, 'age', {
//当有人读取age属性时,get函数就会被调用,返回age的值
get(){
console.log('有人读取age属性');
return number
},
//当有人修改age属性时,set函数就会被调用,value就是修改后的值
set(value){
console.log('有人修改了age属性',value);
number=value
}
})
2.数据代理是什么
定义:通过一个对象代理对另一个对象中属性的操作
举个例子
<script>
let obj = {
x: 100
}
let obj2 = {
y: 200
}
Object.defineProperty(obj2, 'x', {
get() {
return obj.x
},
set(value) {
obj.x = value
}
})
</script>
3.vue中应用数据代理
vue实例中的属性就是用的数据代理,每当获取vue中某属性时,就会触发get方法,获取到data中的对应属性,vue中对应属性改变后触发set修改data中的数据
vue中的data就是vue中的_data
简单来说就是,name,address属性存在于vue中的_data属性中,然后用数据代理在vue中用同名属性代理操作_data中的属性,页面渲染用的就是vue中的代理属性,每个代理属性都有它自己的get和set方法
1.基本使用
看上面v-on
注意:
①如果要传其他参数又要传event,可以在传的时候用$event占个位置,表示传的是event
②methods是没有做数据代理的
2.事件修饰符-前三个常用
①prevent:阻止默认事件
②stop:阻止冒泡事件
③once:事件只触发一次
④capture:使用时间的捕获模式
⑤self:只有event.target是当前操作的元素时才触发事件
⑥passive:事件的默认行为立即执行,无需等待时间回调函数执行完毕
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<style>
.maopao {
height: 100px;
background-color: pink;
}
.wheel {
height: 200px;
width: 150px;
background-color: skyblue;
overflow: auto;
}
.wheel li {
height: 100px;
width: 150px;
}
style>
head>
<body>
<div id="app">
<a href="www.baidu.com" @click.prevent='alerting'> 点我a>
<div @click='alerting' class="maopao">
<button @click.stop='alerting'>阻止冒泡事件button>
div>
<button @click.once='alerting'>只触发一次button>
<div @click.capture='alerting' class="maopao">
<button @click='alerting'>使用捕获模式button>
div>
<div @click.self='alerting' class="maopao" style="margin-top: 10px;">
<button @click='alerting'>selfbutton>
div>
<div class="wheel" @wheel.passive='wheel'>
<li>#li>
<li>#li>
<li>#li>
<li>#li>
div>
div>
<script src="../js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {},
methods: {
alerting: function () {
alert('提示信息')
},
wheel: function () {
for (let i = 0; i < 10000; i++) {
console.log('#');
}
}
}
})
script>
body>
html>
Vue.config.keyCodes.huiche=13
注意:一旦data中数据发生变化,页面就会重新解析渲染
1.使用插值实现姓名案例
<body>
<div id="app">
姓: <input type="text" v-model='xing'><br>
名: <input type="text" v-model='ming'><br>
全称: <span>{{xing.slice(0,2)}}-{{ming}}span>
div>
<script src="../../js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
xing: '',
ming: ''
}
})
script>
body>
实现姓名重组,并且用slice限制姓的长度
2.methods实现姓名案例
<body>
<div id="app">
姓: <input type="text" v-model='xing'><br>
名: <input type="text" v-model='ming'><br>
全称: <span>{{fullName()}}span>
div>
<script src="../../js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
xing: '',
ming: ''
},
methods: {
fullName: function () {
return this.xing + '-' + this.ming
}
}
})
script>
body>
3.计算属性实现姓名案例
注意
①计算属性本身不存在,要通过已有属性计算得来
②底层借助Object。defineproperty方法提供的get和set
③get仅在初次读取数据和依赖数据发生改变时执行
④当执行一次歌天后,计算结果会缓存,后面再有使用计算属性的,直接用缓存值,实现了复用
⑤计算属性没使用数据代理,直接出现在vm上,直接读取使用即可
⑥当计算属性被修改时,要调用set方法修改依赖属性
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
姓: <input type="text" v-model='xing'><br>
名: <input type="text" v-model='ming'><br>
全称: <span>{{fullName}}span>
div>
<script src="../../js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
xing: '',
ming: ''
},
computed: {
fullName: {
get() {
return this.xing + '-' + this.ming
},
set(value) {
let arr = value.split('-')
this.xing = arr[0]
this.ming = arr[1]
}
}
}
})
script>
body>
html>
fullName(){
return this.xing + '-' + this.ming
}
只有在只需要get方法时才可简写,直接写成es6简写方法形式
①当被监视的属性发生改变时,回调函数自动调用
②监视的属性必须存在才能进行监视
③有两种写法,一种创建vue时传入watch配置,一种通过vm.$watch监视
<body>
<div id="app">
<h2>今天的天气很{{info}}h2>
<button @click='change'>切换天气button>
div>
<script src="../../js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
ishot: true
},
computed: {
info() {
return this.ishot ? '炎热' : '凉爽'
}
},
methods: {
change() {
this.ishot = !this.ishot
}
},
watch: {
ishot: {
immediate: true, //初始化时让handler执行一下
handler(newValue, oldValue) {
console.log('属性发生了改变', oldValue, newValue);
}
}
}
})
script>
body>
vm.$watch('ishot', {
immediate: true, //初始化时让handler执行一下
handler(newValue, oldValue) {
console.log('属性发生了改变', oldValue, newValue);
}
})
深度监视
①监视多极结构中的某个属性
属性中的属性要监视用‘a.b’,记得加引号
watch: {
'ishot.a:' {
immediate: true, //初始化时让handler执行一下
handler(newValue, oldValue) {
console.log('属性发生了改变', oldValue, newValue);
}
}
}
②监视多级属性中所有的属性,配置deep:true
watch: {
ishot: {
deep:true,
immediate: true, //初始化时让handler执行一下
handler(newValue, oldValue) {
console.log('属性发生了改变', oldValue, newValue);
}
}
}
简写
ishot(newValue, oldValue) {
console.log('属性发生了改变', oldValue, newValue);
}
vm.$watch('ishot',
function(newValue, oldValue) {
console.log('属性发生了改变', oldValue, newValue);
}
)
简写的缺点就是不能配置immediate和deep
和上面差不多
绑定class样式,basic确定,另一个不确定,用v-bind
style
注意style属性名写法,-要去掉,后面单词首字母大写
有两种方式完成,watch和computed,当两者都能实现时,优先使用computed
①监视属性
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>watch实现title>
head>
<body>
<div id="app">
<input type="text" v-model='keyword'>
<li v-for='(item,index) in filpersons'>{{item.name}}-{{item.sex}}li>
div>
<script src="../js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
keyword: '',
persons: [{
id: '001',
name: '天王星',
sex: '女'
},
{
id: '002',
name: '冥王星',
sex: '男'
},
{
id: '003',
name: '大金星',
sex: '女'
},
{
id: '004',
name: '王天王',
sex: '男'
},
{
id: '005',
name: '冥御史',
sex: '男'
},
],
filpersons: []
},
watch: {
keyword: {
immediate: true,
handler(val) {
this.filpersons = this.persons.filter(p => {
return p.name.includes(val)
})
}
}
}
})
script>
body>
html>
②计算属性
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>watch实现title>
head>
<body>
<div id="app">
<input type="text" v-model='keyword'>
<li v-for='(item,index) in filpersons'>{{item.name}}-{{item.sex}}li>
div>
<script src="../js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
keyword: '',
persons: [{
id: '001',
name: '天王星',
sex: '女'
},
{
id: '002',
name: '冥王星',
sex: '男'
},
{
id: '003',
name: '大金星',
sex: '女'
},
{
id: '004',
name: '王天王',
sex: '男'
},
{
id: '005',
name: '冥御史',
sex: '男'
},
],
},
computed: {
filpersons() {
return this.persons.filter(p => {
return p.name.includes(this.keyword)
})
}
}
})
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>watch实现title>
head>
<body>
<div id="app">
<input type="text" v-model='keyword'>
<button @click='sortnum=2'>升序button>
<button @click='sortnum=1'>降序button>
<button @click='sortnum=0'>原顺序button>
<li v-for='(item,index) in filpersons'>{{item.name}}-{{item.sex}}-{{item.age}}li>
div>
<script src="../js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
keyword: '',
sortnum: 0,
persons: [{
id: '001',
name: '天王星',
sex: '女',
age: 19
},
{
id: '002',
name: '冥王星',
sex: '男',
age: 25
},
{
id: '003',
name: '大金星',
sex: '女',
age: 23
},
{
id: '004',
name: '王天王',
sex: '男',
age: 18
},
{
id: '005',
name: '冥御史',
sex: '男',
age: 26
},
],
},
computed: {
filpersons() {
const arr = this.persons.filter(p => {
return p.name.includes(this.keyword)
})
if (this.sortnum) {
arr.sort((p1, p2) => {
return this.sortnum === 2 ? p1.age - p2.age : p2.age - p1.age
})
}
return arr
}
}
})
script>
body>
html>
1.如何检测对象
靠set方法
即Vue.set()也可用vm.$set()
这种方法添加的属性也有get和set方法
局限性:不能直接给vm或data添加属性,只能给data里属性及以下添加属性
2.如何检测对象
数组内元素是没有get,set的,通过赋值运算无法被vue检测到,但是通过push,pop等方法修改数组元素时,依旧可以检测到改变,因为这些方法是被vue包装过的,不是原汁原味的方法,通过这些方法检测变化
1.使用v-model获取input和select,textarea类型(即有value值的项目)
①如果是text,password等有输入框的,直接v-model获取value值
②单选框radio,要给每个选项设置好value值
③checkbox多选框,除了设置value值,还要把初始值设置为数组,否则收集的是checked布尔值
④textarea,select等设置上value即可
②修饰符-加在v-model后,如v-model.trim=‘’
①lazy:失去焦点再收集数据
②number:输入字符转为有效的数字
③trim:输入首尾空格过滤
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<form action="">
账号:<input type="text" v-model='username'><br><br>
密码:<input type="password" v-model='password'><br><br>
性别:
男<input type="radio" name="sex" v-model='sex' value="male">
女<input type="radio" name="sex" v-model='sex' value="female"><br><br>
爱好:
吃饭:<input type="checkbox" v-model='hobby' value="1">
睡觉:<input type="checkbox" v-model='hobby' value="2">
打豆豆:<input type="checkbox" v-model='hobby' value="3"><br><br>
所属校区:
<select name="" id="" v-model='fangxiang'>
<option value="">请选择校区option>
<option value="dong">东option>
<option value="nan">南option>
<option value="xi">西option>
<option value="bei">北option>
select><br><br>
其他:
<textarea name="" id="" cols="30" rows="10" v-model='other'>textarea><br><br>
<input type="checkbox">阅读并接受用户协议
<input type="button" value="提交" @click='tijiao'>
form>
div>
<script src="../js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
username: '',
password: '',
sex: 'male',
hobby: [],
fangxiang: '',
other: ''
},
methods: {
tijiao() {
console.log(JSON.stringify(this._data));
}
}
})
script>
body>
html>
过滤器本质是一个函数,对要显示的的数据做一些简单处理再显示
注册过滤器
①像methods那样,作为vue实例的一个属性设置上,不过filters是局部的,只有当前vue可以用
②Vue.filter(name,callback)
其他
①过滤器可以接收额外参数,多个过滤器也可以串联
②没有改变原来的数据,而是产生新的数据
③插值语法和v-bind可以使用过滤器,其他的不行
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<h2>时间戳{{now}}h2>
<h2>computed实现{{comnow}}h2>
<h2>methods实现{{metnow()}}h2>
<h2>filters实现{{now | filnow()}}h2>
<h2>filters传参{{now | filnow('YYYY-MM-DD')}}h2>
<h2>filters串联{{now | filnow('YYYY-MM-DD') |filslice()}}h2>
<h2>filter全局{{now | filnow('YYYY-MM-DD') |fslice()}}h2>
div>
<script src="../js/vue.js">script>
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js">script>
<script>
Vue.filter('fslice', function (val) {
return val.slice(0, 4)
})
var vm = new Vue({
el: '#app',
data: {
now: 1638797329896
},
computed: {
comnow() {
return dayjs(this.now).format('YYYY-MM-DD HH:mm:ss')
}
},
methods: {
metnow() {
return dayjs(this.now).format('YYYY-MM-DD HH:mm:ss')
}
},
filters: {
filnow(val, src = 'YYYY-MM-DD HH:mm:ss') {
return dayjs(val).format(src)
},
filslice(val) {
return val.slice(0, 4)
}
}
})
script>
body>
html>
①在directives属性中定义自定义指令
②有两种方式可以定义,分别为函数式和对象式
③函数式传入的两个参数,element就是所在的dom元素,binding则是绑定的参数详细信息
④自定义指令函数式只有在指令与元素绑定成功时和指令所在模板被重新解析时
⑤对象式在对象内存放多个函数,分别在三个不同的时刻调用不同的函数,函数式相当于对象式的阉割版只在两个不同时刻调用
⑥,命名用多个单词时用-链接,命名中出现-时可以用引号把名字包起来
⑦全局自定义指令Vue.directtive(name,对象或者函数)
<body>
<div id="app">
<h2>当前n值为:<span v-text='n'>span>h2>
<h2>放大后n值为:<span v-big='n'>span>h2>
<button @click='n++'>n++button>
<input v-fbind:value="n" type="text">
div>
<script src="../../js/vue.js">script>
<script>
var vm = new Vue({
el: '#app',
data: {
n: 1
},
directives: {
big(element, binding) {
element.innerText = binding.value * 10
},
fbind: {
//指令与元素绑定时
bind(element, binding) {
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element, binding) {
element.focus()
},
//指令所在的模板被重新解析时
update(element, binding) {
element.value = binding.value
}
}
}
})
script>
body>
mounted函数,与data,methods等同级
在vue完成模板的解析并把初始的真实dom元素放入页面后,再调用mouted,且只调用一次
①生命周期又名生命周期回调函数,生命周期函数,生命周期钩子
②是vue在关键时刻帮我们调用的一些特殊名称的函数
③生命周期函数的名字不可更改,但具体的内容是根据需求写的
④生命周期函数中的this指向是vm或组件实例对象
<body>
<div id="app">
<h2 :style="{opacity}">学习Vue-ingh2>
div>
<script src="../js/vue.js">script>
<script>
new Vue({
el: '#app',
data: {
opacity: 1
},
mounted() {
setInterval(() => {
this.opacity -= 0.01
if (this.opacity <= 0) this.opacity = 1
}, 16)
},
})
script>
body>
生命周期钩子总结
常用的生命周期钩子
①mounted:发送ajax请求,启动定时器,绑定自定义事件订阅消息等初始化操作
②beforeDestroy:清除定时器,解绑自定义事件,取消订阅消息等收尾工作
关于销毁Vue实例
①销毁后借助Vue开发者工具看不到任何信息
②销毁后自定义事件会失效,但原生DOM事件依然有效
③一般不会在beforeDestory操作数据,即便操作了也不会触发更新流程
模块:向外提供一定功能的js程序,一般为一个js文件
组件:实现应用中局部功能代码和资源的集合
优点:复用代码,简化项目编码。提高编码效率
模块化:当应用中的js都以模块来编写的,那这个应用就是一个模块化的应用
组件化:当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用
单文件组件:一个文件中只包含一个组件(用的多,条理清晰)
非单文件组件:一个文件中包含n个组件
组件创建时不写el,以后哪里需要往哪搬
组件里的数据要用函数式,那么一个组件被使用多次是不会互相干扰的
1.创建组件
const school=Vue.extend({ })
2.注册组件
局部注册
components:{
school:school}
全局注册
Vue.component(组件名,组件)
3.编写组件标签
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
<school>school>
<student>student>
<hello>hello>
div>
<div id="root">
<hello>hello>
div>
<script src="../../js/vue.js">script>
<script>
//全局注册
const hello = Vue.extend({
template: `
{{helloname}}
`,
data() {
return {
helloname: 'hello'
}
},
})
Vue.component('hello', hello)
//第一步-创建组件
const school = Vue.extend({
template: `
{{schoolname}}
{{address}}
`,
data() {
return {
schoolname: '灵帝国',
address: '九重岛天'
}
},
})
const student = Vue.extend({
template: `
{{studentName}}
`,
data() {
return {
studentName: '王玄清',
age: 18
}
},
})
new Vue({
el: '#app',
//第二步-注册组件
components: {
school: school, //常规形式
student //简写形式,key与value相同时用
}
})
new Vue({
el: '#root'
})
script>
body>
html>
①命名官方推荐
一个单词组成:首字母大小写都行
多个单词组成:第一种my-school,记得在vue里用引号引住,第二种MySchool,需要有Vue脚手架
②关于组建标签的写法
第一种
第二种
需要vue脚手架
③组件创建简写const school ={data(){return}}
把一个组件写在另一个组件的components里面,同时组件标签页也要写在另一个组件模板里面
要注意顺序问题,子组件在定义时要在父组件的前面
通常嵌套都有一个领头的,vm之下,其他组件之上,然后在vm的template中放领头的组件标签,就可以实现容器内干干净净,标准化开发都是这么干的
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<div id="app">
div>
<script src="../../js/vue.js">script>
<script>
//第一步-创建组件
const student = Vue.extend({
template: `
{{studentName}}
`,
data() {
return {
studentName: '王玄清',
age: 18
}
},
})
const school = Vue.extend({
template: `
{{schoolname}}
{{address}}
`,
data() {
return {
schoolname: '灵帝国',
address: '九重岛天'
}
},
components: {
student
}
})
new Vue({
el: '#app',
template: ` `,
components: {
school
}
})
script>
body>
html>
注意:template中如果只有一个标签可以只放该标签,如果有多个,一定要把多个放在一个div里面
1.组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,而是vue.extend生成的
2.我们只需要写,Vue解析时会帮我们创建school的组件实例对象,即Vue帮我们执行new VueComponent(options)
3.每一次调用extend,就会返回一个全新的VueComponent构造函数,当场定义当场返回
4.关于this指向
组件配置中,data,methods等this指向均为VueComponent实例对象
Vue实例配置中,data,methods等this指向均为Vue实例对象
5.VueComponent实例对象简称vc,vue实例对象简称vm
vm和vc不完全相同,vc有的vm都有,vm有的vc不一定有,而且vc中的一些属性要用函数式
prototype:显式原型属性
proto:隐式原型属性
他俩指向了实例的原型对象
在判断的时候要把VueComponent改成对应的school或其他具体组件
<template>
<div class="demo">
<h2>{{ schoolname }}h2>
<h2>{{ address }}h2>
div>
template>
<script>
// 组件的交互
export default {
name: "School",
data() {
return {
schoolname: "灵帝国",
address: "九重岛天",
};
},
};
script>
<style lang="">
/* 组件的样式 */
style>
是官方提供的标准化开发工具/平台
render:h=>h(App)
是一个箭头函数,h是传入的参数,是一个函数,用来注册组件和生成元素,就不用tempplate和components了
public文件夹和main.js不能修改,修改了就运行不起来了
vue inspect > output.js
可以把所有默认配置输出为一个js文件用于浏览,但修改了没用
和id属性类似,可以辅助获取dom元素
在vue文件中this指向就是该组件
注意:同时使用多个同一组件实例,每个组件实例之间互不影响
使用props可以在父级传参数,然后在子级组件用props接收使用,传过来的是字符串,可以通过props里的type修改,传入的数值尽可能不要改,可以改,但会有警示
要改的话就定义一个参数等于这个值,然后用新参数来改
混入的数据方法如果和原来的冲突,那么以原来的为主,如果有mounted,来者不拒,都要
写在所有组件里的style样式最后都会解析在一个文件里,会造成命名冲突,
于是用到了scoped,单词作用域的意思,原理就是给不同的style添加随机生成的属性,这样就
让样式在局部生效,防止冲突
写法:
遇到的问题
1.uuid用于生成全球唯一id,nanoid是它的缩小版
2.数据子传父,父给子传一个函数,然后子调用这个函数
3.父传子数据时记得带:即v-bind,这样才能传表达式或者函数,否则传的都是字符串
4.组件命名要用驼峰法,而且不不能是一个单词要是XxxXxxx
5.组件注册了就要用
6.v-for循环时记得绑定key
7.判断方法,当触发方法时进行一个判断,点确定就继续执行
8.reduce,用于数组的条件计数
9.使用v-show决定底部的显示与隐藏
10.删除数组中指定位置往后的元素,splice(index,)
实现子组件给父组件传递信息,有两种方法
1.使用props,父亲给孩子传一个函数,然后孩子props接收,调用此函数传参
2.父亲在孩子的组件实例绑定一个自定义事件, 然后在子组件的方法中调用this. e m i t ( " 自定义组件名 " ,参数(可以传很多参数) ) 3. 也是用 t h i s . emit("自定义组件名",参数(可以传很多参数)) 3.也是用this. emit("自定义组件名",参数(可以传很多参数))3.也是用this.emit,不过是在绑定自定义事件时使用mounted中this.$refs.shuru.$on("chuancan", this.huoqu);
好处是可以设置延时等操作
**注意:**给组件绑定原生事件也会被默认认为是自定义事件,除非加上.native,如@click.native=
用this. o f f t h i s . off this. offthis.off()----全部解绑
this. o f f ( a ) − − − − 解绑指定事件 t h i s . off(a)----解绑指定事件 this. off(a)−−−−解绑指定事件this.off([a,b])----解绑多个事件
组件的销毁this.$destroy()
销毁之后组件及子组件的自定义事件都不奏效了
简单来说,就是为vue的原型对象添加一个vue实例对象(因为这个实例对象中有着 o n , on, on,off等方法)
因为每个组件实例对象往上追溯都是vue,也就是说每个实例对象都继承了这个组件实例对象,这个对象也被称为事件总线,
接下来当两个组件想要通信时,接收方为总线绑定自定义事件,发送方调用该自定义事件。
(可用于任意组件间通信)
注意:在绑定事件的组件里,在beforeDestroy钩子中,要解绑该组件用到的事件,这样组件销毁后,总线中的事件也会跟着销毁
父传子:用props
子传父:用props,自定义事件都可
同级传,孙传爷:用全局事件总线
也适用于任意组件通信,和总线几乎一摸一样,
且总线是vue本身的,订阅是外部库,所以大多时候用的都是总线
注意:接收数据时,会接受两个参数,第一个是订阅名,第二个才是传的参数
为要添加动画的元素包裹上transition
<transition name="dong" appear>
<div class="ahh" v-show="ist">{{ msg }}</div>
</transition>
再设置动画
transition上的name就是下面动画标签的前缀,后缀是vue固定的
这样,当元素显隐的时候,vue会自动给元素添加对应的动画标签
.dong-enter-active {
animation: dong 1s;
}
.dong-leave-active {
animation: dong 1s reverse;
}
@keyframes dong {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
注意:
①和tempplate一样,解析的时候就消失了
②appear是为了刷新的时候自动触发一次出现动画
和动画类似,方法为
.guo-enter,
.guo-leave-to {
transform: translateX(-100%);
}
.guo-enter-to,
.guo-leave {
transform: translateX(0);
}
.guo-enter-active,
.guo-leave-active {
transition: 1s;
}
在整个进入过程中,transition标签一共给元素添加了三个样式
.v-enter进入的起点
.v-enter-active进入的过程中
.v-enter-to进入的终点
来控制整个动画
注意:transition标签只能控制一个元素的动画
控制多个要用transition-group
但只能控制相同动画元素
第三方动画库:animate.style
1.代理服务器
vue请求服务器一般使用axios
1.创建请求组件(记得先安装axios再引入)(npm i axios)(import axios from “axios”
<template>
<button @click="qingqiu">请求学生数据</button>
</template>
<script>
import axios from "axios";
export default {
methods: {
qingqiu() {
axios.get("http://localhost:8080/students").then(
(response) => {
console.log("yes", response.data);
},
(error) => {
console.log("no", error.message);
}
);
},
},
};
</script>
<style>
</style>
注意:因为使用了代理服务器,所以目标地址是代理服务器的端口号
2.配置代理服务器
在vue.config.js里,地址写目标服务器地址
devServer: {
proxy:'http://localhost:5000'
}
3.补充:创建一个服务器
要保证电脑已经安装了node,且文件安装了express
const express = require("express")
const app = express()
app.use((request,response,next) => {
console.log("有人请求1了");
next()
})
app.get('/students', (request,response) => {
const students = ["这是数据"]
response.send(students)
})
app.listen(5000, (err) => {
if(!err) console.log("启动成功");
})
这种代理服务器不灵活,且当本地有对应数据时,就不会去请求其他服务器,因此有第二种方法更灵活,并且第二种方法有可以配置多个代理
2.代理服务器2
devServer: {
proxy: {
// 这个名字可以不用api,改成自己想要的
'/api': {
// 路径地址
target: 'http://localhost:5000',
// 路径置换,因为请求那里有/api,所以要去掉api
pathRewrite: { '^/api': '' },
// 这两个可以不写
ws: true,
changeOrigin:true
}
}
}
这要在端口号后加上代理名称
methods: {
qingqiu() {
axios.get("http://localhost:8080/api/students").then(
(response) => {
console.log("yes", response.data);
},
(error) => {
console.log("no", error.message);
}
);
},
},
父组件
<template>
<div class="main">
<CateGory title="美食">
<img
src="https://s.cn.bing.net/th?id=OIP-C.ku8Xxe4A_gkLMC1bWlb5FAHaEo&w=316&h=197&c=8&rs=1&qlt=90&o=6&pid=3.1&rm=2"
alt=""
/>
</CateGory>
<CateGory title="游戏">
<ul>
<li v-for="(item, index) in game" :key="index">{{ item }}</li>
</ul>
</CateGory>
<CateGory title="电影">
<video
autoplay
controls
src="https://webstatic.mihoyo.com/upload/op-public/2022/03/08/942f3c2ac510dc3188449e82c4c3dd06_2539121796737105485.mp4"
></video>
</CateGory>
</div>
</template>
子组件
<template>
<div class="container">
<h2>{{ title }}展示平台</h2>
<slot>啥也没传就展示这个</slot>
</div>
</template>
这个slot就是插槽,当组件实例那边传过来内容,就放在插槽位置,不然就显示插槽内容
style样式写在子组件父组件都行
写在父组件,父组件渲染样式后再发过去
写在子组件,发过来子组件自己渲染
注意:
①具名插槽,vue2支持在标签内写插槽名,如
vue3不支持了,必须要在外面套一层template,在template里写名字,
<template #two>
<a href="">美食party</a>
</template>
②具名写法
在子组件slot添加name属性
在父组件引入
<template two>
<a href="">美食party</a>
</template>
简写就是#two
适用于数据在子组件,用同一个数据生成多个结构的场景
父组件
scope用来接收子组件传的数据
子组件
给父组件用到的slot传参
概念:是一个在vue中实现集中式状态/数据管理的一个vue插件,对多个组件的共享状态进行集中式管理(读/写)
用处:可用于任意组件间通信
使用场景:多组件共享状态
actions就如同服务员,用来写条件判断等逻辑
mutations如同后厨,就写具体操作
如果是纯纯的操作,就直接commit调用mutations
有点业务逻辑的就继续通过actions
1.安装vux
npm i vuex@next
2.创建vuex文件
在src/store/index.js引入vuex,之后创建一个vuex实例,进行state等项目的配置
3.项目引入
在main.js里import这个index.js,并use()它
注意:①use写在mount前面,mount写在最后
②引入时写到store即可,他会自动识别文件
4.vuex使用
在组建中直接使用this.$store就可用了
如果是在setup中使用。要先import,再const使用
正常用法
先调用actions
ji() {
this.$store.dispatch("jix", this.n);
},
actions再调用mutations
jix(context, value) {
if (value%2) context.commit('JIAX',value)
},
mutations执行对应的操作
如果仅仅是简单直接的操作,没有条件判断之类的,可以直接调用mutations
jia() {
this.$store.commit("JIAX", this.n);
},
1.getters
类似于计算属性
getters: {
bigsum(state) {
return state.sum*10
}
},
使用方法$store.getters.bigsum
1.mapstate,mapgetters
用来映射数据生成计算属性
①常规计算属性写法
computed: {
sum() {
return this.$store.state.sum;
},
ys() {
return this.$store.state.ys;
},
bh() {
return this.$store.state.bh;
},
bigsum() {
return this.$store.getters.bigsum;
},
},
②使用映射的写法-有两种对象写法和数组写法
先引入
import { mapState, mapGetters } from "vuex";
对象写法
computed: {
...mapState({ sum: "sum", ys: "ys", bh: "bh" }),
...mapGetters({ bigsum: "bigsum" }),
},
数组写法(适用于组件属性名和state的属性名一致的场景)
computed: {
...mapState(["sum", "ys", "bh"]),
...mapGetters(["bigsum"]),
},
2.mapactions,mapmutations
①正常的调用actions和mutations方法的方式
methods: {
jia() {
this.$store.commit("JIAX", this.n);
},
jian() {
this.$store.commit("JIANX", this.n);
},
ji() {
this.$store.dispatch("jix", this.n);
},
djia() {
this.$store.dispatch("djiax", this.n);
},
},
②引入
import { mapState, mapGetters,mapActions,mapMutations } from "vuex";
③写法-也是有对象和数组写法两种
这里只写了对象写法,如果名字一样用数组写法
methods: {
...mapMutations({ jia: "JIAX", jian: "JIANX" }),
...mapActions({ ji: "jix", djia: "djiax" }),
},
**注意:**使用map生成的话,调用方法的时候要记得传参
<button @click="jia(n)">+</button>
1.vuex组件化编写
①把不同功能的属性和方法写在一个单独的js文件中,
②把模块默认暴露出去,注意要写namespaced,后边组件才能正常映射属性和方法
export default {
namespaced:true,
// 数据仓库
state:{
sum: 0,
ys: '原神',
bh:'崩坏三'
},
// 获取数据,类似于计算属性,逻辑复杂且还想复用就用getters
getters: {
bigsum(state) {
return state.sum*10
}
},
// 异步方法
actions: {
// context存放着几个可能要用的方法,可以理解为一个迷你版的store
jix(context, value) {
if (value%2) context.commit('JIAX',value)
},
djiax(context, value) {
setTimeout(() => {
context.commit('JIAX',value)
}, 1000);
}
},
// 更改state的方法
mutations: {
// 第一个参数就是state
JIAX(state,value) {
state.sum+=value
},
JIANX(state,value) {
state.sum-=value
},
},
}
③index.js导入模块并注册
import { createStore } from 'vuex'
import count from './count'
import coushude from './coushude'
export default createStore({
// 分包
modules: {
count,
coushude
}
})
④组件的使用,导入特定模块的属性和方法
methods: {
...mapMutations("count", { jia: "JIAX", jian: "JIANX" }),
...mapActions("count", { ji: "jix", djia: "djiax" }),
},
computed: {
...mapState("count", ["sum", "ys", "bh"]),
...mapGetters("count", ["bigsum"]),
},
一个路由就是一组key-value映射关系,key为路径,value可能是组件或者函数
spi就是一个单页面应用
vue-router是一个vue插件
和vuex类似
1.安装
npm i vue-router
2.创建router
src/router/index.js
在此处写router信息
然后引入组件,编写路径
import { createRouter,createWebHistory } from "vue-router";
import AboutV from '../components/AboutV.vue'
import HomeV from '../components/HomeV.vue'
export default createRouter({
history: createWebHistory(),
routes: [
{
path: '/about',
component:AboutV
},
{
path: '/home',
component:HomeV
},
],
})
3.router引入
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
createApp(App).use(router).mount('#app')
4.使用
<template>
<div>
<p>
<router-link to="/about">about</router-link>
<router-link to="/home">home</router-link>
</p>
<router-view></router-view>
</div>
</template>
注意:
①如果要让路由组件和静态组件区分开,可以建立一个和components同级的pages文件夹,来放路由组件
②隐藏的的路由页面实际是被销毁了的,可以用beforedestroy钩子测试,需要的时候再挂载
③每个组件都有一个 r o u t e , 储存着自己的路由信息,整个应用只有一个 route,储存着自己的路由信息,整个应用只有一个 route,储存着自己的路由信息,整个应用只有一个router属性
1.引入组件,编写路由
把路由写在children数组里,
注意:一级路由path要带/,子级不用带
import { createRouter,createWebHistory } from "vue-router";
import AboutV from '../pages/AboutV.vue'
import HomeV from '../pages/HomeV.vue'
import OneV from '../pages/OneV.vue'
import TwoV from '../pages/TwoV.vue'
export default createRouter({
history: createWebHistory(),
routes: [
{
path: '/about',
component:AboutV
},
{
path: '/home',
component: HomeV,
children: [
{
path: 'one',
component:OneV
},
{
path: 'two',
component:TwoV
}
]
},
],
})
2.使用
和一级路由类似,不同点在于to后的路径要一二级路由都写
<template>
<div>
<h2>这是home组件</h2>
<router-link to="/home/one">one</router-link>
<router-link to="/home/two">two</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "HomeV",
};
</script>
可以简化跳转操作
1.命名
2.简化跳转,可以直接在to后边写名字完成跳转,不用写一长串路径
1.配置占位符
2.传递参数
如果用对象写法,必须用name,不能用path
3.接收参数
有三种写法,如下
接受的话和以前的props一样,正常接收即可
push的话是留下每一次点击的痕迹,即便是12121212121重复切换,回退也是重复切换着回去
replace则是替换掉同级路由的痕迹,直接回上一层
不借助router-link的路由方式
主要api有push,replace,foward,back,go(括号内参数代表动几下)
正常情况下,切换其他组件后,该组件就会被销毁
而使用缓存,在展示组件的router-view处内侧放置keepalive标签,就能实现组件缓存不销毁
include作用是指定缓存的组件,只有指定的才会缓存,其他的不会
指定的名字用组件名
如下是vue3的方式,和vue2不一样
<router-view v-slot="{ Component }">
<keep-alive include="TwoV">
<component :is="Component" />
</keep-alive>
</router-view>
activated激活前
deactivated失活前
用来限制路由通过的方式
有全局守卫,独享守卫,组件内守卫三种
1.全局前置守卫-在跳转之前调用
from:从那来
to:到哪去
next():执行跳转动作
没有next()或者next(false)代表拒绝跳转
import { createRouter,createWebHistory } from "vue-router";
import AboutV from '../pages/AboutV.vue'
import HomeV from '../pages/HomeV.vue'
import OneV from '../pages/OneV.vue'
import TwoV from '../pages/TwoV.vue'
const router=createRouter({
history: createWebHistory(),
routes: [
{
path: '/about',
component:AboutV
},
{
path: '/home',
component: HomeV,
children: [
{
path: 'one',
component:OneV
},
{
path: 'two',
component:TwoV
}
]
},
],
})
router.beforeEach((to,from,next) => {
if (to.fullPath=='/home/two'||to.fullPath=='/home') {
next()
} else {
alert('丑拒')
}
})
export default router
用其他信息做条件判断过于复杂,可以给它配置meta中的属性,然后来判断,这里只是个简单例子
比如可以用来做鉴权,也就是只有有这个属性的路由才会进行条件判断
2.全局后置守卫-在跳转之前调用
马后炮,可用于修改页面标题等
router.afterEach((to,from) => {
document.title=to.meta.title
})
配置在具体路由中
当要跳转该路由时触发
注意:
①是beforeEnter,不是beforeEach
②独享是没有后置的,但是可以搭配全局后置使用
{
path: 'two',
component: TwoV,
meta: {
isauth:true
},
beforeEnter:(to,from,next)=> {
console.log(to);
next()
}
}
写在组件内,和mounted,methods等同级
注意名字,这俩不是前置和后置
而是进入组件前和出了组件后
现在一般用history模式
history模式的404问题要在后端解决,可以通过npm的一个插件connect…或者nginx解决
1.vue项目打包
使用npm run build打包成dist文件
2.搭建服务器
这里搭建的是简单服务器
const express = require("express")
var history = require('connect-history-api-fallback');
const app = express()
app.use(history())
app.use((request,response,next) => {
console.log("有人请求1了");
next()
})
app.use(express.static(__dirname+'/static'))
app.get('/students', (request,response) => {
const students = ["这是数据"]
response.send(students)
})
app.listen(5005, (err) => {
if(!err) console.log("启动成功");
})
按需选择ui组件
一般不全部引入,太大,按照教程进行部分引入即可
有vecli和vite两种方式
更多还是用vuecli
vue3组件模板中可以没有根标签,也就是说一个template中可以放很多标签
compositionAPI翻译过来就是组合式api
原来学到过一个ref属性,用来打标签获取dom元素
这里的ref是一个函数,用于定义响应式数据
生成的对象称为引用实例对象
1.props
就是外部传递的数据,props参数就是该组件接收到的props数据,如果传了没接收,props就是空对象
<script>
import { reactive } from "vue";
export default {
name: "VueT",
props: ["msg", "smg"],
setup(props) {
console.log("我先");
console.log(props);
const data = reactive({
a: 1,
b: 2,
ahh: {
c: 3,
d: 4,
},
});
function change() {
data.ahh.c = 999;
console.log(data);
}
return {
data,
change,
};
},
beforeCreate() {
console.log("wodier");
},
};
</script>
2.context
注意:在vue3中,传递自定义事件时,要用emits接收才能用,和props类似
和vue2基本一致,
不过vue3用什么就得导入什么
<template>
<div>
<input type="text" v-model="data.xing" />
<input type="text" v-model="data.ming" />
<h2>{{ data.fullname }}</h2>
<input type="text" v-model="data.fullname" />
</div>
</template>
<script>
import { reactive, computed } from "vue";
export default {
name: "VueT",
props: ["msg"],
setup() {
const data = reactive({
xing: "张",
ming: "三",
});
// 简单写法
// data.fullname = computed(() => {
// return data.xing + "-" + data.ming;
// });
// 完整写法
data.fullname = computed({
get() {
return data.xing + "-" + data.ming;
},
set(value) {
const na = value.split("-");
data.xing = na[0];
data.ming = na[1];
},
});
return {
data,
};
},
};
</script>
注意:
①watch监视的是变量而不是具体的值,比如a=ref(0),监视的是a变量而不是a.value具体的值0
分多种情况
1.监视ref定义的响应式数据
<script>
import { ref, reactive, watch } from "vue";
export default {
name: "WatchV",
setup() {
let a = ref("奥托");
let b = ref(500);
const data = reactive({
c: 8,
d: 9,
e: {
f: {
g: 10,
},
},
});
watch(a, (newvalue, oldvalue) => {
console.log("a发生了变化", newvalue, oldvalue);
});
return {
a,
b,
data,
};
},
};
</script>
2.监视ref定义的多个响应式数据
采用数组包裹的方式
<script>
import { ref, reactive, watch } from "vue";
export default {
name: "WatchV",
setup() {
let a = ref("奥托");
let b = ref(500);
const data = reactive({
c: 8,
d: 9,
e: {
f: {
g: 10,
},
},
});
watch([a, b], (newvalue, oldvalue) => {
console.log("a发生了变化", newvalue, oldvalue);
});
return {
a,
b,
data,
};
},
};
</script>
3.监视reactive定义的响应式数据
有两个注意点
①无法正确获取oldvalue,获取到的oldvalue和newvalue一样
②deep:true,即深度监视强制开启,关不掉
<script>
import { ref, reactive, watch } from "vue";
export default {
name: "WatchV",
setup() {
let a = ref("奥托");
let b = ref(500);
const data = reactive({
c: 8,
d: 9,
e: {
f: {
g: 10,
},
},
});
watch(data, (newvalue, oldvalue) => {
console.log("a发生了变化", newvalue, oldvalue);
},
{ immediate: true, deep: false });//false无效
return {
a,
b,
data,
};
},
};
</script>
4.监视reactive定义的响应式数据的一个属性
①要用箭头函数返回值输出属性才能用,不能直接data.c
②多个属性的话用数组包裹多个箭头函数即可
③属性的话可以正确监视到oldvalue
④如果属性是一个对象,要想监视则要手动开启深度监视
<script>
import { ref, reactive, watch } from "vue";
export default {
name: "WatchV",
setup() {
let a = ref("奥托");
let b = ref(500);
const data = reactive({
c: 8,
d: 9,
e: {
f: {
g: 10,
},
},
});
watch(
() => data.c,
(newvalue, oldvalue) => {
console.log("a发生了变化", newvalue, oldvalue);
}
);
return {
a,
b,
data,
};
},
};
</script>
①和vue2大致一样,不同的在于最后两个不是destory而是mounted
②有两种写法,一种是和vue2一样的配置项写法,一种是放在组合式api里,
③在setup里要注意名字,下图右面那样写,记得要import
④create那俩无法写在setup里,setup功能就直接代表他俩了
⑤如果要在里面写逻辑,就用setup
类似于mixin,封装一系列组合api,实现复用,谁用谁引
创建hooks文件夹,和components同级,里面放自己的js文件,默认暴露一个函数,函数内是各种数据,函数,钩子
哪个组件用哪个就引入并接受
把对象中的属性单独拆解出来,且为ref对象,并能够实现响应式,c变了,data里的c也会变
把一个响应式数据变成只读数据
shallow那个只变第一层,如果是个深层对象结构,那么就会第一层只读,深层还是响应式
toraw可以理解为reactive的逆过程
markrow适用于添加属性时用,
比如一个响应式数据要添加一个对象属性,正常添加后,该属性也会变成响应式,然而不想它变成响应式,那就先做markrow操作再添加
用于自定义ref
ref相当于精装修房
customref相当于毛坯房,要自定义一些东西,也可以自定义一些特别的效果,比如下面的实现防抖
同一个功能放在同一个就是、模块,更清晰
移动位置那里可以写html,body,可以写#xxx,到对应id处
vue3用什么就得import什么才能用
如
import { reactive } from "vue";
1.数据和方法
<script>
import { reactive } from "vue";
export default {
name: "VueT",
setup() {
const data = reactive({
a: 1,
b: 2,
ahh: {
c: 3,
d: 4,
},
});
function change() {
console.log(data.a);
}
return {
data,
change,
};
},
};
</script>