vue学习笔记

目录

1.什么是MVC,什么是MVVM?

两种开发模式:

​ 前后端不分离(基于服务端渲染,web网页资源服务器 )

前后端分离(Web接口服务器)

两种软件架构模式:

​ MVC

​ MVVM

MVC:全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范,将业务逻辑、数据、界面显示分离组织代码的形式

M:model层,主要处理数据的curd

V:view 视图层,前 端页面

C:controller 控制器,也被称为业务逻辑层,路由也是这里面的,最重要的是conrtol,数据的业务逻辑。例:登陆,注销

img

MVVM-----前后端分离模式, 可以说是MVC架构模式的改进版

  • Model:模型层,在这里表示 JavaScript 对象
  • View:视图层,在这里表示 DOM(HTML 操作的元素)
  • ViewModel:连接视图和数据的中间件,Vue.js 就是 MVVM 中的 ViewModel 层的实现者

img

VUE就是一个典型的MVVM模型的框架

2 vue简介

官网参考文档:https://cn.vuejs.org/guide/introduction.html

Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。

Vue 有很多特点和Web开发中常见的高级功能

    • 解耦视图和数据
    • 可复用的组件
    • 前端路由技术
    • 状态管理
    • 虚拟DOM

为什么要使用 Vue.js

  • 轻量级,体积小是一个重要指标。Vue.js 压缩后有只有 20多kb (Angular 压缩后 56kb+,React 压缩后 44kb+)
  • 移动优先。更适合移动端,比如移动端的 Touch 事件
  • 易上手,学习曲线平稳,文档齐全
  • 吸取了 Angular(模块化)和 React(虚拟 DOM)的长处,并拥有自己独特的功能,如:计算属性
  • 开源,社区活跃度高

Vue的两大核心特点

  • 数据驱动视图
  • 组件化

3 Vue初体验

<!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>Document</title>
    <!-- 引入vue.js框架 -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app">
      <div>{{msg}}====={{number}}</div>
      <button @click="addnumber">{{number}}</button>
    </div>

    <script>

      const {createApp,ref} = Vue
      createApp({
        setup(){
          const msg=ref("hello vue")
          const number = ref(0)
          function addnumber(){
            number.value++
          }
          return {
            msg,
            number,
            addnumber
          }
        }

      }).mount("#app")

    </script>

  </body>
</html>

4 Vue的使用和安装

前提条件:已安装node 16.0或以上版本

创建一个vue项目:

npm create vue@latest myapp //myapp是项目名称

5 vue基础

1.setup函数

setup函数。是vue的入口函数。

1、setup函数是Vue3.0中的一个新的配置项,值为一个函数,setup是组件的一个入口函数。

2、组件中用到的:数据、方法等等,均要配置在setup中,并返回。

3、若返回一个对象,则对象中的属性、方法在模板中均可以直接使用

1.1 原始setup函数

<script>
//vue3组合式API  setup函数的语法规则:
//1、入口函数
//2、模板中用到的数据和方法,需要return以下,才能使用
import { ref } from "vue";

export default {
  setup() {
    //定义响应式数据
    const msg = ref("哈哈哈");
    const count = ref(0)

    //定义方法
    function add(){
      count.value++;
    }

    return {
      msg,
      count,
      add,
    };
  },
};
</script>

<template>
  <header>
    <h1>hello vue</h1>
    <h1>{{ msg }}</h1>
    <div>计数器:{{count}}</div>
    <button @click="add">++</button>
  </header>

  <main></main>
</template>

<style scoped></style>

1.2 setup函数的语法糖


<script setup>
//setup函数的语法糖
//setup函数的语法糖,setup以属性的形式出现在script标签里
//响应式数据和方法无需再return出来,可直接在模板中使用
import {ref} from "vue"
const msg = ref("欢迎来到北游学java")
const count=ref(0)

function add(){
  count.value++
}
</script>

<template>
  <header>
    <h1>hello vue</h1>
    <h1>{{ msg }}</h1>
    <div>计数器:{{count}}</div>
    <button @click="add">++</button>
  </header>

  <main></main>
</template>

<style scoped></style>

2.ref函数

ref函数 用来定义响应式数据

使用

  1. 使用之前需要从"vue"中导入

  2. 可以定义任何类型的响应式数据

  3. 用ref定义的响应式数据,在js中使用,需要通过.value获取,在视图中使用,不需要.value 可以直接使用

        import {ref} from "vue"
        //定义普通数据
        let a = 10;
        //定义响应式数据
        let msg = ref("lalala")
    

3.reactive函数

reactive用来定义响应式复杂数据(数组和对象)

使用

  1. 使用前需要从"vue"引入

  2. 可以用来定义响应书复杂数据类型 在js中不需要通过.value使用

  3. 推荐用法:如果需要定基本响应式数据和数组类型,使用ref定义,其余一概使用reactive定义

区别

对比一下ref函数和reactive函数区别:

  1. ref可以用来定义任何类型的响应式数据,reactive只能用来定一复杂数据类型(对象)

  2. ref定义的响应式数据在is中要通过.value使用,reactive定义的数据可以在is中直接使用

  3. 推荐用法:如果需要定基本响应式数据和数组类型,使用ref定义,其余一概使用reactive定义

4.几个简单指令

补充几个简单的vue指令

指令

1.v-html解析并渲染html标签字符串 类似于innerHtml

​ 2.v-text 渲染文本字符v 类似于innerText

​ 3.v-noce 代表该元素或标签只渲染一次,后续对被v-noce指令定义的标签渲染不再生效

​ 4.{{}} 插值表达式

注意点

1、v-text 标签里不能添加内容 {{}}可以实现部分文本的穿插

​ 2、插值表达式{{}}只能是表达式(例如:变量名,三元表达式)不可以写js语句

<script setup>
import {ref,reactive } from "vue"

let title = ref("halohalo")
let title1 = ref("<h1>我是大傻子</h1>")

let num = ref(10);

function add(){
    num.value++
}
</script>

<template>
    <div>
        <p v-html="title1"></p> 
        <p v-text="title1"></p>

        <p>{{ num }}</p>
        <p v-once>{{ num*10 }}</p>
        <button @click="add">++</button>
    </div>
</template>
<style scoped></style>

5.条件渲染

使用

1.指令 v-if v-else v-else-if 类似于 js中的 if else else-if
根据条件决定是否渲染该元素,实现显示隐藏效果

2.v-show条件渲染 条件为true 渲染 false不渲染 隐藏结果

3.三元表达式也可以实现条件渲染

对比v-if和v-show的区别

​ 1.v-if条件为false时 dom节点压根不存在该标签

​ 2.v-show条件为false时 dom节点中有该标签,他是通过添加display:none实现隐身

