vue2:选项式开发模式 vue3:组合式开发模式和选项式开发模式
利用vite创建vue3项目
npm create vite@latest
这是我的选项:
1.响应式数据
ref:定义基本类型响应式数据
ref和reactive均可定义对象类型的响应式数据
ref:
reactive:
vue2使用的是object.defineproperty实现响应式,vue3则是proxy实现响应式
2.computed
3.watch(需要明确指出监视的数据)
作用:监视数据的变化
只能监听以下四种数据:
①ref定义的数据
ref定义的基本类型的数据
ref定义的对象类型的数据:监视的是对象的地址值,若想监听对象内部属性的变化,需要手动开启深度监视(deep:true)
②reactive定义的对象类型数据:默认开启深度监视,无法关闭
③函数返回一个值(getter函数)
④一个包含上述内容的数组
4.watchEffect(不用明确指出监视的数据,响应式地追踪其依赖)
5.标签的ref属性
对于html标签:取dom元素
对于组件:取组件实例对象
6.props的使用(传值)
defineProps
7.生命周期(组件一生)[生命周期,生命周期函数,生命周期钩子]
组件的生命周期:特定的时刻调用特定的函数
vue2:4个阶段,8个钩子:
创建(创建前beforeCreate(),创建完毕created())
挂载(挂载前beforeMount(),挂在完毕mounted())
更新(更新前beforeUpdate(),更新完毕updated())
销毁(销毁前beforeDestroy(),销毁完毕Destroyed())
vue3:4个阶段,7个钩子:
创建(setup)
挂载(挂载前onBeforeMount(()=>{}),挂在完毕onMounted(()=>{}))
更新(更新前onBeforeUpdate(()=>{}),更新完毕onUpdated(()=>{}))
卸载(卸载前onBeforeUnmount(()=>{}),销毁完毕onUnmount(()=>{})
8.axios(涉及promise和ajax知识补充)
API:API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。——百度百科
补充:XML(可扩展标记语言,存储和传输数据,现被json取代)而 HTML是呈现数据.
Ajax全称:Asynchronous JavaScript and XML(异步的JavaScript和XML)
Ajax特点:在网页不刷新的情况下,向服务端发起http请求,然后得到http响应.(登陆页面不刷新显示账号情况,百度搜索某内容会出现对应相关内容,商品二级目录交互显示一级目录等)
http:超文本传输协议(英文:Hyper Text Transfer Protocol)
请求报文:从客户端发往服务器的报文。
响应报文:服务器收到请求报文后,作为响应发往客户端的报文文。
注:CR:回车 LF:换行
请求报文举;例格式:
http://www/xyz.edu.cn/dir/index.htm
GET /dir/index.htm HTTP/1.1
HOST:www/xyz.edu.cn //给出主机域名
Connection:close //告诉服务器发送完请求文档就可以释放连接
User=Agent:Mozilla/5.0 //表示用户代理使用的是火狐浏览器firefox
Accept-Language:cn //表示用户希望优先得到的是中文版本的文档
响应报文中:
#头部举例
HTTP/1.1 202 Accpted
HTTP/1.1 400 Bad Request
HTTP/1.1 404 Not Found
#常见头部(headers)
HTTP报文之"请求报文"和"响应报文"详解_请求报文是什么意思-CSDN博客
(空行)
#体(响应体)
<html>
<body>
<h1>Hello, World</h1>
</body>
</html>
网页中查看报文:
express框架:(学习Ajax)
#安装工具包 npm install -g nodemon
引入xmlhttprequest: XMLHttpRequest 详解_xmlrequest-CSDN博客
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#result{
width: 200px;
height: 100px;
border: solid 1px blue;
}
</style>
</head>
<body>
<button>点击发送请求</button>
<div id="result" ></div>
</body>
<script>
const btn=document.getElementsByTagName('button')[0];
const result=document.getElementById('result')
btn.onclick=function (){
const xhr=new XMLHttpRequest();
xhr.open('GET','http://127.0.0.1:8000/server');
xhr.send(),
//xhr.setRequestHeader()请求头内容
xhr.onreadystatechange=function(){
//0未初始化 1open方法调用完毕 2send方法调用完毕
//3服务端返回部分接口 4服务端返回所有接口
if(xhr.readyState===4){
if(xhr.status>=200&&xhr.status<300){
// console.log(xhr.status);//状态码
// console.log(xhr.statusText);//状态码文本
// console.log(xhr.getAllResponseHeaders)//响应头
// console.log(xhr.response)//响应体
result.innerHTML=xhr.response
}
}
}
}
</script>
</html>
const express = require('express')
const app = express();
app.all('/server',(request,response)=>{
response.setHeader('Access-Control-Allow-Origin','*')
response.send('this body')
});//all->get,post,option
app.listen(8000,()=>{
console.log("suceess8000,watching")
})
在ajax中传递参数:
利用post传递参数:
至此也说明了为什么get method没有请求体而post可能有.
服务端响应json数据:
虽然在服务器端通过 response.send(data)
发送了一个对象,但如果不设置 xhr.responseType = 'json'
,xhr.response
的值将会是一个字符串形式的响应体。
例如,如果不设置 xhr.responseType = 'json'
,得到的 xhr.response
可能类似于 '{"username":"henry"}'
这样的字符串,而不是已经解析为 JavaScript 对象的形式。这样直接使用 xhr.response.username
就会导致错误,因为此时 xhr.response
不是一个对象,没有 username
这个属性。
设置 xhr.responseType = 'json'
后,浏览器会自动将接收到的字符串形式的 JSON 数据解析为 JavaScript 对象,从而可以方便地通过 xhr.response.username
来获取属性值。
延时与网络异常处理:
取消请求:
拒绝重复请求:
Promise:
JavaScript是单线程语言,在执行任务的时候,会先执行第一个任务再执行第二个任务,假如第一个任务是个耗时的任务那么第二个任务就一直阻塞不能执行,那么这个时候就需要异步来处理这个操作;
同步:主线程上排队执行的任务,只有前一个任务执行完毕,才能继续执行下一个任务;
异步:不进入主线程,而进入任务队列的任务,只有任务队列通知主线程,某个异步任务可以执行了,该任务才会进入主线程;
①promise是一门新的技术(ES6规范),是JS中进行异步编程(fs文件操作,数据库操作,ajax,定时器)的新解决方案.
异步编程是一种编程模型,它将程序中的计算任务分成独立的阶段,并在每个阶段完成后立即返回结果。异步编程模型通常用于处理长时间运行的任务
②从语法上来说:promise是一个构造函数,从功能上来说:promise对象用来封装一个异步操作并可以获取其成功/失败的结果值.
promise支持链式调回,可以解决回调地狱问题
回调地狱:外部回调函数异步执行的结果是嵌套的回调执行的条件,那么随着异步层级的增长,代码会变得极其深陷且难以理解和维护。
回调地狱产生的 根本原因是异步操作的嵌套和回调函数的链式调用.缺点:不便于阅读,不方便异常处理.
promise之setTimeout:
<body>
<button class="btn">点击抽奖</button>
</body>
<script>
function getRnd(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min - 1
}
const btn = document.querySelector('.btn')
btn.addEventListener('click', function () {
let test = getRnd(1, 100);//0-100不包括100
// setTimeout(()=>{//回调函数的方法
// let test = getRnd(1, 100);//0-100不包括100
// if (test <= 30) {
// console.log(test)
// alert("中奖了")
// }else{
// console.log(test)
// alert("抱歉")
// }
// },1000)
// promise方法
const p = new Promise((resolve, reject) => {
setTimeout(() => {
if (test <= 30) {
resolve(test);//将promise对象的状态设置为成功
} else {
reject(test);
}
}, 1000);
});
//调用then函数
p.then((test) => {
console.log(test);
alert("中奖了");
}, (test) => {
console.log(test)
alert("抱歉")
})
})
</script>
promise的属性:
接上面的例子我们了解一下promise的属性:
promise实例对象的一个属性promisestate(状态):三种状态即为中奖(成功)的fulfilled/resolved(成功),rejected(失败),以及pending(没有决定的),无论成功或者失败都只有一种结果数据,成功数据一般为value,失败数据一般为reason.
除了resolve和reject还有throw也可以更改状态:
promise实例对象的一个属性promiseresult(结果):保存实例对象成功和失败的值,可以使用resolve和reject进行修改
promise之fs:
const fs = require('fs')
// fs.readFile('11.txt',(err,data)=>{
// if(err) throw err;
// console.log(data.toString())
// })
let p = new Promise((resolve, reject) => {
fs.readFile('11.tx', (err, data) => {
if (err) reject(err);
resolve(data);
});
});
//构造函数then
p.then(data=>{
console.log(data.toString())
},err=>{
console.log(err)
})
封装
function testFile(path){
return new Promise((resolve, reject) => {
require('fs').readFile(path,(err,data)=>{
if(err) reject(err);
resolve(data);
})
})
}
testFile('11.txt').then(data=>{
console.log(data.toString())
},err=>{
console.log(err)
})
promise之ajax:
<script>
function testajax(url){
return new Promise((resolve, reject) => {
const xhr= new XMLHttpRequest()
xhr.open('GET',url);
xhr.send();
xhr.onreadystatechange=function(){
if(xhr.readyState===4){
if(xhr.status>=200&&xhr.status<300){
resolve(xhr.response)
}else{
reject(xhr.status)
}
}
}
})
}
testajax('http://127.0.0.1:8000/json-srver')//之前express中的ajax
.then(value=>{
console.log(value)
},reason=>{
console.warn(reason)
})
</script>
promise函数的方法
promise.resolve
promise.reject
promise.all ->包含n个promise对象的数组
promise对象有一个失败贼为失败:
promise.race
第一个promise状态结果就为最终的结果:
promise串联多个任务:
promise异常穿透:
只需要一次抛出错误即可
中断穿透链的方法:
async和await:
async:
①
②
③
await:
await必须写在async函数中,但是async函数中可以没有await
结合async,await
回到之前提到的回调地狱
//回调地狱
// const fs = require('fs');
// fs.readFile('1.txt', (err, data1) => {
// if (err) throw err
// fs.readFile('2.txt', (err, data2) => {
// if (err) throw err
// fs.readFile('3.txt', (err, data3) => {
// if (err) throw err
// console.log(data1+data2+data3)
// })
// })
// })
//使用async和await
const fs = require('fs');
const util=require('util')
const mineReadFile=util.promisify(fs.readFile)
async function main() {
try{
let data1=await mineReadFile('1.txt')
let data2=await mineReadFile('2.txt')
let data3=await mineReadFile('3.txt')
console.log(data1+data2+data3)
}catch(e){
console.log(e);
}
}
main()
Axios:
axios有很多特性,方便了很多.
搭建json-server
GitHub - typicode/json-server: Get a full fake REST API with zero coding in less than 30 seconds (seriously)https://github.com/typicode/json-server
axios配置
GitHub - axios/axios: Promise based HTTP client for the browser and node.jsPromise based HTTP client for the browser and node.js - axios/axioshttps://github.com/axios/axios
axios:get:
axios:post:
axios:put:
axios:delete:
<template>
<button @click="clickGet" >发送 get</button>
<button @click="clickPost" >发送 Post</button>
<button @click="clickPut" >发送 put</button>
<button @click="clickDelete" >发送 delete</button>
</template>
<script setup lang="ts">
import axios from 'axios';
axios.defaults.baseURL='http://localhost:3000'
const clickGet = () => {
axios.request({
method: 'GET',
url: '/posts/2'
}).then(response => {
console.log(response);
});
};
const clickPost = () => {
axios({
method: 'POST',
url: '/posts',
//设置请求体
data:{
"id":2,
"title": "add",
"views": 300
}
}).then(response => {
console.log(response);
});
};
const clickPut = () => {
axios({
method: 'PUt',
url: '/posts/2',
//设置请求体
data:{
"id":2,
"title": "add",
"views": 300
}
}).then(response => {
console.log(response);
});
};
const clickDelete = () => {
axios({
method: 'delete',
url: '/posts/2',
}).then(response => {
console.log(response);
});
};
</script>
axios.methods
axios.request()
const clickGet = () => {
axios.request({
method: 'GET',
url: 'http://localhost:3000/posts/1'
}).then(response => {
console.log(response);
});
};
axios.post()
const clickPost = () => {
axios.post(
'http://localhost:3000/comments',
//设置请求体
{
"text": "more comments about post 1",
"postId": "1"
}).then(response => {
console.log(response);
});
};
创建axios实例对象(重点)
import axios from 'axios';
const clickGet = () => {
let request=axios.create({
baseURL:'http://localhost:3000',
timeout:3000
})
request.get('/posts').then(response=>{
console.log(response)
})
}
拦截器 :
请求拦截器(Request Interceptor)的作用:
请求拦截器允许在发送请求之前对请求进行处理和修改。
- 可以添加统一的请求头,例如添加身份验证信息、设置
Content-Type
等。例如,如果您的应用需要在每个请求中都携带一个特定的token
用于身份验证,就可以在请求拦截器中添加。 - 可以对请求参数进行预处理,比如格式化、加密等操作。
- 可以在发送请求前进行日志记录,方便后续的调试和跟踪。
响应拦截器(Response Interceptor)的作用:
响应拦截器让在接收到服务器的响应后能够对其进行处理。
- 可以统一处理错误状态。例如,当服务器返回特定的错误码时,进行统一的错误提示或跳转处理。
- 对响应数据进行解析和转换。例如,如果服务器返回的数据格式不统一,在响应拦截器中进行格式转换,以方便后续使用。
- 进行缓存处理,根据响应结果决定是否将数据缓存起来,以提高后续相同请求的响应速度。
<script setup lang="ts">
import axios from 'axios';
let test=axios.create({
baseURL:'http://localhost:3000',
timeout:3000
})
test.interceptors.request.use(function(config){
console.log('reques interceptors')
// return config;
throw 'wrong'
}
),
test.interceptors.response.use(function(response){
console.log('response interceptors')
return response;
},function(error){
console.log('response interceptors err')
return Promise.reject(error)
})
test({
method:'GET',
url:'http://localhost:3000/posts'
}).then(response=>{
console.log(response)
},reason=>{
console.log('失败')
})
</script>
取消axios请求:
9.hooks(封装)
10.路由
(安装路由器->npm i vue-router)
路径->组件
路由组件:靠路由的规则渲染出来的(pages/views)
一般组件:需要亲手写标签(components)
路由的三种to跳转写法:
路由嵌套:
const router=createRouter({
history:createWebHistory (),
routes:[
{
path:'/menu2',
name:'menu2',
component:Menu2,
children:[{
path:'/menu2-1',
component:Menu21
}]
}
路由query参数(通过地址传参)
<RouterLink
:to="{
path:' ',
query:{
}
}"
>
</RouterLink>
路由params参数(传递params
参数时,需要提前在规则中占位。 )
<RouterLink
:to="{
name:' ',
params:{
}
}"
>
</RouterLink>
11.组件通信方式
①Props:只读的(组件中间传递只读的数据)
vue3中对应父子组件传递数据,需要使用defineProps方法去接受父组件传递过来的数据,不需要引入直接使用.
defineProps();
②自定义事件
-
原生事件:
-
事件名是特定的(
click
、mosueenter
等等) -
事件对象
$event
: 是包含事件相关信息的对象(pageX
、pageY
、target
、keyCode
)
-
-
自定义事件:
-
事件名是任意名称
-
事件对象
$event
: 是调用emit
时所提供的数据,可以是任意类型!!!
-
vue3中利用defineEmits方法返回函数触发自定义事件,不需要引入直接使用.
③全局事件总线(mitt)
// 绑定事件
<template>
<div class="box1">
<h3>{{gnum}}</h3>
</div>
</template>
<script setup lang='ts'>
import tnum from '@/bus';
import { ref } from 'vue';
let gnum =ref('');
tnum.on('tnum',(value:any)=>{
gnum.value=value;
})
</script>
<style scpoed lang='scss'>
.box1{
@extend %box;
background-color: rgb(168, 36, 177);
}
</style>
// 触发事件
<template>
<div class="box2">
<button @click="tnum.emit('tnum',n)">传输数字</button>
<h3>{{ n }}</h3>
</div>
</template>
<script setup lang='ts'>
import tnum from '@/bus';
import { ref } from 'vue';
let n=ref(234);
</script>
<style scpoed lang='scss'>
.box2{
@extend %box;
background-color: aquamarine;
}
</style>
④v-model
原理:
1.v-bind绑定value属性的值。
2.v-on绑定input事件监听到函数中,函数会获取最新的值赋值到绑定的属性中。
<!-- v-model用在<html>标签上 -->
<input type="text" v-model="username">
<!-- 对v-model进行更冗长的等价展开 -->
<!-- <input type="text" :value=”username” @input="username=( <HTMLInputElement>$event.target).value”-->
<!-- v-model用在组件标签上 -->
<Home v-model="username"/>
<!-- 对v-model进行更冗长的等价展开 -->
<!-- <input type="text" :modelvalue=”username” @update="modelvalue="username=$event"-->
在Home组件中:
<template>
<div class="box">
<!--将接收的value值赋给input元素的value属性,目的是:为了呈现数据 -->
<!--给input元素绑定原生input事件,触发input事件时,进而触发update:model-value事件-->
<input
type="text"
:value="modelValue"
@input="emit('update:model-value',$event.target.value)"
>
</div>
</template><script setup lang="ts" name="AtguiguInput">
// 接收props
defineProps(['modelValue'])
// 声明事件
const emit = defineEmits(['update:model-value'])
</script>
对于原生事件
,$event就是事件对象(能.target)
对于自定义事件
,$event就是触发事件时,所传递的数据(不能.target)
⑤useAtrrts方法(获取组件的属性与事件)
useAtrrts方法可以获取组件的属性与事件.
⑥ref和$parent(父子间实现互相传递应用)
-
$refs
用于 :父→子。 -
$parent
用于:子→父。
$refs | 值为对象,包含所有被ref 属性标识的DOM 元素或组件实例。 |
$parent | 值为对象,当前组件的父组件实例对象。 |
组件内部数据对外关闭的,别人不能访问
如果想要外部访问需要通过deFineExpose方法对外暴露
⑦provide和inject(隔辈传递数据)
12.pinia(任意组件通信)->项目存储数据
Pinia是vue生态里Vuex的替代者,一个全新的vue状态管理库。在Vue3成为正式版以后,尤雨溪强势推荐的项目就是Pinia。
核心概念:state.actions.getters
pinia组合式写法:选择器API.组合式API
持久存储: 快速开始 | pinia-plugin-persistedstate (prazdevs.github.io)
选择器API
大仓库配置(./store/index.ts)
//创建大仓库
通过createPinia( )方法,得到pinia的实例,然后将Pinia挂载到Vue根实例上。
import { createPinia } from "pinia";
const store = createPinia();
export default store;
小仓库配置:(./modouls/info)
//定义小仓库
import { defineStore } from "pinia";
//defineStore方法会执行返回第一个函数,函数作用就是可以让组件可以获取到仓库数据
//第一个参数:小仓库名字 第二个参数:小仓库配置对象
const useinfostore=defineStore("info",{
//数据
state:() =>{
return{
}
},
//方法
actions:{
},
//计算
getters:{
}
})
export default useinfostore;
获取小仓库数据:
<template>
<h3>box2:{{ infoStore.num }}</h3>
</template>
<script setup lang='ts'>
import useinfostore from '@/store/modules/info';
let infoStore=useinfostore();
</script>
<style scpoed lang='scss'>
</style>
组合式API
import { defineStore } from "pinia";
import { ref } from "vue";
const usetodoStore=defineStore('todo',()=>{
//要返回一个对象:属性与方法可以提供给组件使用
const num=ref(999);
return{
num,
updateto(){
this.num.value+=1;
},
}
});
export default usetodoStore;
<template>
<h3>box1:{{ todoStore.num }}</h3>
<button @click="updatetodo">小仓库数据+1</button>
</template>
<script setup lang='ts'>
import usetodostore from '@/store/modules/todo';
let todoStore=usetodostore();
const updatetodo=()=>{
todoStore.updateto();
}
</script>
<style scpoed lang='scss'>
</style>
13.插槽
①默认插槽
子组件:
<template>
<h1>插槽前内容</h1>
<!-- 默认插槽 -->
<slot></slot>
<h1>插槽后内容</h1>
</template>
<script setup lang='ts'>
</script>
<style scpoed lang='scss'>
</style>
父组件:
<template>
<sBox>
<pre>这是插槽内容</pre>
</sBox>
</template>
<script setup lang='ts'>
import sBox from './sBox.vue';
</script>
<style scpoed lang='scss'>
</style>
②具名插槽
子组件:
<template>
<h1>插槽(a)前内容</h1>
<!-- 具名插槽 -->
<slot name="a"></slot>
<h1>插槽(a)后内容</h1>
</template>
父组件:
<template>
<sBox>
<template v-slot:a>
<pre>这是插槽a内容</pre>
</template>
</sBox>
</template>
③作用域插槽
作用域插槽:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
父组件:
<template>
<sBox v-slot="params">
<ul>
<li v-for="c in params.content" :key="c.id">{{ c.name }}</li>
</ul>
</sBox>
</template>
子组件:
<template>
<h1>插槽前内容</h1>
<!-- 作用域插槽 -->
<slot :content="content"></slot>
<h1>插槽后内容</h1>
</template>
<script setup lang='ts'>
import {reactive} from 'vue'
let content = reactive([
{id:'01',name:'内容1'},
{id:'02',name:'内容2'},
{id:'03',name:'内容3'},
{id:'04',name:'内容4'}
])
</script>