VUE3学习笔记
文章目录
- VUE3学习笔记
- 1.工具准备
- 2.项目目录
- 3.模版语法
- 4.条件渲染
- 5.条件渲染
- 6.事件处理
- 7.表单输入绑定
- 8.组件基础
- 9.Props组件交互
- 10.自定义事件组件交互
- 11.组件生命周期
- 12.引入第三方组件
- 13.axios网络请求
- 14.axios网络请求封装
- 15.请求跨域
- 16.路由
- 17.路由传参
- 18.路由嵌套
- 19.axios网络请求
- 20.axios网络请求封装
- 21.请求跨域
- 22.路由
- 23.路由传参
- 24.路由嵌套
- 25.setup
- 26.ref,reactive
- 27.生命周期
- 28.Teleport
- 29.provide / inject
- 30.侦听器
- 31.computed 计算属性
- 32.readonly 和 shallowReadonly
1.工具准备
HBuilderX 3.2.8
2.项目目录
src中有四个目录文件:
1.第一个assets,存放的是项目的静态资源,例如图片
2.componets,存放的是相关的显示组件
3.App.vue,应用开发的主app页面
4.main.js,app的配置页面
一个VUE界面主要包含三个部分:template,script,style。其中,template用来写代码,script用来写脚本,style用来写CSS样式
3.模版语法
template:
<span>message:{{msg}} </span>
script:
export default {
data(){
return{
msg:"消息内容传送"
}
}
}
将字符串放进data函数的return中进行返回标记使用。
原始Html支持:
template:
<span v-html="rawHtml">百战</span>
script:
export default {
data(){
return{
rawHtml:"<a href=' '>百战</a >"
}
}
}
4.条件渲染
template:
<span v-if="flag">1</span>
<span v-else>2</span>
script:
export default {
data(){
return{
flag:true
}
}
}
通过flag的判断控制字符的显示,除此之外,还可以使用v-if,v-else if,v-else结合div嵌套多个span等块选择性显示你想显示的内容
template:
<span v-show="flag">1</span>
script:
export default {
data(){
return{
flag:true
}
}
}
v-show只有两种状态,要么显示,要么不显示。
5.条件渲染
template:
<ul>
<il v-for="item in items">{{item.msg}}</il>
</ul>
script:
export default {
data(){
return{
items:[{msg:"01"},{msg:"02"}]
}
}
}
数据中存在列表,使用v-for语法进行循环,每一组的属性attr,使用单项.attr进行显示。
维护显示
template:
<ul>
<il v-for="(item,index) in items" :key="item.id|index">{{item.msg}}</il>
</ul>
script:
export default {
data(){
return{
items:[{msg:"01"},{msg:"02"}]
}
}
}
通常每个数据传过来是有ID的,使用ID处理即可,减少渲染时间。
这里面涉及到了属性绑定,:key
属性绑定,意思就是将标签的属性进行绑定,原名称为v-bind:,为了简化,可以写成一个冒号:,主要是将脚本的数据与标签中数据进行绑定显示。
6.事件处理
template:
<button @click="greet">Greet</button>
script:
export default {
methods:{
greet(event){
if(event){
alert(event.target.tagNane)
}
}
}
}
事件传递参数
template:
<button @click="sya{'so'}">{{msg}}</button>
script:
export default {
data(){
return{
msg=""
}
},
methods:{
say(msg){
this.msg = msg
}
}
}
7.表单输入绑定
可以在input,textarea,select等进行双向数据绑定
template:
<input type="text" v-model="msg"/>
<p>msg is {{msg}}</p >
script:
export default {
data(){
return{
msg=""
}
}
}
这种是实时进行跟踪的
.lazy属性
改变在
template:
<input type="text" v-model.lazy="msg"/>
<p>msg is {{msg}}</p >
.trim属性
改变在
template:
<input type="text" v-model.trim="msg"/>
<p>msg is {{msg}}</p >
8.组件基础
1.单文件组件(以建立myComponents.vue文件为例),并建立在项目名/src/components目录下
文件初始内容为下
<template>
</template>
<script>
export default {
name:myComponents,
}
</script>
<style scoped>
</style>
scoped属性的加入是为了style只在本页面生效,如果不加,其它页面也会受到影响。
2.引入
在根组件App.vue中引入组件,在App.vue的script中
<script>
import myComponents from "./components/myComponents.vue"
export default {
}
</script>
3.挂载组件
在App.vue的script中
<script>
import myComponents from "./components/myComponents.vue"
export default {
name:'App',
components:{
myComponents
}
}
</script>
4.引用组件
在App.vue的template中
<template>
<myComponents />
</template>
当然,可以组件套组件,形成组件的组织。
9.Props组件交互
App.vue
<template>
<myComponents :title="title" :age="age" :names="names"/>
</template>
<script>
import myComponents from "./components/myComponents.vue"
export default {
name:'App',
data(){
return{
title:"Test",
age:20,
names:["ime","frank","smith"]
}
},
components:{
myComponents
}
}
</script>
<style scoped>
</style>
myComponents.vue
<template>
<span>{{title}}</span>
<span>{{age}}</span>
<ul>
<il v-for="(items,index) in names" :key="index">{{item}}</il>
</ul>
</template>
<script>
export default {
name:myComponents,
Props:{
title:{
type:String,
default:""
},
age:{
type:Number,
default:""
},
names:{
type:Array,
default:function(){
return []
}
}
}
}
</script>
<style scoped>
</style>
Props接收的数据类型:
String,Number,Boolean,Array,Object,Function
其中,在传递数组或者对象时,需要返回工厂模式(函数形式)。
简单梳理一下props的用法:首先,他是从父组件向子组件进行数据传递,在引入组件的基础上,将所要传递的数据放进template的组件标签中,在组件标签中,在script中加入props,在其中添加要接受的数据名称,接收数据的类型以及默认接收值即可,之后便可以在子组件页面引用传递的值了。
10.自定义事件组件交互
myComponents.vue
<template>
<button @click="sendClickHandle">点击发送</button>
</template>
<script>
export default {
name:myComponents,
data(){
return{
message:"Test"
}
},
methods:{
sendClickHandle(){
this.$emit("onEvent",this.message)
}
}
}
</script>
<style scoped>
</style>
App.vue
<template>
<myComponents @onEvent="getDataHandle"/>
<span>{{msg}}</span>
</template>
<script>
import myComponents from "./components/myComponents.vue"
export default {
name:'App',
components:{
myComponents
},
data(){
return {
msg:""
}
}
methods:{
getDataHandle(data){
this.msg=data
}
}
}
</script>
<style scoped>
</style>
简述:在子组件中,使用函数出发$emit(eventName,data)去传递数据,在父组件的子组件标签中,使用所使用的方法获取子组件的事件名eventName,并传递给父组件一个方法名parentEventName,在父组件的脚本中,使用方法去获取到这个数据,就可以使用了。
通过上述两个案例,我发现,子组件标签在父组件的使用中,既可以给子组件传递多个数据,也可以给父组件使用自定义事件反向传递数据,十分方便。
11.组件生命周期
export default {
data(){
return {
msg:""
}
}
beforeCreate(){
},
created(){
},
beforeMount(){
},
mounted(){
用到最多的地方,比如网络请求加载
},
beforeUpdate(){
},
Updated(){
},
beforeUnmount(){
资源卸载
},
unmounted(){
},
}
一共8个生命,分为四类,即创建,渲染,更新,卸载。
12.引入第三方组件
引入第三方组件,过程与第8节组件基础的组件引入是一样的,这里不在进行详细说明,组件的使用语法详见官方文档。
13.axios网络请求
1.安装
打开项目终端机输入:
npm install --save axios
2.引入
组件引入:
全剧引入:
main.js文件:
import axios from "axios"
const app = createApp(App);
app.config.globalProperties.$axios = axios
app.mount('#app');
在组建中调用: t h i s . this. this.axios
网络请求基本示例:
'get'
axios({
method:"get",
url:"http://......."
}).then(res=>{
//进行数据处理
res.data
})
简洁方式:
'get'
axios.get("http://......."
).then(res=>{
//进行数据处理
res.data
})
'post'
axios({
method:"get",
url:"http://......."
data:{querystring.stringify({
user_id:"",
password:"",
verification_code:""
}
}).then(res=>{
//进行数据处理
res.data
})
简洁方式:
'post'
axios.post(
url:"http://.......",querystring.stringify({
user_id:"",
password:"",
verification_code:""
})).then(res=>{
//进行数据处理
res.data
})
14.axios网络请求封装
在src目录下创建utils目录,并在其下建立一个request,js的文件,内容如下:
import axios from "axios"
import quertstring from "querystring"
//使用const 声明一个自己定义的变量
const instance = axios.create({
//网络请求的公共配置
timeout:5000
})
//发送数据之前
instance.interceptors.request.use(
config=>{
if(config.method === "post"){
config.data = querystring.stringify(config.data)
}
return config;
},
error=>{return Promise.reject(error)
})
//错误信息处理
const errorHandle(status,info)=>{
switch(status){
case 400:
console.log("");
break;
case 401:
console.log("");
break;
case 403:
console.log("");
break;
case 404:
console.log("");
break;
case 500:
console.log("");
break;
case 502:
console.log("");
break;
default:
console.log("");
break;
}
}
//获取数据之前
instance.interceptors.response.use(
response => {
return response.status === 200 ? Promise.resolve(response) : Promise.reject(response)
},
error => {
const {response} = error;
errorHandle(response.status,response.info);
}
)
//最常用的拦截器
//
export default instance;
建立一个api目录,并在其下创建index.js,path.js
配置文件路径path.js:
const base = {
baseUrl:"域名地址",
pages:"/api/.....php"
}
export default base;
结合文件路径与封装的请求,在index.js写业务逻辑。
import axios from "../utils/request"
import path from "./path"
const api = {
getpagges(){
return axios.get(path.baseUrl+path.pages)
}
}
export default api;
在组建页面:
script中引用api:
//api.index 自动寻找
import api from "../api"
然后去引用API。
15.请求跨域
当协议,域名,端口任意一个不同时,都会产生跨域问题。
目前,解决跨域问题的有两个:
后台:cors
前台:proxy
在vue.config.js文件中进行配置,如下:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
//以下为添加内容
devServer:{
proxy:{
'/api':{
target:'<url>',
changeOrigin:true
}
}
}
})
16.路由
简单来说,路由就是可以管理页面之间的关系,我们使用vue-router来使用,可以很简单的实现单页应用。 是一个组件,该组件用于设置一个导航链接,切换不同 HTML 内容。 to 属性为目标地址, 即要显示的内容。
1.安装
npm install --save vue-router
2.配置独立的路由文件,建立router文件夹并在其下建立index.js文件,其中:
import {craeteRouter, createWebHashHistory} from 'vue-router'
impoert 需要引入跳转的页面
//假如存在首页index,page1,page2
//配置信息中需要页面的相关配置
const routers = [
{
path:"/",
name:"index",
component:index
},
{
path:"/page1",
nsme:"page1",
component:page1
},
{
path:"/page2",
component:page2
},
]
const router = createRouter({
history:createWebHashHistory(),
routers
})
export default router;
使用:
在main.js中进行配置
import { createApp } from 'vue'
import App from './App.vue'
import router from "./router/router"
createApp(App).use(router).mount('#app')
在App.vue开始应用
<template>
<router-link to="/">首页</router-link>
<router-link to="/page1">页面1</router-link>
<router-link to="/page2">页面2</router-link>
//. 下面代码开启路由路口,主页要写,其它页面不需要写
<router-view> </router-view>
</template>
17.路由传参
通常,在页面加载中,只有主页面被引入,其他页面采用异步加载,节省资源:
const routers = [
{
path:"/",
nsame:"index",
component:index
},
{
path:"/page1",
name:"page1",
component:()=>import("../page1.vue")
},
{
path:"/page2",
namee:"page2",
component:)=>import("../page2.vue")
},
]
如果有page1和page2需要跳转相同的页面,但是这个页面显示的内容不同,但是都是需要显示内容,则应该传递的参数不同,让它显示对应页面参数的内容。
1.首先,在路由配置中指定参数
{
path:"/page1/:name",
name:"page1",
component:()=>import("../page1.vue")
},
路径后冒号加参数
2.跳转过程引入数据
<router-link to="/page1/数据">页面1</router-link>
3.详情页面调取参数(详情显示页)
<span>{{$route.params.name}} </span>
18.路由嵌套
通常在一级菜单下有的还存在二级菜单,那么如何在一级页面创建二级菜单呢,
假设page2页面还有分类,需要跳转页面,这时候新建页面page2_1,page2_2,他们均属于page2的子页面,
在路由中添加修改:
{
path:"page2",
namee:"page2",
component:)=>import("../page2.vue")
children:[
{
//二级导航不要加斜线
path:"/page2_1",
name:"page2_1",
component:()=>import("../page2_1.vue")
},
{
path:"page2_2",
name:"page2_2",
component:()=>import("../page2_2.vue")
}
]
}
在page2页面加上子路由跳转开启转接
<template>
<router-link to="/page2/page2_1">页面1</router-link>
<router-link to="/page2/page2_2">页面2</router-link>
//. 下面代码开启路由路口,主页要写,其它页面不需要写
<router-view> </router-view>
</template>
当然页面最开始存在初始页面,如何设定在,路由中添加修改:
{
path:"page2",
namee:"page2",
component:)=>import("../page2.vue"),
//重定向默认页面
redirect:"/page2/page2_1",
children:[
{
//二级导航不要加斜线
path:"/page2_1",
name:"page2_1",
component:()=>import("../page2_1.vue")
},
{
path:"page2_2",
name:"page2_2",
component:()=>import("../page2_2.vue")
}
]
}
19.axios网络请求
1.安装
打开项目终端机输入:
npm install --save axios
2.引入
组件引入:
全剧引入:
main.js文件:
import axios from "axios"
const app = createApp(App);
app.config.globalProperties.$axios = axios
app.mount('#app');
在组建中调用: t h i s . this. this.axios
网络请求基本示例:
'get'
axios({
method:"get",
url:"http://......."
}).then(res=>{
//进行数据处理
res.data
})
简洁方式:
'get'
axios.get("http://......."
).then(res=>{
//进行数据处理
res.data
})
'post'
axios({
method:"get",
url:"http://......."
data:{querystring.stringify({
user_id:"",
password:"",
verification_code:""
}
}).then(res=>{
//进行数据处理
res.data
})
简洁方式:
'post'
axios.post(
url:"http://.......",querystring.stringify({
user_id:"",
password:"",
verification_code:""
})).then(res=>{
//进行数据处理
res.data
})
20.axios网络请求封装
在src目录下创建utils目录,并在其下建立一个request,js的文件,内容如下:
import axios from "axios"
import quertstring from "querystring"
//使用const 声明一个自己定义的变量
const instance = axios.create({
//网络请求的公共配置
timeout:5000
})
//发送数据之前
instance.interceptors.request.use(
config=>{
if(config.method === "post"){
config.data = querystring.stringify(config.data)
}
return config;
},
error=>{return Promise.reject(error)
})
//错误信息处理
const errorHandle(status,info)=>{
switch(status){
case 400:
console.log("");
break;
case 401:
console.log("");
break;
case 403:
console.log("");
break;
case 404:
console.log("");
break;
case 500:
console.log("");
break;
case 502:
console.log("");
break;
default:
console.log("");
break;
}
}
//获取数据之前
instance.interceptors.response.use(
response => {
return response.status === 200 ? Promise.resolve(response) : Promise.reject(response)
},
error => {
const {response} = error;
errorHandle(response.status,response.info);
}
)
//最常用的拦截器
//
export default instance;
建立一个api目录,并在其下创建index.js,path.js
配置文件路径path.js:
const base = {
baseUrl:"域名地址",
pages:"/api/.....php"
}
export default base;
结合文件路径与封装的请求,在index.js写业务逻辑。
import axios from "../utils/request"
import path from "./path"
const api = {
getpagges(){
return axios.get(path.baseUrl+path.pages)
}
}
export default api;
在组建页面:
script中引用api:
//api.index 自动寻找
import api from "../api"
然后去引用API。
21.请求跨域
当协议,域名,端口任意一个不同时,都会产生跨域问题。
目前,解决跨域问题的有两个:
后台:cors
前台:proxy
在vue.config.js文件中进行配置,如下:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
//以下为添加内容
devServer:{
proxy:{
'/api':{
target:'<url>',
changeOrigin:true
}
}
}
})
22.路由
简单来说,路由就是可以管理页面之间的关系,我们使用vue-router来使用,可以很简单的实现单页应用。 是一个组件,该组件用于设置一个导航链接,切换不同 HTML 内容。 to 属性为目标地址, 即要显示的内容。
1.安装
npm install --save vue-router
2.配置独立的路由文件,建立router文件夹并在其下建立index.js文件,其中:
import {craeteRouter, createWebHashHistory} from 'vue-router'
impoert 需要引入跳转的页面
//假如存在首页index,page1,page2
//配置信息中需要页面的相关配置
const routers = [
{
path:"/",
name:"index",
component:index
},
{
path:"/page1",
nsme:"page1",
component:page1
},
{
path:"/page2",
component:page2
},
]
const router = createRouter({
history:createWebHashHistory(),
routers
})
export default router;
使用:
在main.js中进行配置
import { createApp } from 'vue'
import App from './App.vue'
import router from "./router/router"
createApp(App).use(router).mount('#app')
在App.vue开始应用
<template>
<router-link to="/">首页</router-link>
<router-link to="/page1">页面1</router-link>
<router-link to="/page2">页面2</router-link>
//. 下面代码开启路由路口,主页要写,其它页面不需要写
<router-view> </router-view>
</template>
23.路由传参
通常,在页面加载中,只有主页面被引入,其他页面采用异步加载,节省资源:
const routers = [
{
path:"/",
nsame:"index",
component:index
},
{
path:"/page1",
name:"page1",
component:()=>import("../page1.vue")
},
{
path:"/page2",
namee:"page2",
component:)=>import("../page2.vue")
},
]
如果有page1和page2需要跳转相同的页面,但是这个页面显示的内容不同,但是都是需要显示内容,则应该传递的参数不同,让它显示对应页面参数的内容。
1.首先,在路由配置中指定参数
{
path:"/page1/:name",
name:"page1",
component:()=>import("../page1.vue")
},
路径后冒号加参数
2.跳转过程引入数据
<router-link to="/page1/数据">页面1</router-link>
3.详情页面调取参数(详情显示页)
<span>{{$route.params.name}} </span>
24.路由嵌套
通常在一级菜单下有的还存在二级菜单,那么如何在一级页面创建二级菜单呢,
假设page2页面还有分类,需要跳转页面,这时候新建页面page2_1,page2_2,他们均属于page2的子页面,
在路由中添加修改:
{
path:"page2",
namee:"page2",
component:)=>import("../page2.vue")
children:[
{
//二级导航不要加斜线
path:"/page2_1",
name:"page2_1",
component:()=>import("../page2_1.vue")
},
{
path:"page2_2",
name:"page2_2",
component:()=>import("../page2_2.vue")
}
]
}
在page2页面加上子路由跳转开启转接
<template>
<router-link to="/page2/page2_1">页面1</router-link>
<router-link to="/page2/page2_2">页面2</router-link>
//. 下面代码开启路由路口,主页要写,其它页面不需要写
<router-view> </router-view>
</template>
当然页面最开始存在初始页面,如何设定在,路由中添加修改:
{
path:"page2",
namee:"page2",
component:)=>import("../page2.vue"),
//重定向默认页面
redirect:"/page2/page2_1",
children:[
{
//二级导航不要加斜线
path:"/page2_1",
name:"page2_1",
component:()=>import("../page2_1.vue")
},
{
path:"page2_2",
name:"page2_2",
component:()=>import("../page2_2.vue")
}
]
}
25.setup
setup函数在beforecreated钩子函数前执行,此时setup中的this还不是组件实例,此时this是undefined.
第1个参数为props。props为一个对象,内部包含了父组件传递过来的所有prop数据
第2个参数为一个对象context。context对象包含了attrs,slots, emit属性,
如果在data()中也定义了同名的数据,则以setup()中为准。
attrs: 除了 props 中的其他属性
slots: 父组件传入插槽内容的对象
emit: 和用于父子组件通信
26.ref,reactive
ref
定义/转为 响应式
作用:定义一个响应式的数据
语法: const xxx = ref(initValue)
创建一个包含响应式数据引用对象(reference对象)
JS中操作数据:xxx.value
模板中读取数据:不需要.value,直接:
{ {xxx}}
备注:
接收的数据可以是:基本类型、也可以是对象类型
基本类型的数据:响应式依然靠的是Object.defineProperty()的get和set完成的
对象类型的数据: 内部”求助“了Vue3.0中的一个新的函数——reactive函数
reactive 函数
作用:定义一个对象类型的响应式数据(基本类型别用他,用ref函数)
语法:const 代理对象 = reactive(被代理对象)接收一个对象(或数组),返回一个代理对象(proxy对象)
reactive定义的响应式数据是”深层次的“
内部基于ES6的Proxy实现,通过代理对象操作源对象内部数据进行操作
区别
eactive对比ref
从定义数据角度对比:
ref用来定义: 基本数据类型
reactive用来定义: 对象(或数组)类型数据
备注: ref也可以用来定义对象(或数组)类型数据,它内部会自动通过reactive转为代理对象
从原理角度对比:
ref通过Object.defineProperty()的get和set来实现响应式(数据劫持)
reactive通过Proxy来实现响应式(数据劫持),并通过Reflect操作源对象内部的数据
从使用角度对比:
ref定义数据:操作数据需要 .value ,读取数据时模板中直接读取不需要 .value
reactive 定义的数据: 操作数据和读取数据均不需要 .value
toRef和toRefs
toRef和toRefs整两个方法,它们不创造响应式,而是延续响应式。创造响应式一般由ref和reactive来解决,而toRef和toRefs则把对象的数据进行分解和扩散,其这个对象针对的是响应式对象(reactive)而非普通对象。
27.生命周期
onBeforeMount
onMounted
onBeforeUpdate
onUpdated
onBeforeUnmount
onUnmounted
onActivated
onDeactivated
28.Teleport
Teleport是一种能够将我们组件html结构移动到指定位置的技术(开发的时候非常有用)
29.provide / inject
作用:实现祖孙组件间的通信
套路:父组件有一个provide选项提供数据,子组件有一个inject选项来开始使用这些数据
30.侦听器
watch
语法:watch(监听源|[多个], (val, oldVal) => {}, {immediate?: false, deep: false})
watch写法上支持一个或者多个监听源,这些监听源必须只能是getter/effect函数,ref数据,reactive对象,或者是数组类型
watchEffect
它立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数
watch 和 watchEffect的区别
两者都可以监听 data 属性变化;
watch 需要明确监听哪个属性;
而 watchEffect 会根据其中的属性,自动监听其变化。
31.computed 计算属性
computed函数调用时, 要接收一个处理函数, 处理函数中, 需要返回计算属性的值
32.readonly 和 shallowReadonly
readonly:让一个响应式的数据变成只读的(深只读)
shallowReadonly: 让一个响应式数据变成只读的(浅只读)
应用场景:不希望数据被修改的时候