​ 3.如何取舍

​ 如果显示隐藏切换频繁时,使用v-show

​ 如果只切换一次时,选择v-if

<script setup>
import {ref,reactive } from "vue"



let islogin = ref(false)

let score = ref(90)



function switchlogin() {
    islogin.value = !(islogin.value)
}

let boo = ref(true)
</script>

<template>
<div>

    <h1 v-if="islogin">登录成功</h1>
    <h1 v-else>登录失败</h1>
    <button @click="switchlogin">切换登录状态</button>


    <div>
        
        您的成绩为{{score}},
        <br>
        等级为:
        <span v-if="score>90">666</span>
        <span v-else-if="score>80">66</span>
        <span v-else-if="score>70">6</span>
        <span v-else>不及格</span>
    </div>

    <button @click="boo=!boo">切换</button>
    <div id="box" v-show="boo"></div>



</div>

</template>


<style scoped>
#box{
    width: 300px;
    height: 300px;
    background-color: red;
}
</style>

6.列表渲染

列表渲染:渲染数组 渲染对象

1.渲染数组

​ 语法:v-for=“(item,index) in arr”

​ item代表数组元素 必选的

​ index代表数组索引 可选

2.渲染对象

​ 不常用

​ 语法:v-for=“(value,key,index) in obj”

注意:列表渲染时一定要动态绑定key属性,值取唯一值,一般推荐使用id :key=“item.id” 如果没有id用index

7.v-bind动态绑定

1.使用场景

‘{{}}’ 插值表达式可以实现标签内容的动态控制
但是某些情况下,我们也需要动态控制一些标签属性 例如a标签的href img的src属性

2.使用语法

v-bind:属性名=“变量名”

3.注意

v-bind是可以动态绑定任何属性包括class属性 id等

4.v-bind语法糖(简写形式)

:属性名=“变量名”

v-bind动态控制class属性,进而控制标签样式

<!-- 
/*   v-bind动态绑定属性

    1.使用场景:‘{{}}’ 插值表达式可以实现标签内容的动态控制
     但是某些情况下,我们也需要动态控制一些标签属性 例如a标签的href  img的src属性

    2.使用语法  v-bind:属性名="变量名"

    3、注意:v-bind是可以动态绑定任何属性包括class属性 id等

    4、v-bind语法糖(简写形式)  :属性名="变量名"

    5.v-bind动态控制class属性,进而控制标签样式

 */  -->
<template>
    <div>

        <!-- v-bind -->
        <a v-bind:href="url" target="_blank">百度一下</a>

        <br><br>

        <!-- 语法糖 -->
        <img :src="imgurl" alt="图片" width="400px">

        <br><br>


        <button @click="changeImage">切换图片</button>

        <!-- v-bind动态控制class属性 -->
        <div :class="{'box':boo}" id="a"></div>
        <button @click=" boo= !boo">切换颜色</button>

        <!-- 点击高亮 -->
        <h1>点击高亮</h1>
    </div>
</template>

<script setup>
import { ref } from 'vue';
let boo = ref(true)
let list = ref([1,3,,4,5,6,6,7,8,9])

// 使用 ref 创建响应式数据
const url = ref('https://www.baidu.com/');
const imgurl1 = ref('https://ts1.cn.mm.bing.net/th/id/R-C.748160bf925a7acb3ba1c9514bbc60db?rik=AYY%2bJ9WcXYIMgw&riu=http%3a%2f%2fseopic.699pic.com%2fphoto%2f50017%2f0822.jpg_wh1200.jpg&ehk=CMVcdZMU6xxsjVjafO70cFcmJvD62suFC1ytk8UuAUk%3d&risl=&pid=ImgRaw&r=0');
const imgurl2 = ref('https://ts1.cn.mm.bing.net/th/id/R-C.23034dbcaded6ab4169b9514f76f51b5?rik=mSGADwV9o%2fteUA&riu=http%3a%2f%2fpic.bizhi360.com%2fbbpic%2f40%2f9640_1.jpg&ehk=RYei4n5qyNCPVysJmE2a3WhxSOXqGQMGJcvWBmFyfdg%3d&risl=&pid=ImgRaw&r=0');
const imgurl = ref("")
imgurl.value = imgurl1.value

// 定义切换图片的函数
function changeImage() {

    // // 根据当前显示的图片路径切换到另一张图片
    // if (imgurl1.value === imgurl.value) {
    //     imgurl.value = imgurl2.value;
    // } else {
    //     imgurl.value = imgurl1.value;
    // }

    imgurl.value = (imgurl1.value === imgurl.value) ?imgurl2.value : imgurl1.value
}
</script>

<style scoped>
.box{
    background-color: red;
}
#a{
    width: 400px;
    height: 400px;
    border: 1px solid black;
}
</style>

8.v-on事件绑定

1.事件绑定

语法:v-on:事件名称=“事件处理函数” 例如:点击事件click

2.事件绑定语法糖

@事件名称=“事件处理函数”

3.事件对象

$event

4.事件传参

看例子

<script setup>
import {ref,reactive } from "vue"
/* 
    1.事件绑定
        语法:v-on:事件名称="事件处理函数" 例如:点击事件click

    2.事件绑定语法糖: @事件名称="事件处理函数"

    3.事件对象  $event  

    4.事件传参

    常用事件类型:click  mouseleave 鼠标离开
    mouseenter 鼠标进入


*/

let num = ref(0);

let handclick = (e)=>{
    console.log(e)
    console.log(e.target)
    console.log(e.target.id)
    console.log("lalalal");
}
let handclick1 = (e,a)=>{
    num.value += a
}

let isred = ref(false);

let bian = function(){
    console.log("lalalal");
    isred.value = ! isred.value
}

let bian1 = function(){
    isred.value = false;
}
</script>

<template>

<button v-on:click="handclick($event)">aaa</button>

<!-- 事件传参 -->
<h1>{{ num }}</h1>
<button @click="handclick1($event,5)">num+5</button>


<!-- 图片变身 -->
<div class="box"  @mouseenter="bian" :class="{'red':isred}" @mouseleave="bian1">  </div>
</template>

<!-- 
    scoped属性  表示该样式代码只在当前vue中生效
    不加scoped属性 表示该样式代码在所有vue中生效
 -->
<style scoped>
.box{
    width: 300px;height: 300px;background-color: blue;
}
.red{
    background-color: red;
}
</style>

9.事件绑定练习

<script setup>
import {ref,reactive } from "vue"
// 练习:渲染一个学生信息管理表格 实现删除功能
//方法1.  arr.splice(beginIndex,count) 从beginIndex开始截取count个元素 修改原数组

