########Vue3基础部分

一:ES6新特性

栈内存:存放基本数据类型的变量名和变量值;复杂(引用)数据类型的变量名和引用地址
堆内存:复杂数据类型的变量值

1.let命令
var 和 let的区别(var的三大bug):

  • 作用域:var变量全局范围内有效,let变量仅在块级作用域内有效
  • 变量提升:var会发生变量提升现象,而let不会,即let必须先定义再使用
  • 变量重复声明:var在相同作用域内可以被重复声明,而let不允许重复声明

2.const命令
是一个只读的常量,声明时,必须赋初值,一旦声明,栈值就不能改变,

  • 对于基本数据类型,声明后值是不能改变的
  • 对于复杂数据类型,栈内的地址不能变,数据值(堆内存)是可以变的

3.变量的结构赋值
包括数组和对象的结构赋值

  • 数组: let [a, b, c] = [10, 20, 30];

  • 对象:let { name1, age1 } = { name1: ‘李四’, age1: 29 };
    4.对象的扩展
    包括属性的简写,方法的简写,扩展运算符,模版字符串

  • 属性的简写::当属性名和值的变量名相同时,触发对象的属性简写let name = ‘张三’; const person ={name}

  • 方法的简写:去掉冒号和function,
    eat() {
    return ‘三顿’
    }

  • 扩展运算符:三个点(…).可遍历属性。.三个点放在对象前,用于对象的合并等
    let z = { a: 10, b: 20 }
    let n = { …z, c: 30 };
    console.log(n) // {a: 10, b: 20, c: 30}

  • 模版字符串:模板字符串用反引号()表示,嵌入变量用${}表示 let idCard = '360424198612121539'; let str = 身份证号码${idCard} `
    5.箭头函数
    主要针对的是函数变量,即带有函数名的函数;使用箭头( => )连接参数列表和函数体
    箭头函数的简化:

  • 参数只有一个时,括号可以省略
    const say = msg => {
    函数体
    }

  • 无参数时,括号不能省略
    const say = () => {
    函数体
    }

  • 参数多个时,括号不能省略
    const say = (x,y) => {
    函数体
    }

  • 可变参数,括号不能省略
    const say = (…args) => {
    函数体
    }

  • 函数体只有一条return时,可以省略大括号和return关键字
    const say2 = x =>x+1

  • 函数体包含多条语句时,不可以省略大括号和return关键字

  • 函数体中有一个对象时,省略大括号和return关键字后需要用小括号
    -const student2 = () => ({ name: ‘张三’, age: 25 })

6.模块语法

  • export:规定模块的对外接口,如果希望外部能够获取模块内的某个变量/函数/类,就必须在模块中使用export输出该变量/函数/类
    const PI = 3.1415
    const add = (a, b) => a + b
    export { PI as pi, add } //可以合在一起导出,也可以分别导出

  • import:引入模块
    //import { pi as PI, add } from ‘./demo1.js’
    import * as abc from ‘./demo1.js’ // 导入全部
    console.log(‘pi的值为:’, abc.pi)
    console.log(‘调用add函数:’, abc.add(40, 50))

  • export default:每个模块【只能够使用一次】,可以导出变量,常量,函数,类,匿名函数
    export default (a, b) => a + b //默认导出的是匿名函数
    对于export default导出的,导入时,不需要{},并且变量名可以随意
    import 你家的孩子 from ‘./demo2.js’
    console.log(‘变量值为:’, 你家的孩子(3, 6))
    7.Promise异步编程
    Promise对象要点:
    原理:异步执行,当接口请求后,可以去做其他事情,等接口返回成功再渲染页面,接口返回失败也会有相应的提示

<!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>8-1 promise对象.html</title>
</head><body><script>/*Promise对象要点:1.Promise对象是用于执行异步操作的2.可以使用Promise构造函数来创建实例对象3.Promise对象的.then方法调用后,返回的还是一个Promise对象4.Promise对象的.catch方法调用后,返回的还是一个Promise对象*//*步骤1:创建Promise对象1.调用构造函数,来创建Promise对象2.构造函数的参数,是一个函数【参数是函数】,它负责执行业务3.该函数接受2个参数作为参数4.第一个参数:是resolve(成功的)函数,可以是其他5.第二个参数:是reject(拒绝的)函数*/const p1 = new Promise((resolve, reject) => {console.log('1.异步请求开始,异步讨债开始')// 去讨债开始......// ......漫长的过程,....可以去干其它事情....  // 讨债结束.....const flag = falseif (flag) { //resolve方法执行后,则执行then的第一个参数return resolve('还钱成功!')//异步调用,只支持一个参数(可以是一个对象)} else {return reject('还钱失败!')//它们前面加上return语句,这样就不会有意外。}})       /*要点:1.then方法,也接收2个函数作为参数,但第二个参数是可选的2.当resolve方法调用时,会触发then的第一个参数3.当rreject方法调用时,会触发then的第二个参数*///步骤2:调用异步执行.then方法const p2 = p1.then((a) => {// throw new Error('4.人为模拟异常,还的钱是假钱...')console.log('3.进来了then的第一个方法,还钱成功了,用钱干什么,买手机。。。', a)}// , () => {//第二个参数是可选的//     console.log('3.进来了then的第二个方法,,还钱失败了,怎么办。。。')// })//还可以继续.then/*要点:1.catch方法,也接收1个函数作为参数2.当【前面】的方法中有异常时,才会触发catch的参数*/// 步骤3.调用catch方法,then方法有效const p3 = p2.catch((e) => {console.log(`catch方法被调用了${e}`)}).finally(() => { //无论如何都会执行console.log('finally')})console.log('2.底部的代码调用了,将在当前脚本所有同步任务执行完才会执行点then异步代码')//Promise 新建后立即执行,所以首先输出的是Promise。
//然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出。</script>
</body>
</html>

二:创建vue3.0项目

1.在本地电脑创建一个文件夹
2.终端进入文件夹,创建项目:npm create vue@3,命名项目名称,出现如下界面

3.VSCode编辑器中,在终端执行一下命令,初始化并启动项目

  • cd study_vue #进入到项目根目录
  • npm install #安装项目依赖
  • npm run dev #启动项目

4.页面执行顺序
创建一个vue组件,main.js中导入该vue组件,挂载文件index.html 就可以找到该组件并运行在浏览器中

//main.js文件
import { createApp } from 'vue'   //不是路径的话,必须package.json中定义,dependencies
import { createPinia } from 'pinia'//{}是采用export形式导出的//import App from './App.vue'//export default导出的,App这个名字可以任意取。
import App from './components/CaoQing.vue'
import router from './router' //会找router文件下的index.jsimport './assets/main.css'
//创建vue实例化对象
const app = createApp(App) //app名字上随便的
//使用第三方插件/库
app.use(createPinia())
app.use(router)
//把创建的vue实例,挂载到 index.html
app.mount('#app') //括号里的app要和index.html里的<div id="app"></div>的id一致//总结:把开发的vue组件放到index.html里运行
//main.js:入门文件/主文件
//App.vue :根组件
//index.html ://挂载文件
//.vue结尾的都叫一个组件,打包工具会把组件打包成一个js,js会加上export default
//三个地方可以放组件:components:公共组件 views:业务组件  App.vue:src根目录下
//index.html文件
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><link rel="icon" href="/favicon.ico"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vite App</title>
</head>
<body><div id="app"></div><script type="module" src="/src/main.js"></script>
</body>
</html>

三:vcode常用插件

四:Vue3的基本指令

创建组件,组件名首字母要大写,以.vue后缀表示组件,装的插件有自动补全功能,所以只需要输入vbase,选择弹出的含有reactive的模版。Vue3的基本指令都是在template模版中使用,以下是模版简介

<template><!-- 第一部分:template模版,相当于html的body部分,是必须的 --><!-- 在模版中可以【直接使用】返回对象中的属性/方法 --><div>响应式对象计数:{{ count }}</div><div>普通对象计数:{{ count1 }}</div><div>响应式变量计数:{{ age }}</div>
</template><script>
//第二部分:js部分
import { onMounted, reactive, ref, toRefs } from 'vue'export default {//1.setup函数,是一个生命周期函数,是组合式API的起点//它比较特殊,无需从vue中导入,其他的周期函数都需要导入才能使用,而且其他生命周期函数都需要在setup函数使用setup() {//2.定义一个【响应式】对象 =》页面会变化const state = reactive({count: 0})//定义一个【普通】对象 =》页面不会变化const state1 = {count1: 0}//2.【响应式】变量 =》页面会变化const age = ref(0)//3.定义一个函数,方法不存在收否响应const addOne = () => {state.count += 1state1.count1 += 1age.value += 1}//4.生命周期函数:当页面加载完成后,才会执行onMounted(() => {//5.每隔多久执行某个代码/函数setInterval(addOne, 1000)})//以上定义的属性和方法必须返回,模板中才能使用//注意:如果是响应式对象里的变量,就不需返回模版里也可以使用return {age,//toRefs:把一个【响应式】对象,转换成普通对象,该普通对象的每一个属性值都是ref类型//三个点是扩展运算符,取出对象的所有可遍历属性...toRefs(state),...state1}}
}
</script><style lang="scss" scoped>
</style>

(1)文本插值
数据绑定最常见的形式就是使用双大括号的文本插值,基本语法:{{ 变量/数组/对象等 }}
(2)v-text指令 和 v-html指令

  • v-text指令,原样式输出文本
  • v-html指令,会将元素当成html标签解析后输出
    (3)v-once指令:用于执行一次性的插值,定义的元素或组件只会被渲染一次,当数据改变时,插值处的数据不会被更新
    (4)v-bond(数据绑定):基本语法 <标签 v-bind:属性=“值”><标签/>
    缩写是冒号: <标签 :属性=“值”><标签/>
    可以绑定的html属性包括:class,src,style,href,disabled等
    (5)v-if与v-show(条件渲染):只会在指令的表达式返回为true时进行渲染内容
    v-if基本语法:v-if v-else-if v-else
  • v-if: 条件判断指令,当不满足条件时,F12看元素被删除。if 更实用90%
  • v-show:条件判断指令,当不满足条件时,F12看元素隐藏,style="display: none
    (6)v-for(遍历):可以遍历数组,对象数组,对象
  • 遍历数组语法 v-for=“(item,index) in arrName” :key=“index”
    其中,item是数组项,index是下标,arrName是待遍历的数组
  • 遍历对象的语法 v-for=“(value,key,index) in obj” :key=“index”
    其中,value是对象的属性值,key是属性名,obj是具体的对象
    (7)v-on(监听事件)
    鼠标常用事件:
  • click:单击鼠标按钮时触发
  • dbclick:双击击鼠标按钮时触发
  • mouseover:当鼠标移到某个元素上方时触发
  • mouseout:当鼠标移出某个元素上方时触发

键盘常用事件:

  • keyup:当用户释放键盘上的健时触发
  • chage:当文本框(input或textarea)中的一个或多个字符触发
  • input:用户输入时触发,非常重要
  • focus:当页面或元素获得焦点时在window及相关元素上面触发
  • blur:当页面或元素失去焦点时在window及相关元素上面触发
  • submit:当用户点击提交按钮在元素上触发
  • reset:当用户点击重置按钮在元素上触发
    事件对象:当用户触发了一个事件后,对该事件的一些描述信息,事件对象必须使用($event)作为实参,e.target可获取整个元素的信息
    事件常用修饰符:.stop 组织同一事件的继续传播,通俗就是互补干扰彼此的执行,在事件名后使用,比如@click.stop
    按键(键盘)常用修饰符:.enter:回车键 .tab:table键盘

v-on用于:基本语法 <标签 v-on:事件名=“事件的处理方法或脚本”><标签/>
缩写是@:<标签 @事件名=“事件的处理方法或脚本”><标签/>
(8)v-model(表单输入绑定)
所谓表单,指的是html的input ,select,textarea等表单的元素,v-model实现和这些标签数据的双向绑定,监听用户的输入事件来更新数据。它本质上是一个语法糖,实际上就是v-bind:value + v-on:input的组合。

双向绑定:用javascript命令改变数据的值时,会在页面中自动重新渲染内容,改变文本框的内容也会自动修改绑定的数据(可在控制台看,以便于存放修改后的数据到数据库)。
可用于文本框,单选框,复选框,下拉列表,多行文本框的绑定

基本语法:<标签 v-model=“响应式数据”><标签/>输入框可以.number 限制只输入数字,.trim 去除左右空格。例如v-model.number和v-model.trim

五:Vue进阶

1.计算属性:
使用computed方法实现,方法参数是一个函数,它必须有return返回值,在该函数中,任意一个响应式数据发生变化,computed方法都将自动重新运算,视图也会同步更新,默认第一次就会调用。
2.侦听属性:
使用watch方法实现,该方法有三个参数:

  • 参数1:表示被侦听的响应式数据,可以是ref变量,ref数组,reactive对象,reactive对象的某个属性,只要操作了参数1中的数据,就会调用watch
  • 一个ref数据:直接写
  • 多个ref数据:数组形式[num1, num2]
  • reactive对象:state
  • reactive对象的某个属性:() => state.count
  • 参数2:是一个回调函数(即被监听数据变更后,需要触发的函数)在回调函数中,就可以做我们的计算了
  • 参数3:watch的额外配置项,对象格式,是可选的。immediate:true/false 是否首次页面加载就执行。默认false
    可以用setTimeout实现异步操作,例如:
    setTimeout(() => {
    num.value = 900
    }, 5000)

3.watchEffect:
和watch功能类似,不同的是 它会自动监听其内部回调函数使用到的数据,其中任意一个数据发生了变化,它都会执行回调函数,首次加载就会执行一次。
只有一个参数,该参数是一个函数
4.总结
计算属性:

  • 不支持异步 操作
  • 必须使用return
  • 监听的数据必须参与计算
  • 无法得到变更前的值
  • 有缓存,即结果存储到一个响应式变量中
    侦听属性:
  • 支持异步操作
  • 可以不使用return
  • 监听的数据可以不参与计算
  • 可以得到变更前的值
  • 计算属性完成的功能,侦听属性都可以完成
  • 没有缓存,即不会有存储结果
  • 默认首次加载不执行,当数据改变时才执行

watchEffect
和watch功能类似,不同的是:

  • 首次就会执行,相当于watch的immediate为true
  • 自动收集数据依赖
  • 得不到变更前的值
  • 可以停止监听,watch不可以

六:组件化开发

1.组件的常用的生命周期
创建-》挂载-》更新-》销毁
以下代码说明:

<template><div class="about"><h1>This is an about page(生命周期)</h1><div><input type="radio" name="xb" value="1" v-model="sex" />男<input type="radio" name="xb" value="2" v-model="sex" />女</div></div>
</template><style>
@media (min-width: 1024px) {.about {min-height: 100vh;display: flex;align-items: center;}
}
</style>
<script>
import {onBeforeMount,onBeforeUnmount,onBeforeUpdate,onMounted,onUnmounted,onUpdated,reactive,toRefs
} from 'vue'
export default {setup() {//第一阶段:创建console.log('1~2.setup()函数开始了!!!!相当于vue2的(BeforeCreate、Created)')const state = reactive({count: 0,sex: 1})//阻塞的睡眠函数(delay参数:N毫秒)//普通函数function sleep2(delay) {//当前时间const start = new Date().getTime()//执行的时间4 小于 设定的等待时间5 就继续等待,如果6大于等待的时间5,则跳出循环不再等待执行下一步骤while (new Date().getTime() - start < delay) {//继续,调用whilecontinue}}//箭头函数const sleep = (delay) => {//当前时间const start = new Date().getTime()//执行的时间4 小于 设定的等待时间5 就继续等待,如果6大于等待的时间5,则跳出循环不再等待执行下一步骤while (new Date().getTime() - start < delay) {//继续,调用whilecontinue}}//第二阶段:挂载,组件被挂载到index.html上//2。挂载前onBeforeMount(() => {console.log('3.onBeforeMount被调用了!(挂载前。。。。)')// 在组件挂载到index.html之前,睡大觉。睡5秒sleep(3000)})onMounted(() => {console.log('4.onMounted被调用了!(挂载后。。。。)')})//第三阶段:数据更新onBeforeUpdate(() => {console.log('5.onBeforeUpdate被调用了!(更新前。。。。)')})onUpdated(() => {console.log('6.onUpdated被调用了!(更新后。。。。)')})//第四阶段:销毁阶段,vue组件被销毁,即点击其他组件时,当前组件被销毁onBeforeUnmount(() => {console.log('7.onBeforeUnmount被调用了(组件失效了。。。)!')})onUnmounted(() => {console.log('8.onUnmounted被调用了!(组件失效且销毁了。。。)')})return {...toRefs(state)}}
}
</script>

2.组件的使用步骤

  1. 定义组件
  2. 父组件导入并注册组件
  3. 父组件使用子组件
<template><div><h2>组件的使用步骤</h2><h3>这里是父组件-FatherComp.vue</h3><!-- 步骤3:使用子组件 --><!-- 单标签 --><!-- <ChildComp /> --><!-- 标签对 --><child-comp></child-comp><!-- <ChildComp></ChildComp> --></div>
</template>
<script>
import { reactive, toRefs } from 'vue'
//步骤2-1:导入子组件
import ChildComp from './ChildComp.vue'
export default {//步骤2-2:注册子组件components: { ChildComp },setup() {const state = reactive({count: 0})return {...toRefs(state)}}
}
</script><style lang="scss" scoped>
</style>

3.父组件传递数据给子组件(80%以上用这个)
前提是:父子组件已经关联,参考2进行关联

  • 在父组件中定义好数据时,需要在其模版中绑定要传给子组件的数据 ,例如
 <child-comp v-bind:ccount="count" v-bind:cname="name" :clistObj="listObj"></child-comp>
  • 在子组件中用props接收父组件模版中定义的数据,props有两种接收数据的方式,分别是数组和对象,其中对象是常用的,父组件数据变化,子组件也会跟着变。代码如下:
<template><div><h4 style="color: red">这里是子组件-ChildComp.vue</h4><!-- 子组件渲染 --><h5>这里是从父组件传递过来的ccount的值:{{ ccount }}</h5><p>这里是从父组件传递过来的cname的值: {{ cname }}</p><p>这里是从父组件传递过来的clistObj的值: {{ clistObj }}</p><ul><li v-for="(obj, index) in clistObj" :key="index">{{ obj.id }}-{{ obj.realName }}</li></ul></div>
</template>
<script>
import { reactive, toRefs, ref, watch, watchEffect } from 'vue'export default {// props: ['ccount', 'cname', 'clistObj'],//Number、String、Array、Object等等//导入父组件模版中定义的值props: { ccount: Number, cname: String, clistObj: Array },setup(props) {const state = reactive({count: 0,ccount: 0 //定义一个响应式变量,接收父组件传过来的变更的值})//因为只执行一次,所以值一直不变// console.log('拿到的props的值为:', props.ccount)// 如果ccount 在setup中,也需要有响应式,怎么办?// 可以采用:侦听器watch(() => props.ccount,() => {console.log('调用了watch方法。')state.ccount = props.ccountconsole.log('拿到的props的值为:', state.ccount)},{ immediate: true })//父组件值改变,子组件值跟着改变,方便存储到数据库// watchEffect(() => {//   console.log('进来了watchEffect')//   state.ccount = props.ccount//   console.log('拿到的props的值为:', state.ccount)// })return {// result,...toRefs(state)}}
}
</script>
<style lang="scss" scoped>
</style>

4.子组件传递数据给父组件(用的比较少)
前提是:父子组件已经关联,参考2进行关联

  • 在子组件中定义好数据时,定义一个箭头函数,用emit函数包裹住要传给子组件的数据,它两个参数:1.事件名,由父组件的模版调用;2.要传递的数据,子组件数据变化,父组件也会跟着变
  /*setup接收2个参数,第一个是props,它为响应式对象。第二个参数context,它是非响应式对象context对象包括三个属性:emit(方法)、slots(插槽对象)、attrs(attribute对象)context:{ emit:()=>{}, slots:{},  attrs:{}  }我们也可以对它进行解构*/setup(props, { emit }) {const state = reactive({count: 10000,name: '小马云',obj: { name: '张三', age: 29 },objList: [{ id: 1, name: '张三', age: 22 },{ id: 2, name: '李四', age: 23 },{ id: 3, name: '王五', age: 25 },{ id: 4, name: '李世民', age: 27 },{ id: 5, name: '朱元璋', age: 30 }]})const sendMsg = () => {console.log('调用了子组件的传值方法。。。')//传给父组件//两个参数:1.事件名,由父组件的模版调用;2.要传递的数据emit('caoqq', state.count, state.name, state.obj, state.objList)}
  • 在父组件中定义一个箭头函数用来接收子组件传过来的数据,然后在该组件的模版中利用子组件中emit的事件名输出数据,代码如下:
<template><div><h2 style="color: pink">【子组件传递数据给父组件】</h2><h3 style="color: green">这里是父组件-FatherComp.vue</h3><!-- 步骤3:使用子组件 --><!-- 标签对 --><!-- caoqq是子组件中emit函数的事件名 --><child-comp @caoqq="getData"></child-comp></div>
</template>
<script>
import { reactive, toRefs } from 'vue'
//步骤2-1:导入子组件
import ChildComp from './ChildComp.vue'
export default {//步骤2-2:注册子组件components: { ChildComp },setup() {const state = reactive({count: 0})//方法里的参数要和子组件中emit的一致,也可以用可变参数接收const getData = (data, name, obj, objList) => {console.log('父组件接受了子组件传过来的值:count的值为:',data,'name的值:',name,'obj的值:',obj,'objList的值:',objList)// state.count = data}

七:组件进阶

1.动态组件
场景:在一个父组件中同时引用三个子组件,我们想一次只显示一个组件,当点击某个按钮时,切换显示不同的组件,要实现这种组件动态显示效果,vue提供了 compoent标签,语法如下:

<compoent :is="要显示的组件名" ></compoent> //采用v-bind指令绑定is属性
<template><div><h3>这里是父组件</h3><!-- 使用动态使用子组件 --><!-- component:is ,is的值是哪个组件的名称就显示哪个组件 --><component :is="selectTab"></component><!-- 选择需要显示的组件 --><select v-model="selectTab"><option value="TabOne">选项卡一</option><option value="TabTwo">选项卡二</option><option value="TabThree">选项卡三</option></select><div>选项内容:{{ selectTab }}</div></div>
</template><script>
import { reactive, toRefs } from 'vue'
//导入子组件
import TabOne from './TabOne.vue'
import TabTwo from './TabTwo.vue'
import TabThree from './TabThree.vue'export default {//注册子组件components: { TabOne, TabTwo, TabThree },setup() {const state = reactive({count: 0,selectTab: 'TabOne'})return {...toRefs(state)}}
}
</script>

2.插槽的使用
分为默认插槽(不具名插槽)和具名插槽
插槽:在子组件中留插槽,想让内容显示在什么位置,就把插槽放在哪里,插槽显示的内容是在父组件中写的。如果子组件定义了默认插槽,其他内容将显示在默认插槽中,如果定义了具名插槽具名插槽的内容将显示在具名插槽中,如果没有定义默认插槽,其他内容将不会显示

  • 默认插槽(不具名插槽):子组件模版中插槽语法格式:<slot></slot>
  • 具名插槽:子组件模版中插槽语法格式: <div><slot name="zhangsan"></slot></div> 其中name,是父组件中定义的插槽名,父组件模版中需要定义以下格式: <template v-slot:zhangsan>具名插槽内容-章三</template>, v-slot: 可以缩写成 #
    父组件内容如下:
    <!-- 在父组件中添加内容,这些内容将展示在子组件的插槽中 --><child-comp><!-- 这是不具名(默认)插槽要显示的内容 -->这里是父组件传给子组件展示的默认插槽内容11: {{ count }}<!-- 这是具名插槽要显示的内容 --><!--需要用到template标签,  --><template v-slot:zhangsan>具名插槽内容-章三</template><!--需要用到template标签,  --><template #lisi>简写具名插槽内容-李四</template></child-comp>

3.响应式变量的定义
三种方式定义响应式变量

  • reactive函数(通常用于复杂数据类型,比如对象和数组)
  • ref函数(通常用于基本数据类型,字符串,数值,布尔值,null,underfined,Symbol,Bigint)
  • computed计算属性(有return)
    4.toRef和toRefs
  • toRef:toRef接收两个参数:源响应式对象 和 该对象的指定属性名,返回一个ref数据,即单个
  • toRefs:把一个响应式对象转换成普通对象,该普通对象的每个属性都是ref,即批量
  setup() {//定义响应式变量state,但是state里的属性是没有响应式的const state = reactive({count: 0,name: '张三'})//toRef接收两个参数:源响应式对象 和 该对象的属性名(指定属性),返回一个ref数据// 采用toRef函数,为响应式对象的某个属性,添加响应式const conut2 = toRef(state, 'count')setInterval(() => {state.count += 1}, 1000)//return中的变量在模版中可以直接用return {age: 22, //也属性响应式变量,可直接使用conut2,count3: toRef(state, 'count'),//  1.toRefs,用来把响应式对象中的属性,变成响应式...toRefs(state)//   ...state //count就没有响应式了}}

5.模版引用
可以获取元素的具体信息

  • 第一步:定义一个响应式变量,并返回
  • 第二步:在模版中给需要的元素加上ref属性,并绑定第一步定义的响应式变量
  • 第三步:当页面加载完后,用响应式变量.value可以获取元素的值

########前端项目实战

一:路由的使用步骤

  1. 路由的安装:npm i vue-router@next
  2. 路由的开启:在程序入口文件main.js中全局配置路由
    import router from ‘./router’ //即router 文件夹下的 index.js 文件
  3. 路由的配置:项目中的 router/index.js 配置路由信息
//...1.从vue-router中导入createRouter, createWebHistory
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
//。。。2.导入HomeView组件
import Home from '../views/Home.vue'
//。。。。。3,使用createRouter方法创建一个路由器对象
const router = createRouter({//路由模式1:history模式(参数:导入环境变量中的基础URL),也可以不写括号里的内容// history: createWebHistory(import.meta.env.BASE_URL),history: createWebHistory(),//路由模式2:hash模式// history: createWebHashHistory(),routes: [//每一个路由,都是一个对象,它包括三个属性:path,【name】,[component/redirect二选一]{path: '/',//根路由,路由的路径name: 'home', //路由的名称 可以省略component: Home},{path: '/login',// route level code-splitting 路由级代码拆分//这将为此路由生成一个单独的模块(About.4543054354dfgdf.js)// this generates a separate chunk (About.[hash].js) for this route// 当访问路由时,是懒加载的// which is lazy-loaded when the route is visited.// 总结:路由懒加载方式,项目打包时,一个组件打包为一个js文件。访问时才加载组件。// component: () => import('../views/AboutView.vue')component: () => import('../views/Login.vue')}]
})
export default router //导出路由器
  1. 路由的使用

路由是用来实现页面导航的,导航分为两种:
声明式导航:在模板中声明路由链接,最终形成a标签导航
编程式导航:通过调用 JavaScript 形式的API实现导航,适合页面重定向,比 如登录成功后重定向到主页
(1)路由链接的代码如下(声明式导航的实现):

<!-- 作用:RouterLink会被渲染成一个a标签,它的to属性,会被渲染成a元素的href属性 -->
<!-- 好处:可以给to属性绑定变量(对象),to的值等于路由配置中的path -->
<RouterLink to="/about">About</RouterLink><RouterLink :to="{ path: '/', query: { a: '123', b: '456' } }">Home</RouterLink>

(2)路由填充位(路由占位符 )
通过路由规则匹配到的组件后,将组件的内容 渲染到路由占位符所在的位置(想在哪个组件里显示内容就在该组件留路由占位符,比如点击A组件中的【按钮】希望A组件内容在B组件展示,那么A组件和B组件就需要有关系,在同一Web网友中)。路由占位符的代码如下:

 <RouterView />
或<router-view />
或<router-view></router-view>

总结:前端页面访问的路由在根组件App.vue里找,找到后去index.js,找到对应的组件,将组件的内容在路由占位符中显示

二:Element+组件库

官网:https://element-plus.gitee.io/

  1. Element Plus安装: npm install element-plus
  2. main.js中全局配置这个库
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'  //样式
import zhCn from 'element-plus/es/locale/lang/zh-cn'const elementConfig = { size: 'default', local: zhCn, zIndex: 3000 }
app.use(ElementPlus, elementConfig)
  1. ElementPlus库的使用
    包括:表单,输入框,添加数据校验等多个组件,具体组件及用法参考官网。需要注意的点:
    1.表单验证时:
    ref:模版引用,用于获取页面元素
    model:数据绑定对象
    rules:绑定传入约定的验证规则
    prop:prop属性设置为需要校验的字段名

三:配置全局样式

main.js中全局导入自定义样式:import ‘./assets/css/common.scss’

四:全局注册 ICON图标库

  1. 安装库:npm i @element-plus/icons-vue
  2. 全局注册icon组件:
import * as Icons from '@element-plus/icons-vue'
// 1.注册全局elementplus icon组件 Object.keys(Icons).forEach((key) => {app.component(key, Icons[key])
})
  1. 使用:在Element Plus官网中找到需要的图标,直接复制即可
<el-icon><CirclePlus /></el-icon >

五:ElMessage消息组件

  1. 导入:import { ElMessage } from ‘element-plus’
  2. 使用:
import { ElMessage } from 'element-plus'
# 用法一
ElMessage.type('消息内容')
// 其中:type可替换为:success、warning、info、error
# 用法二 ElMessage({message: '消息内容',
type: 'success',// 其中:type值可为:success、warning、info、 error
})

六:localStorage本地存储

跟缓存类似,本地存储(新增、获取、删除、清空全部)
在浏览器的Applicationd的Local Storage下的地址中查看

  // A.新增// localStorage.setItem('userName', 'caoqq')// localStorage.setItem('userId', '123')// localStorage.setItem('token', 'wfffdsfd')// B.获取// console.log('userId====', localStorage.getItem('userId'))// C.删除// localStorage.removeItem('userName')// // D.清空所有// localStorage.clear()

七:Axios概述

Axios是一个基于Promise的HTTP库,可以用在浏览器和node.js中。用于向服 务器后端发起Ajax请求,并在请求的过程中可以进行很多控制,其主要特性如下:

  • 可以在浏览器中发送XMLHttpRequests
  • 可以在Node.js中发送HTTP请求
  • 支持Promise API
  • 可以拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求 自动转换JSON数据
  • 客户端可以防止XSRF攻击

Axios的安装:$ npm install axios
Axios的使用:两种方式,代码如下:

// 第一步:导入axios库
import axios from 'axios'
// 第二步:编写请求配置
const config = {url: '/token/',method: 'post',baseURL: 'http://地址/api',data: {username: "账号",password: "密码",captcha: "9999",captchaKey: 1157}
}
//第三步:发送网络请求
axios(config).then((res) => {console.log('res的值为:', res)console.log('res对象中的data为:', res.data)
}).catch((e) => {console.log('异常响应对象为:', e.response)console.log('异常响应状态码为:', e.response.status)console.log('请求异常')
})
// 第一步:导入axios库
import axios from 'axios'
// 第二步:编写请求配置
const config = {baseURL: 'http://地址/api',
}
// 第三步:采用别名的方式发送请求
//语法格式:axios.post(url[, data[, config]])
axios.post('/token/',{username: "账号",password: "密码",captcha: "9999",captchaKey: 1157}, config
).then((rep) => {console.log('res对象中的data为.data', rep.data)
}).catch()

总结:在实际应用中会封装Axios
定义一个js文件,包括

  • 默认配置,比如URL地址和请求超时时间
  • 定义常用的请求方法(post、get、delete、put)
  • 定义一个方法,里面封装各种请求的参数,比如处理请求头,处理config对象,请求路径的统一处理,params参数和data参数的特殊处理
  • 定义业务接口(项目的所有接口)
    例如:
    //每一个接口都是一个箭头函数,传参params是一个对象,然后导出
    export const login = params => axiosPost({ url: ‘token/’, params }) // Token登录

八:编程式导航基础router

通过调用 JavaScript 形式的API实现导航,适合页面重定向

  1. 导入路由器:
    import { useRouter } from ‘vue-router’ //导入router对象
  2. 创建路由器对象-必须在setup函数中创建
    const router = useRouter()
  3. 使用 router 对象提供的方法
    点击某个链接时,想要导航到不同的位置,可以使用 router.push 方法
//...1.参数为路径字符串
router.push('/about')
//...2.参数为对象-path属性
router.push({ path: '/about' }) //...3.参数为对象-name属性
router.push({ name: 'About' }) //...4.参数为对象-带查询参数
router.push({ name: 'About', query: { a: 'Hello' } })

九:主页组件的开发思路

1.主页布局
引用Element Plus布局,主页布局我们采用 左右结构 ,右边采用 上下结构
效果图如下:

  • 在 src/components 目录,再创建 顶栏 NavBar组件,侧边栏SideBar.vue组件,多个Tab页组件(内容)MutiTabs.vue组件
  • 在 src/components 目录,创建布局 Layout.vue 组件,内容参考Element Plus布局中的代码,把 顶栏,侧边栏,多个Tab页组件放入布局Layout.vue 组件中
  • 在 Home父组件 中引入 Layout子组件
    2.主页组件包括的内容
    顶栏:左和右区域
    左:折叠按钮/这里放面包屑(点击按钮时路径拼接显示)
    右:全屏按钮/用户图像/用户名/下拉退出登陆和用户设置
    左侧边栏:菜单,菜单下面有子菜单,点击按钮可以对菜单进行折叠
    多个Tab页:点击左边侧边栏按钮会展示对应的内容

3.左侧边栏组件注意内容

点击接口自动化下的各子组件时MutiTabs.vue组件会展示对应的内容

  • el-menu组件,默认情况下菜单路由功能是关闭的。可以设置 el-menu 组件 的 属性为 true
    来开启菜单路由功能,el-menu-item 组件的index 属性将被用来作为 path 进行路由跳转。
  • 路由嵌套,在src/views下创建 Cases 、 Requests 、 Plans 、 Reports 四个业务组件。
  • 再在 router/index.js 给Home组件配置四个字路由,因为流程是先进入主页组件,在主页组件的某一个角落显示业务组件的内容
 //父子路由children: [{path: '/cases', // 根路由,路由的路径name: '测试用例',component: () => import('../views/sqtp/Cases.vue')},{path: '/requests',name: 'web接口',component: () => import('../views/sqtp/Requests.vue')},{path: '/plans',name: '测试计划',component: () => import('../views/sqtp/Plans.vue')},{path: '/reports',name: '测试报告',component: () => import('../views/sqtp/Reports.vue')}
  • 点击接口自动化下的各子组件时MutiTabs.vue组件会展示对应的内容,所以可以在MutiTabs.vue组件中留一个路由占位符,也可以在 Layout.vue 组件中留一个路由占位符(Layout.vue中有MutiTabs组件 )

十:状态管理

pinia 都是状态管理库,用于跨组件(页面)进行状态共享,应用中,存在某些变量需要跨组件共享时,应该使用状态管理库。一个 Store 是一个存储实体,它有 state 、 getters 和 actions ,相当于组件中的 响应式数据 、 计算属性 和 方法 。

  • 安装:npm install pinia
  • 在 main.js 中,添加 pinia 的根存储,关键代码如下:
import { createPinia } from 'pinia'
app.use(createPinia())
  • 在stores下定义一个状态管理文件,以js结尾,关键代码如下:
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'// Setup方式定义Store
export const useUserStore = defineStore('user2', () => {// 1.定义响应式变量const count = ref(40)const name = ref('张三')// 2.定义计算属性const doubleCount = computed(() => count.value * 2)// 3.定义方法const addOne = () => { count.value++ }// 4.返回return { count, name, doubleCount, addOne }
})
  • 导入与调用:
import { useUserStore } from '@/stores/user' // 1.导入一个store
export default {setup() {const store = useUserStore()
return {} }
}
  • 获取状态

// 采用storeToRefs()、toRefs()函数解构,保留响应式 。记得要导出
const { count, name, doubleCount, addOne } = toRefs(store)
  • 修改状态
// $patch()方法修改(批量修改)
store.$patch({count: store.count + 1,name: '李四' })

十一:左侧菜单的展示

需求:根据当前登录的用户,从后端动态获取对应的菜单,进行格式转换后,存到本地存储中
(1)menuTree:左侧菜单数据
2)menuList: 按钮权限数据,类似:
“menuPermission”:
[“Retrieve”, “Update”, “Search”,“Create”, “Build”, “Delete”]

十二:全局路由守卫

碰到的问题:用户在未登录的情况下,仍然可以访问Home主页。这在实际项 目中是不允许的。如何在请求每条路由链接前,判断用户是否登录呢? Vue-rout提供了全局路由守卫来监听路由的进入与离开。程序员可以通过 Vue-router 提 供的 beforeEach (前置守卫)、 afterEach (后置守卫)两个钩子函数,来搞事 情。它们分别在路由改变前和改变后触发
在项目的 router/index.js 中,添加前置路由守卫,代码如下:

/* 前置路由守卫to表示要跳转到哪里from 表示从哪里来next表示动作 让进入
*/
router.beforeEach((to, from, next) => {// 进度条开始NProgress.start()const userId = localStorage.getItem('userId')if (to.path === '/login') {//1.跳转到登录界面,放行next(true) //或者next() } else if (userId) { // 2.有登录的,放行next()} else {//其他情况(无登录,且非登录界面)都跳转到登录界面next('/login') //进入登陆界面}
})
// 后置路由守卫
router.afterEach(() => {// 进度条结束NProgress.done()
})// 进度条的配置项:ease可以设置css3动画,如ease,linear;speed是进度条从开始到结束的耗时
NProgress.configure({ ease: 'linear', speed: 500 })

十三:XEUtils通用函数库

xe-utils 提供了一套实用的基础函数、任意格式的日期转换函数,浏览器相 关操作函数等。提供了100多个函数,应有尽有。总之,如果你有判断、处理、转 换的一些需求,尽管来这里找找看。
官网地址:https://toscode.gitee.com/x-extends/xe-utils api
文档:https://x-extends.github.io/xe-utils/

  • 安装与导入:
npm install xe-utils
import XEUtils from 'xe-utils'
  • 常用API:
    searchTree(array, iterate): 从树结构中根据回调查找数据。根据某一个子菜单查找到它所属的父菜单
    toTreeArray (array, options):将一个树结构转成数组列表
    toArrayTree (array, options):一个高性能的树结构转换函数,将一个带层级的数据列表转成树结构
    cookie (name, value, options):常用操作
XEUtils.cookie('name') // 根据name获取
XEUtils.cookie('name', 'value', {expires: '7d'}) //指定7天后期
XEUtils.cookie('name', null, {expires: -1}) // 删除 XEUtils.cookie.remove(name) // 删除

十四:面包屑组件的开发

思路:

  • 在 Element Plus 官网上,找到面包屑组件,拷贝过来
  • 根据 route对象 ,获取当前 url,从本地存储中,获取 menuTree (因为我们需要的icon和菜单名称都在菜单树 中)
  • 用监听器,监听 route.path 的变化
  • 在监听器中,根据 route.path 到菜单树中查找匹配的数组(这里要用到 XEUtils 库的 searchTree 函数)
    将匹配的树形数组,转换为数组列表,返回到 template 中(这里要用到 XEUtils 库的 toTreeArray 函数)
    在 template 中,对匹配的数组列表进行循环,显示菜单的ICON和菜单的名称

十五: 多Tab页选项卡的实现

利用状态管理,定义两个变量,左边菜单栏点击菜单,重复点击的菜单不重复展示

// 1.当前激活的选项卡const activeName = ref('')
// 2.当前打开的选项卡数组const openTabs = ref([])

十六:内容页布局组件(顶部搜索区、中间数据表格、底部数据分页)

系统中,业务功能菜单展示的内容,大部分布局是:上、中、下三栏布局,即顶部搜索区、中间数据表格、底部数据分页。这三个组件是通用组件
因此,我们可以单独创建一个内容页组件( MainLayout )。在该组件中,再单 独引入 Search 、 Tables 、 Paginator 三个子组件
布局采用:vh+ calc() ( 我们采用 ),即后面会在 Tables 组件中,添加了 height=“calc(100vh - 250px)”

十七:跨组件通讯

使用 Provide (提供)和 Inject (注入)进行数据传递,父组件可以作为所有子组件的依赖项提供数据,而不管组件层次结构有多深。 这种特性有两个部分:父组件有一个 Provide 选项用于提供数据;子组件有一个 I nject 选项用于接收这个数据。例如:
在测试用例组件中利用Provide

  1. 先导入import { provide } from ‘vue’
  2. 定义变量或方法
  3. 向外提供数据
 provide('searchForm', searchForm)provide('queryParam', queryParam)provide('columns', columns)provide('tableData', tableData)provide('total', total)provide('pageSize', pageSize)provide('pageIndex', pageIndex)provide('multiple', multiple)provide('getData', getData)
  1. 子组件接收数据,导入import { inject } from ‘vue’
   const tableData = inject('tableData')const columns = inject('columns')const multiple = inject('multiple', false)

Vue3总结(持续更新)相关推荐

  1. Admin.NET管理系统(vue3等前后端分离)学习笔记--持续更新

    我的学习笔记 - 9iAdmin.NET 欢迎学习交流 (一)前端笔记 1.1 关于.env的设置 1.2 关于路由模式问题 1.3 关于 vue.config.ts 1.4 关于 打包(pnpm r ...

  2. Vue3中使用Monaco Editor代码编辑器记录~持续更新

    Vue3中使用Monaco Editor代码编辑器记录-持续更新 因为毕设需要用到代码编辑器,根据调研,我选择使用monaco-editor代码编辑器 前端框架使用Vue3 + elementUI m ...

  3. Java 最常见的 10000+ 面试题及答案整理:持续更新

    Java面试题以及答案整理[最新版]Java高级面试题大全(2021版),发现网上很多Java面试题都没有答案,所以花了很长时间搜集,本套Java面试题大全,汇总了大量经典的Java程序员面试题以及答 ...

  4. Web前端面试题整合,持续更新【可以收藏】

    饭后闲来无事,把这几年带学生用的一些面试题整合一下,供上!拿走,不客气!应付一般公司的二面基本上是够用了.祝你早日拿到心仪的offer. css相关 1. 万能居中 1.margin: 0 auto; ...

  5. 最好的Vue组件库之Vuetify的入坑指南(持续更新中)

    目录 安装Vuetify 文档结构 快速入门 特性 样式和动画 首先先声明,个人不是什么很牛逼的大佬,只是想向那些想入坑Vuetify的前端新手或者嫌文档太长不知如何入手的人提供一些浅显的建议而已,能 ...

  6. 前端面试题(附答案)持续更新中……

    前端面试笔记 前言 一.HTML篇 1.语义话的目的是什么?? 2.HTML5新特征??? 3.cookie与sessionStorage和localStorage的区别??? 二.CSS篇 1.cs ...

  7. vue通用后台管理系统(保姆级)--持续更新中

    配合目录使用更加友好哦,文章中分享的项目搭建是完全从0-1搭建,完全适用于小白,可用于vue练手项目,目前还在持续更新中,本篇文章不会断更,因工作原因,只能晚上给大家更新,感觉还行的可以给个关注或者收 ...

  8. VSCode前端必备插件2022版(持续更新)

    VSCode前端必备插件2022版(持续更新) VSCode作为我们前端主流的开发工具,优势自然在于它的扩展插件,可以有效地提高开发效率和团队协作,本文提高的都是UP主亲测,最底下贴入我的vscode ...

  9. s-systemtap工具使用图谱(持续更新)

    整体的学习思维导图如下,后续持续更新完善 文章目录 安装 简介 执行流程 执行方式 stap脚本语法 探针语法 API函数 探针举例 变量使用 基本应用 1. 定位函数位置 2. 查看文件能够添加探针 ...

  10. swift 错误集合 ------持续更新中

    从今天开始凡是在用swift中遇到的错误都会在本博客持续更新 便于自己学习和快速开发 2017.7.20 如果你的程序写的有进入后台的方法,例如我的博客中点击home进入后台持续定位的那篇文章,发信进 ...

最新文章

  1. JAVscript对象
  2. 对kubernetes的认识
  3. PHD considerations
  4. web开发中常用的概念
  5. gui jfr_Java飞行记录器(JFR)
  6. ubuntu命令收集
  7. ios 音高测试软件,‎App Store 上的“绝对音感训练!”
  8. carlife android 无线,carlife无线连接流程是什么
  9. tablewidget 行数自适应_PS滤镜知识:详解自适应广角滤镜的概括以及使用方式。...
  10. binlog关闭事务记录_MySQL的CrashSafe和Binlog的关系-爱可生
  11. [Javascript]把html内容复制到剪贴板
  12. h5py group_人工智能驱动的零售:H&M Group如何做到
  13. 翻译记忆软件-塔多思TRADO经典教程_5
  14. Sublime 快捷键整理
  15. r语言boxcox异方差_R教程-15:线性回归中的异方差
  16. 120_x轴与y轴平移【transform: translateX(n) translateY(n)】利用定位和变形使元素水平垂直居中
  17. 区块链中的epoch
  18. 【报错】paddle相关报错和处理方法
  19. 浪潮互联网峰会张冬技术报告
  20. J-Flash下载程序

热门文章

  1. 合同的收据和发票的区别
  2. Lucene使用IKAnalyzer分词实例 及 IKAnalyzer扩展词库
  3. Origin 2021/2022绘图软件 出现0xc000007b错误的解决方法
  4. matlab三维可视化,三维可视化 - MATLAB Simulink - MathWorks 中国
  5. centos 7 安装音频视频解码器
  6. Error while merging dex archives 的解决办法
  7. c++如何按照空格分割字符串
  8. 阿里中台再起波澜,中台适合做“组合式创新”,没法做“颠覆式创新”
  9. Kotlin系列二:面向对象编程(类与对象)
  10. U8C推拉单API开发笔记