//方法2.  arr.filter((item,index)=>{retrun index!=ind})
</script>

<template>

</template>

<!-- 
    scoped属性  表示该样式代码只在当前vue中生效
    不加scoped属性 表示该样式代码在所有vue中生效
 -->
<style scoped></style>

10.事件绑定的修饰符

<script setup>

import {ref,reactive } from "vue"
/* 
    事件绑定修饰符 @事件名称.事件修饰符 = "事件处理函数"
    1. .prevent  会自动调用e.preventDefault() 用来阻止事件默认行为
    2. .once 事件只触发一次
*/

let cc= ()=>{
    console.log("www")
}

let ccc= ()=>{
    console.log("qqq")
}
</script>

<template>
    <a href="https://www.baidu.com" @click.prevent="cc">111</a>
    <button  @click.once="ccc">222</button>
</template>

<style scoped></style>

11.计算属性

1.使用场景

{{}}插值表达式可以将响应式数据直接渲染到标签内容上,但是在某些情况下,我们的数据可能需要转化处理之后,在显示在页面上,这时就需要用到计算属性 computed

2.使用方式

​ 1.需要从 "vue"中引用

​ 2.调用computed()函数,在函数的参数(回调函数)中将转换处理好的数据返回即可

3.注意点

计算属性的值会随着着依赖数据的变化而变化,从而自动更新视图

<script setup>

import {ref,reactive,computed } from "vue"
/* 
计算属性
    1、使用场景:{{}}插值表达式可以将响应式数据直接渲染到标签内容上,但是在某些情况下,我们的数据可能需要转化处理之后,在显示在页面上,这时就需要用到计算属性  computed

    2.使用方式
        1.需要从 "vue"中引用
        2.调用computed()函数,在函数的参数(回调函数)中将转换处理好的数据返回即可

    3.注意点:
        1.计算属性的值会随着着依赖数据的变化而变化,从而自动更新视图

*/

//练习1
    let firstName = ref("张")
    let lastName = ref("三")

    //使用计算属性
    let fullName = computed(()=>firstName.value+lastName.value)

//练习2 工资1000 显示公积金 社保 医保缴纳金额
    let salary = ref(10000)
    let gjj = computed(()=>salary.value*0.12)
    let sb = computed(()=>salary.value*0.02)
    let yb = computed(()=>salary.value*0.04)

    let addSal = function(){
        salary.value+=1000;
    }


</script>

<template>
<div>
    <!-- 练习1 -->
        <!-- 不使用计算属性 -->
        <h1>{{ firstName+lastName }}</h1>

        <!-- 使用计算属性 -->
        <h1>{{ fullName }}</h1>
        <br>
        <br>
    <!-- 练习二 -->
        <h1>工资:{{ salary }}</h1>
        <h1>公积金{{ gjj }}</h1>
        <h1>社保:{{ sb }}</h1>
        <h1>医保:{{ yb }}</h1>
        <button @click="addSal">加钱</button>
</div>

</template>
<style scoped></style>

12.v-model双向数据绑定

注意点

​ 1.双向数据绑定仅仅针对于表单标签

​ 2.双向数据绑定指vue实例对象中的响应式数据和表单标签的value属性

​ 3.表单的双向数据绑定本质上是v-bind和v-on的结合

​ 4.v-model实现双向数据绑定

<script setup>

import { ref, reactive } from "vue"

/* 
    双向数据绑定 v-model
        1.双向数据绑定仅仅针对于表单标签
        2.双向数据绑定指vue实例对象中的响应式数据和表单标签的value属性
        3.表单的双向数据绑定本质上是v-bind和v-on的结合
        4.v-model实现双向数据绑定
*/


//想要做到修改value属性,响应式数据也同时更新
let val = ref("333")

let change = function (e) {
    console.log(e.target.value)
    val.value = e.target.value
}
// <!-- v-model实现双向数据绑定 -->
let keyWord = ref("222")
let lala = (e)=>{
    console.log(e.target.value)
}


// <!-- 单选框双向数据绑定 -->
let sex= ref("男")

// <!-- 单独复选框的双向数据绑定 -->

let isAgree = ref(false)

// <!-- 多个复选框的双向数据绑定 -->
let hobby = ref([])
</script>

<template>

    <!-- @input 输入事件 input被输入内容时会触发 -->
    <input type="text" :value="val" @input="change">
    <h1>{{ val }}</h1>

    <!-- v-model实现双向数据绑定 -->
    <input type="text" v-model="keyWord" @input="lala">
    <h1>{{ keyWord }}</h1>


    <!-- 单选框双向数据绑定 -->
    <label >
        <input type="radio" value="男" v-model="sex">男
    </label>
    <label >
        <input type="radio" value="女" v-model="sex">女
    </label>
    <label >
        <input type="radio" value="不详" v-model="sex">不详
    </label>

    <h1>{{ sex }}</h1>

    <!-- 单独复选框的双向数据绑定 -->
    <input type="checkbox" v-model="isAgree">同意协议
    <br>
    <button :disabled="!isAgree">下一步</button>
    <h1>{{ isAgree }}</h1>

     <!-- 多个复选框的双向数据绑定 -->
     爱好:
     <label >
        <input type="checkbox" v-model="hobby" value="唱">唱歌
     </label>
     <label >
        <input type="checkbox" v-model="hobby" value="跳">跳
     </label>
     <label >
        <input type="checkbox" v-model="hobby" value="rap">rap
     </label>
     {{ hobby }}

</template>
<style scoped></style>

13.监听器


<script setup>

import {reactive, ref,watch} from "vue"
/* 
    watch 监听器 用来监听响应式数据的变化 使用之前需要从 "vue"中引入
    watch监听响应式数据的几种情况
        1.监听一个基本响应式数据的变化,添加immediate:true可以监听初始化变化
        2.监听多个基本响应式数据的变化,数组中只要有一个发生变化就会触发监听
        3.监听响应式对象
        4.监听响应式对象的某一个的属性
        5.监听响应式对象的某几个属性
*/

// 1.监听一个基本响应式数据
let num = ref(0)
watch(num,(newval,oldval)=>{
    console.log("更新前"+oldval)
    console.log("更新后"+newval)
},{immediate:true})

// 2.监听多个基本响应式数据的变化
let msg = ref("lalala")
let change  = ()=>{
    msg.value = "哈哈"
}
watch([num,msg],(newval,oldval)=>{
    console.log("更新前"+oldval)
    console.log("更新后"+newval)
})

//3.监听响应式对象
let userInfo = reactive({name:"admin",age:18})
let changUser = ()=>{
    if(userInfo.name ==="lweq"){
        userInfo.name="admin"
        return
    }
    userInfo.name = "lweq"
}
//注意:回调函数只有一个形参,代表更新之后 的值
watch(userInfo,(val)=>{
    console.log(val)
})



//4.监听响应式对象的某一个的属性
let stu = reactive({name:"wang",age:25,sex:"男",high:180,addr:"中国"})
let changeStu = ()=>{
    stu.age = 50;
}
//监听age属性
watch(()=>stu.age,(n,o)=>{
    console.log("更新前"+o)
    console.log("更新后"+n)
})


//5.监听响应式对象的某几个属性
//监听age和sex属性
watch( [()=>stu.age,()=>stu.sex],(n,o)=>{
    console.log("更新前"+o)
    console.log("更新后"+n)
})
</script>

<template>

    <!-- 1.监听一个基本响应式数据 -->
    <div>计数器 {{ num }}</div>
    <button @click="num++">++</button>

    <!-- 2.监听多个基本响应式数据的变化 -->
    <h1>{{ msg }}</h1>
    <button @click="change">++</button>

    <!-- //3.监听响应式对象 -->
    <h1 @click="changUser">{{ userInfo.name }}</h1>
    <h1>{{ userInfo.age }}</h1>

    <!--4.监听响应式对象的某一个的属性 -->
    <div v-for="(value,key,index) in stu" :key="index">{{ key }}:{{ value }}:{{ index }}</div>
    <button @click="changeStu">++</button>

</template>
<style scoped></style>

14.生命周期钩子函数

概念

组件-实例从被创建到被销毁的整个过程

使用步骤

  1. 先从vue中导入以on打头的生命周期钩子函数
  2. 在setup函数中调用生命周期函数并传入回调函数
  3. 生命周期钩子函数可以调用多次
生命周期函数含义执行机制
setup入口函数实例对象创建之前自动执行
onBeforeMount渲染前几乎不用
onMounted渲染后常用,用来发送ajax请求 操作dom 初始化图表、设置定时器
onBeforeUpdate更新前几乎不用 可以监听器watch替代
onUpdated更新后几乎不用
onBeforeUnmount销毁前常用来进行销毁操作 比如清除定时器
onUnmounted销毁后几乎不用
<script setup>
/* 
    生命周期钩子函数
        1.setup 入口函数  实例对象创建之前自动执行
        2.onBeforeMount   渲染前    几乎不用
        3.onMounted       渲染后    常用,用来发送ajax请求 操作dom 初始化图表、设置定时器
        4.onBeforeUpdate  更新前    几乎不用  可以监听器watch替代
        5.onUpdated       更新后    几乎不用
        6.onBeforeUnmount 销毁前    常用来进行销毁操作  比如清除定时器
        7.onUnmounted     销毁后    几乎不用
   
    使用声明周期钩子函数之前,也需要导入  从"vue"中

*/

import {ref,reactive,onBeforeMount,onMounted,onUpdated,onBeforeUpdate,onBeforeUnmount,onUnmounted} from "vue"

//渲染前
onBeforeMount(()=>{

})

//渲染后 发送ajax请求
onMounted(()=>{

})

let timer = reactive({time:null})
timer.time = setInterval(()=>{
    console.log("lalalla")
},3000)


//销毁前
onBeforeUnmount(()=>{
    clearInterval(timer); // 停止定时器
})
</script>

<template>


</template>
<style scoped></style>

15.ref获取dom节点

步骤

1.创建ref对象

2.在目标节点中建立联系

3.使用dom节点

<script setup>
import {ref,reactive } from "vue"
/* 
    ref函数有两大功能
    1.定义响应式数据和数组
    2.用来获取dom节点   功能类似于原生js中的document.getElementById()
        获取dom节点步骤:
            1.创建ref对象
            2.在目标节点中建立联系
            3.使用dom节点
 */
//获取dom节点
//1.创建ref对象
let divRef = ref(null)

let getDiv = ()=>{
    //3.使用dom节点
    console.log(divRef.value) //获取dom节点
    console.log(divRef.value.innerText) //获取节点文本
}

</script>

<template>
<!-- 2.在目标节点中建立 -->
<div ref="divRef">
    欢迎!!
</div>
<button @click="getDiv">获取div</button>


</template>
<style scoped></style>

6 自定义组件

1.自定义组件的使用

组件化思想

组件化是 Vue.js 中的重要思想 ,它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用

任何的应用都会被抽象成一颗组件树:

img

有了组件化的思想,我们在之后的开发中就要充分的利用它,尽可能的将页面拆分成一个个小的、可复用的组件,这样让我们的代码更加方便组织和管理,并且扩展性也更强

分类

局部组件:只能在当前引入组件中使用;

全局组件:可以在所有组件中使用

步骤

1.创建组件 .vue文件 在src/components/xxx.vue

2.引入组件

3.使用组件

App.vue组件:

<script setup>
import {ref,reactive } from "vue"
import OneCom from "./components/OneCom.vue"
import TwoCom from "./components/TwoCom.vue";
/* 
    组件化开发
    1.组件的分类:局部组件  全局组件
    2.自定义组件的使用步骤
        1.创建组件 .vue文件 在src/components/xxx.vue
        2.引入组件
        3.使用组件
*/
</script>

<template>
<div>
    根组件
    <OneCom></OneCom>
    <TwoCom></TwoCom>
</div>

</template>


<style scoped></style>

全局组件

需要早入口文件main.js中引入,并注册

img

2.父传子

什么是组件通讯

组件是独立且封闭的单元,默认情况下组件只能使用自己的数据(state)

组件化开发的过程中,完整的功能会拆分多个组件,在这个过程中不可避免的需要互相传递一些数据

为了能让各组件之间可以进行互相沟通,数据传递,这个过程就是组件通信

组件的通信的分类

​ 1、父传子

​ 2、子传父

​ 3、非父子组件通信

父传子的实现步骤

1.父组件提供数据

2.在父组件的子组件标签上添加自定义属性 值就是要传递的数据

3.在子组件中用defineProsp接收,通过props.属性名获取要传递的值

​ const props = defineProps({

​ msg:String,

​ })

APP.vue

~~~vue
<!--1.2.在父组件的子组件标签上添加自定义属性  值就是要传递的数据 -->
根组件
~~~

SonCom.vue

<script setup>
import { ref, reactive,defineProps,defineEmits } from "vue"

   //1.3在子组件中用defineProsp接收,通过props.属性名获取要传递的值
const props = defineProps({
    msg: String,//String是进行类型检测是否为String如果不为String则警告
    user: {
        name: String,
        age: Number
    }
})

</script>

<template>

    <!-- 父传子 -->
    <div>子组件</div>
    <div>从父组件接收过来的数据: {{ props.msg }}</div>
    <div>
        {{ props.user.name+props.user.age }}
    </div>
</template>

<style scoped>
div {
    background-color: pink;
    color: blue;
}
</style>

3.子传父

props是单向数据流,不允许子组件修改父组件的数据,此时需要子组件向父组件传递数据

实现步骤

1.子组件提供数据

2.子组件通过defineEmits注册自定义事件,并发送自定义事件,同时传参

3.父组件的子组件标签上绑定自定义事件,事件处理函数的形参就是要传递过来的数据

SonCom.vue

<script setup>
import { ref, reactive,defineProps,defineEmits } from "vue"

//2.子传父
    //1.子组件提供数据
    let id = ref(100)
    //2.注册自定义事件
    const emits = defineEmits(["sentId"])
    let handClick = ()=>{
        emits('sentId',id.value)//发送自定义事件并传值
    }
</script>


<template>

    <div>
        <!-- 子传父 -->
        <button @click="handClick">发送id</button>
    </div>
</template>


<style scoped>
div {
    background-color: pink;
    color: blue;
}
</style>

APP.vue

<script setup>
import {ref,reactive } from "vue"
import SonCom from "./components/SonCom.vue";

/* 
    2.子传父   因为vue是单项数据流,所以子组件不能直接修改父组件传递过来的数据
        步骤:
            1.子组件提供数据
            2.子组件通过defineEmits注册自定义事件,并发送自定义事件,同时传参
            3.父组件的子组件标签上绑定自定义事件,事件处理函数的形参就是要传递过来的数据
*/




// 子传父
let getId = function(id){
    console.log(id)
}
</script>

<template>

    
<div class="box">
    根组件
    <!-- 在父组件的子组件标签上绑定自定义事件 -->
    <SonCom  @sentId="getId"></SonCom>

</div>

</template>


<style scoped>
.box{
    background-color: red;
    height: 400px
}

</style>

4.跨级组件通信 发布订阅

步骤

1、下载pubsub-js npm i pubsub-js
2、订阅者(接收数据的组件)先订阅 PubSub.subscribe(“变量名”,(msg,data){ })
3、发布者(向外传递数据的组件)发布消息 PubSub.publish(“变量名”,value)

App.vue

<script setup>
import { ref, reactive, onMounted } from "vue"
import PubSub from 'pubsub-js'
import Father from "./components/Father.vue";

/* 
跨级组件通信   发布订阅   ,可用于任何关系的组件之间
跨级组件通信  发布订阅模式实现数据传递,步骤:
1、下载pubsub-js    npm i pubsub-js   
2、订阅者(接收数据的组件)先订阅    PubSub.subscribe("变量名",(msg,data){     })
3、发布者(向外传递数据的组件)发布消息   PubSub.publish("变量名",value)
*/

let Num = ref(99)

onMounted(() => {
    PubSub.publish("Num", Num.value)
})
</script>

<template>
    <div style="background-color: red;height: 800px;width: 600px;margin: 0 auto;">
        爷爷组件
        爷爷组件的Num:{{ Num }}
        <button @click="Num++">++</button>
        <Father></Father>

    </div>
</template>
<style scoped></style>

Father.vue

<script setup>
import { ref, reactive } from "vue"
import Son from "./Son.vue";

</script>

<template>
    <div style="background-color: blue;height: 200px;">父组件
        <Son></Son>
    </div>

</template>
<style scoped>
</style>

Son.vue

<script setup>
import { ref, reactive, onMounted } from "vue"
import PubSub from 'pubsub-js'

let newNum = ref()
onMounted(() => {
    PubSub.subscribe("Num", (msg, date) => {
        newNum.value = date
    })
})

</script>

<template>
    <div style="background-color: chartreuse;">
        孙组件
        根组件传递过来的Num{{ newNum }}
    </div>

</template>

<style scoped></style>

7 插槽

定义

slot 翻译为插槽,插槽的目的是让我们原来的设备具备更多的扩展性

组件的插槽,也是为了让我们封装的组件更加具有扩展性,让使用者可以决定组件内部的一些内容到底展示什么

插槽的三种类型

  • 默认插槽 default
  • 具名插槽 name
  • 作用域插槽 v-slot

在子组件中:

  • 插槽用 <slot> 标签来确定渲染的位置,里面放的是父组件没传内容时的后备内容,一个不带 name 的 <slot> 出口会带有隐含的名字 default
  • 具名插槽用 name 属性来表示插槽的名字
  • 作用域插槽在作用域上绑定属性来将子组件的信息传给父组件使用

1.默认插槽

顾名思义,插槽没有名字 用slot标签代表插槽内容,

插槽没有命名,或者命名为default 插槽可以重复调用的

​ 语法:

​ 父组件

默认插槽

​ 子组件

2.具名插槽

有名字的插槽,名字不能是default

​ 语法:

​ 定义插槽内容 <template v-solt:插槽名>插槽内容

​ 使用插槽

​ 语法糖:

​ <template #插槽名>

​ 插槽内容

3.作用域插槽

定义插槽内容(在父组件中定义)的时候,想使用子组件中的数据,这种插槽叫作用域插槽

​ 定义:

{{ slotprops.acg }}

​ 语法糖:

​ <template #slot3=“slotprops”>

{{ slotprops.acg }}

​ 使用:

​ <slot name=“slot3” :acg=“acg” …可定义多个>

案例

App.vue

<script setup>
import { ref, reactive, onMounted } from "vue"
import Son from "./components/Son.vue";
import Son2 from "./components/Son2.vue";
import Son3 from "./components/Son3.vue";
</script>

<template>
    <div style="background-color: red;height: 800px;width: 600px;margin: 0 auto;">
        根组件
        <Son>
            <!-- 默认插槽 -->
            <!-- <h1>QWERUIOP</h1> -->
            <!-- 默认插槽的完整形式 -->
            <template v-slot:default>
                <h1>默认插槽</h1>
            </template>
        </Son>

        <Son2>

            <!-- 具名插槽 -->
            <template v-slot:GGBond>
                <h1>
                    我是具名插槽
                </h1>
            </template>
            <template #FFQueen>
                <p>我是具名插槽语法糖</p>
            </template>
            
        </Son2>

        <Son3>
            <!-- 作用域插槽 -->
            <template #slot3="slotprops">
                <h1>{{ slotprops.acg }}</h1>
            </template>
        </Son3>
    </div>


</template>


<style scoped></style>

Son.vue

<script setup>
import { ref, reactive, onMounted } from "vue"
</script>

<template>
    <div style="background-color: chartreuse;">
        子组件

        <!-- 默认插槽 -->
        <slot></slot>
        <slot></slot>
        <slot></slot>
    </div>
</template>

<style scoped></style>

Son2.vue

<script setup>
import { ref, reactive, onMounted } from "vue"
</script>

<template>
    <div style="background-color: blue;">
        子组件2
        <slot name="GGBond"></slot>
        <slot name="GGBond"></slot>
        <slot name="GGBond"></slot>
        <slot name="FFQueen"></slot>
        <slot name="FFQueen"></slot>
        <slot name="FFQueen"></slot>
        <slot name="FFQueen"></slot>
    </div>
</template>

<style scoped></style>

Son3.vue

<script setup>
import { ref, reactive, onMounted } from "vue"
let acg = ref(789)
</script>

<template>
    <div style="background-color: pink;">
        子组件3
        <slot name="slot3" :acg="acg"></slot>
    </div>
</template>

<style scoped></style>

8 路由 vue-router

1.路由的基本使用

vue-router 是基于路由和组件的,路由用于设定访问路径,将路径和组件映射起来

前端路由:一个url路径对应一个页面.vue文件

路由实现的步骤

  1. 下载vue-router

    npm i vue-roter

  2. 创建路由模块.js文件

    src/router/index.js(xxx.js)

  3. 在路由模块里创建路由对象并导出

    index.js

    /* 路由模块
        在该模块创建路由对象并导出
    */
    import HomeView from "../views/HomeView.vue"
    import AboutView from "@/views/AboutView.vue";
    
    //创建路由对象的步骤
    //1.引入createRouter,createWebHashHistory
    import { createRouter, createWebHashHistory } from "vue-router";
    
    //2.配置路由表 本质上是一个数组,里面存放路由对象
    // .vue文件需要自定义   src/views/xxx.vue
    const routes = [
        //配置默认路由
        {
            path:"/",
            redirect:"/home",//路由重定向
        },
        {
            path: "/home",
            name: "home",
            component: HomeView
        },
        {
            path: "/about",
            name: "about",
            component: AboutView
        },
        {
            path: "/cars",
            name: "cars",
            // 路由懒加载
            component: import("@/views/CarsView.vue")
        }
    ]
    
    //3.创建路由对象并导出
    
    const router = createRouter({
        // routes:routes,   //路由表  简写 routes, === routes:routes,
        routes,
        history:createWebHashHistory()        //路由模式 history模式
    })
    
    export default router;
    
  4. 在main.js中引入路由对象 并注册
    // import './assets/main.css'
    
    import { createApp } from 'vue'
    import App from './App.vue'
    
    //导入路由对象
    import router from "./router/index.js"
    
    
    let app = createApp(App)
    //注册路由
    app.use(router)
    app.mount('#app')
    
  5. 使用路由 (声明式路由 和 编程式路由)
    1. 声明式路由

      ​ 路由跳转组件:

      ​ 路由显示组件:

      ​ 本质上是一个a标签

      <script setup>
      import { ref, reactive } from "vue"
      import { RouterLink, RouterView } from "vue-router"
      </script>
      
      <template>
          <div class="Abox">
              <div class="Abox1">
                  <RouterLink to="/home">首页</RouterLink>
                  <RouterLink to="/about">关于</RouterLink>
                  <RouterLink to="/cars">购物车</RouterLink>
              </div>
              <div>
                  <!-- 路由组件显示的位置 放在哪在哪显示 -->
                  <RouterView></RouterView>
              </div>
          </div>
      </template>
      
      
      <style scoped>
      .Abox1 a{
          color: black;
          text-decoration: none;
          display: inline-block;
          margin: 30px;
          height: 30px;
          line-height: 30px;
      }
      
      /*路由被激活时,自动添加的类名 router-link-active, 可以设置激活样式*/
      .Abox1 .router-link-active{
      color: red ;
      background-color :pink;
      }
      
      </style>
      
    2. 编程式路由

    ​ 在js中实现路由跳转

    ​ 1.首先引用useRouter函数 import { useRouter } from “vue-router”;

    ​ 2.获取路由实例对象 const router = useRouter() //路由对象

    ​ 3.调用路由实例对象的方法.push进行跳转

    <script setup>
    import { ref, reactive } from "vue"
    import { useRouter } from "vue-router";
    
    const router = useRouter()  //路由对象
    
    let goHome = ()=>{
        console.log(router); //路由实例对象 用来进行路由跳转
        // 常用的方法:push("url路径") back()返回上一页  go(1)下一个 go(-1)上一个 和back效果一样
        router.push("/home")
    
    }
    </script>
    
    <template>
        <h1>购物车</h1>
        <button @click="goHome">返回首页</button>
        <!-- <a href="/home">返回首页</a> -->
    
    </template>
    
    <style scoped></style>
    

2.路由传参

路由传参:有两种方式,1.query传参;2.params动态传参

1.query传参

传参:把参数以?隔开拼接到url路径

​ 例如:跳转到个人中心页面的同时传递参数id 值100

​ 1) 声明式路由 个人中心

​ (2)编程式路由 router.push(/profile?id=${id.value})

​ 接参:使用useRoute 获取当前路由信息 通过route.query.id获取传递过来的id值

2.params动态传参

例如:跳转到购物车页面同时传递一个参数money=9999

​ 路由注册时: //动态传参 path:'/cars/:money" index.js文件里修改

​ 传参:

​ 1) 声明式路由

​ 购物车

​ (2)编程式路由

​ router.push(“/cars/78787”)

​ 接参:使用useRoute获取当前路由信息通过route.params.money获取传递过来的id值

useRouter 和 useRoute的区别

  1. useRouter获取路由实例对象,用来进行路由跳转

​ 例如: import{useRouter} from ‘vue-router’

​ const router = useRouter;

​ router.push(“url路径”) //进行路由跳转

  1. useRoute 获取当前路由信息 一般用来获取路由传参

​ 例如: import{useRoute} from ‘vue-router’

​ const route = useRoute;

​ router.query.id 或者 route.params.id

案例

App.vue 传递参数

<script setup>
import { ref, reactive } from "vue"
import { RouterLink, RouterView } from "vue-router"
</script>

<template>
    <div class="Abox">
        <div class="Abox1">
            <RouterLink to="/home">首页</RouterLink>
            <RouterLink to="/about">关于</RouterLink>
            <!-- params动态传参 声明式路由  -->
            <RouterLink to="/cars/999">购物车</RouterLink>
            <RouterLink to="/ProFile?id=100">个人中心</RouterLink>
        </div>
        <div>
            <!-- 路由组件显示的位置 放在哪在哪显示 -->
            <RouterView></RouterView>
        </div>
    </div>
</template>

<style scoped>
.Abox1 a {
    color: black;
    text-decoration: none;
    display: inline-block;
    margin: 30px;
    height: 30px;
    line-height: 30px;
}

/*路由被激活时,自动添加的类名 router-link-active, 可以设置激活样式*/
.Abox1 .router-link-active {
    color: red;
    background-color: pink;
}
</style>

ProFileView.vue query传参的对象 声明式路由 接收参数

<script setup>
import { ref } from "vue"
import { useRoute } from "vue-router";
const route = useRoute(); //route代表当前路由的实例信息 一般用来获取路由传参 route.query.属性名  就是传递过来属性的值
console.log(route.query.id)

</script>

<template>
    <div>个人中心</div>
</template>

<style scoped></style>

HomeView.vue query传参的对象 编程式路由

<script setup>
import { ref, reactive } from "vue"
import { useRouter } from "vue-router";

const router = useRouter()  //路由对象
let id = ref(456)
let toProFile = function(){
    router.push(`/ProFile?id=${id.value}`) //多个&连接
}
</script>

<template>
    <h1>首页</h1>
    <button @click="toProFile">跳转个人中心</button>

</template>

<style scoped></style>

params动态传参 在index.js里配置

/* 路由模块
    在该模块创建路由对象并导出
*/
import HomeView from "../views/HomeView.vue"
import AboutView from "@/views/AboutView.vue";
import ProFileView from "@/views/ProFileView.vue"

//创建路由对象的步骤
//1.引入createRouter,createWebHashHistory
import { createRouter, createWebHashHistory } from "vue-router";

//2.配置路由表 本质上是一个数组,里面存放路由对象
// .vue文件需要自定义   src/views/xxx.vue
const routes = [
    //配置默认路由
    {
        path:"/",
        redirect:"/home",//路由重定向
    },
    {
        path: "/home",
        name: "home",
        component: HomeView
    },
    {
        path: "/about",
        name: "about",
        component: AboutView
    },
    {	//params动态传参 App.vue里直接传入999就是money的值
        //<RouterLink to="/cars/999">购物车</RouterLink>
        path:'/cars/:money',
        name: "cars",
        // 路由懒加载
        component: import("@/views/CarsView.vue")
    },{
        path:"/ProFile",
        name:"ProFile",
        component:ProFileView
    }
]

//3.创建路由对象并导出

const router = createRouter({
    // routes:routes,   //路由表  简写 routes, === routes:routes,
    routes,
    history:createWebHashHistory()        //路由模式 history模式
})
export default router;

CarsView.app 接参 params动态传参

<script setup>
import { ref, reactive } from "vue"
import { useRouter,useRoute } from "vue-router";

const route = useRoute()  //当前路由的实力信息 
console.log(route.params.money)//输出接收到的参数money=999

</script>

<template>
    <h1>购物车</h1>
    <button @click="goHome">返回首页</button>
    <!-- <a href="/home">返回首页</a> -->

</template>


<style scoped></style>

AboutView.app 传参编程式路由

<script setup>
import { ref, reactive } from "vue"
import { useRouter,useRoute } from "vue-router";
 //params动态传参 编程式式路由  
const router = useRouter()
let tocars = function(){
    router.push("/cars/78787")
}
</script>

<template>
    <h1>关于</h1>
    <button @click="tocars">购物车页面</button>
</template>


<style scoped></style>

3.路由嵌套

步骤

​ 1.创建二级路由的组件

​ 2.在路由对象里添加二级路由 在要添加二级路由的对象里新增children属性

index.js

/* 路由模块
    在该模块创建路由对象并导出
*/

import { name } from "pubsub-js";
import { createRouter, createWebHashHistory } from "vue-router";

const routes = [
    {
        path: "/",
        redirect: "/home"
    },
    {
        path: "/home",
        name: "home",
        component: import("../views/HomeView.vue"),
        children: [
            //二级路由的默认路由
            {
                path: '',
                redirect: "/home/usersmanage" //url要写全
            },
            {
                //path后面的路径不要带杠
                path: "ordermanage",
                name: "ordermanage",
                component: import("../views/home/OrderManage.vue")
            },
            {
                path: "usersmanage",
                name: "usersmanage",
                component: import("../views/home/UsersManage.vue")
            },
            {
                path: "systemmanage",
                name: "systemmanage",
                component: import("../views/home/SystemManage.vue")
            },
            {
                path: "datacount",
                name: "datacount",
                component: import("../views/home/DataCount.vue")
            }
        ]
    },
    {
        path: "/about",
        name: "about",
        component: import("../views/AboutView.vue")
    },
    {
        path: "/set",
        name: "set",
        component: import("../views/SetView.vue")
    },
    {
        path:"/login",
        name:"login",
        component:import("../views/Login.vue")
    }
]

//3.创建路由对象并导出

const router = createRouter({
    // routes:routes,   //路由表  简写 routes, === routes:routes,
    routes,
    history: createWebHashHistory()        //路由模式 history模式
})

export default router;

​ 3.在相对应的一级路由的组件里使用二级路由

这里一级路由是HomeView.app

<script setup>
import { ref, reactive } from "vue"
import { useRouter } from "vue-router";

</script>

<template>
    <div class="home">
        <div class="aside">
            <RouterLink to="/home/usersmanage">用户管理</RouterLink>
            <RouterLink to="/home/ordermanage">订单管理</RouterLink>
            <RouterLink to="/home/systemmanage">系统管理</RouterLink>
            <RouterLink to="/home/datacount">数据统计</RouterLink>
        </div>
        <div class="main">
            <RouterView></RouterView>
        </div>

    </div>

</template>


<style scoped>
.home .aside {
    width: 200px;
    height: 800px;
    background-color: #ccc;
    float: left;
    padding-top: 30px;
    box-sizing: border-box;
}

.aside a {
    display: block;
    height: 30px;
    line-height: 30px;
    text-decoration: none;
    color: black;
    text-align: center;
    border-bottom: 1px solid gray;

}

.aside .router-link-active {
    background-color: red;
}

.home .main {
    width: 800px;
    height: 800px;
    float: left;
    background-color:rgba(9, 181, 212, 0.914);
    text-align: center;
}

.home {
    position: relative;
    height: 800px
}

.login {
    position: absolute;
}
</style>

9 多页面状态管理pinia

vue 已经帮我们做好了单个界面的状态管理,但是如果是多个界面呢?

多页面状态管理,即多个页面都共用某一个数据,那么状态管理工具用什么呢?

pinia的使用步骤:

1、下载 npm i pinia

2、创建pinia仓库模块 src/store/index.js

3、在main.js中,引入并注册pinia仓库

4、在组件中使用

1.pinia状态管理工具的使用方法一(了解)

1、创建pinia仓库(了解)

import {defineStore} from "pinia"
const useUserStore = defineStore("user",{
  
    // state初始化数据
    state:()=>{
        return {
            num:999,
            password:"123456",
            user:{
                uname:'admin',
                age:30,
            }
        }
    },
    // 计算属性  ---类似于computed
    getters:{
        getSum(state){
            return state.num *100;
        }
    },
    // 修改状态的方法
    // 定义修改状态的方法
    actions:{
        addnum(n){
            this.num=this.num+n
        }
    }
})
export default useUserStore

2、在main.js中导入(了解)

// import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'

//导入路由对象
import router from "./router/index.js"

//导入pinia对象
import { createPinia } from 'pinia'
const pinia = createPinia()


let app = createApp(App)
//注册路由
app.use(router)//注册路由
app.use(pinia) //注册pinia
app.mount('#app')


3、在页面中使用pinia仓库中的数据(了解)

<script setup>
import { ref, reactive } from "vue"
//使用pinia中的数据
import useUserStore from "@/store";
//创建pinia仓库实例对象
const store = useUserStore();
console.log(store.num)
console.log(store.password)

let numadd = function(){
    //2.调用store仓库里actions的方法,前提是需要在acyions定义修改数据的方法
    store.addnum(5)
}

</script>

<template>
   
   <h1>aaaaa</h1>
   <h1>num:{{ store.num }}</h1>
   <h1>password:{{ store.password }}</h1>
   <!-- 1.直接修改num的值 -->
   <button @click="store.num++">num+1</button>
   <button @click="numadd">addnum</button>

</template>


<style scoped>
</style>

2.pinia状态管理工具使用方法2(重点掌握)

1.在src/store/index.js中创建pinia仓库,并初始化

import {defineStore} from "pinia"
import {ref,computed} from 'vue'
const useUserStore = defineStore("index",()=>{
    //定义响应式数据
    const count = ref(9)
    //定义计算属性
    //const doubleCount = computed(()=>count.value*2)
    const doubleCount = computed(()=>{return(count.value)*2})
    //定义修改数据的方法
    function changeCount(){
        count.value--
    }
    return {count,doubleCount,changeCount}
})
export default useUserStore

2.在main.js中引入并注册,同第一种方法的

3.在组件中使用仓库中的数据

<script setup>
import { ref, reactive } from "vue"
//使用pinia中的数据
import useUserStore from "@/store";
//创建pinia仓库实例对象
const store = useUserStore();
console.log(store.count)

</script>

<template>
   <h1>方法2</h1>
   <h1>count:{{ store.count }}</h1>
   <button @click="store.count++">1count++</button>
   <br>
   <h1>doubleCount:{{ store.doubleCount }}</h1>
   <br>
   <button @click="store.changeCount">count--</button>
</template>

<style scoped>
</style>

10 网络请求axios

axios类似于原生的ajax、 jquery中的ajax等,都是用用来向后端发送请求拿去数据的。

  • **axios(config)**
  • **axios.request(config)**
  • axios.get(url[, config])
  • axios.delete(url[, config])
  • axios.head(url[, config])
  • axios.post(url[, data[, config]])
  • axios.put(url[, data[, config]])
  • axios.patch(url[, data[, config]])

1、axios发送请求

axios的使用步骤:

1、下载 npm i axios

2、引入 并使用

<script setup>
import { ref } from "vue";
// axios的使用步骤:
// 1、下载  npm i  axios
// 2、引入   并使用
import axios from "axios";
import { onMounted } from "vue";
const menus = ref([]);
onMounted(() => {
  // 获取首页数据
  axios
    .get("https://apif.java.crmeb.net/api/front/index")
    .then((res) => {
      console.log(1);
      console.log(res);
      console.log(res.data.data.menus);
    // 把请求过来的数据,更新到本组件的数据上,就可渲染到页面上了
      menus.value = res.data.data.menus;
    })
    .catch((err) => {
      console.log(err);
    });

  // 获取商品分类数据
  axios
    .get("https://apif.java.crmeb.net/api/front/category")
    .then((res) => {
      console.log(res);
      console.log(2);
    })
    // 捕获异常
    .catch((err) => {
      console.log(err);
    });
});
// 处理多个异步操作
// 如果有多个请求,需要同步操作  可以使用async  await
onMounted(async ()=>{
    const res = await axios.get("https://apif.java.crmeb.net/api/front/category")
    console.log(res)

    const res2 = await axios.get("https://apif.java.crmeb.net/api/front/index")
    console.log(res2)
})
</script>
<template>
  <div>购物车页面</div>
  <div style="" class="menus">
    <div
      v-for="(item, index) in menus"
      :key="index"
      style="width: 80px; height: 100px"
    >
      <img :src="item.pic" />
      <div>{{ item.name }}</div>
    </div>
  </div>
</template>
<style>
.menus{
    display:flex;
    flex-wrap:wrap;
    justify-content:space-between;
}
</style>

2、axios的封装

1、首次封装 新建axios的网络请求模块 src/utils/http.js

import axios from "axios"
import { inputNumberEmits } from "element-plus"
import {getToken,removeToken} from "./token.js"
import router from "../router/index.js"



axios.defaults.baseURL = "http://vapi.youlai.tech/api/v1/"

// 请求拦截
axios.interceptors.request.use((config)=>{
    // 请求成功的拦截  可以做token登录认证
    const token = getToken()
    if(token){
        config.headers.Authoriation = token
    }else{
        return config
    }
    return config

},(err)=>{
    // 请求失败的拦截
    return Promise.reject(err)

})


// 响应成功的拦截
axios.interceptors.response.use((res)=>{
    //处理无效token  进行数据过滤 
    if(res.data.msg=="token无效或已过期"){
        // 表示token过期
        removeToken()  //清空token
        // 跳转到登录页面
        router.push("/login")
    }
    return res.data
},(err)=>{
    return Promise.reject(err)
})




// 封装请求方法
export const http = (url,method,params)=>{
    return new Promise((resolve,reject)=>{
        axios({
            url:url,
            method:method,
            params:params,   //参数
            // params:method==="get"?params:null,
            // data:method !=="get"?params:null,
        }).then(res=>{
            resolve(res)
        })
    })
    
}

2、二次封装 src/api/index.js

img

3、在组组件中测试

img

img

不完整接口:

https://docs.apipost.cn/preview/eda898270b2e68d6/013ffbe1cd7bdd41/?target_id=3cb7f592-397c-4e54-8d70-ddfe237726c0 这是丰享荟对应的接口地址,不一定全,可以作为参考使用。

项目参考:

https://java.crmeb.net/static/html/pc.html 丰享荟移动端项目参考地址

11 ui组件 element-plus的使用

参考官网:https://element-plus.org/zh-CN/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值