Vue3 详细教程

news2024/11/24 11:50:07

文章目录

  • 一、API 风格
    • 1.1 选项式 API
    • 1.2 组合式 API
  • 二、Vue 指令
    • 2.1 {{}} 文本插值
    • 2.2 v-html 标签元素
    • 2.3 v-on 绑定事件
    • 2.4 v-show 隐藏元素
    • 2.5 v-if 消除元素
    • 2.6 v-bind 属性渲染
    • 2.7 v-for 列表渲染
    • 2.8 v-model 数据双向绑定
  • 三、组件
    • 3.1 组件组合
    • 3.2 Props 组件交互
    • 3.3 自定义事件组件交互
    • 3.4 组件生命周期
  • 四、Vue 引入第三方 Swiper
  • 五、Axios 网络请求库
    • 5.1 基本使用
    • 5.2 Axios 网络请求封装
    • 5.3 网络请求跨域解决方案
  • 六、Vue Router 路由
    • 6.1 引入路由
    • 6.2 根据URL参数路由
    • 6.3 多级路由嵌套
  • 七、Vuex 状态管理
    • 7.1 State 数据存储
    • 7.2 Getter 数据过滤
    • 7.3 Mutation 数据更改
    • 7.4 Action 异步更改
  • 八、Vue3 组合式 API
    • 8.1 ref 和 reactive
    • 8.2 setup() 定义方法
    • 8.3 props 和 context
    • 8.4 Provide 和 Inject
    • 8.5 setup中生命周期钩子
  • 九、Element-plus
    • 9.1 加载组件
    • 9.2 加载字体图标


提示:以下是本篇文章正文内容,前端系列学习将会持续更新

在这里插入图片描述
官网:https://cn.vuejs.org

一、API 风格

1.1 选项式 API

使用选项式 API,我们可以用包含多个选项的对象来描述组件的逻辑,例如 data、methods 和 mounted。选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例。

<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>

<script>
  export default {
    data() {
      return {
        count: 0
      }
  	},
    methods: {
      increment() {
        this.count++
      }
    },
    mounted() {
      // 该函数就会在组件挂载完成后被调用
      // 一般进行网络请求,重新渲染数据
    }
  }
</script>

1.2 组合式 API

通过组合式 API,我们可以使用导入的 API 函数来描述组件逻辑。在单文件组件中,组合式 API 通常会与 <script setup> 搭配使用。这个 setup attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API。比如,<script setup> 中的导入和顶层变量/函数都能够在模板中直接使用。

下面是使用了组合式 API 与 <script setup> 改造后和上面的模板完全一样的组件:

<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>

<script setup>
  import { ref, onMounted } from 'vue'

  // 响应式状态
  const count = ref(0)

  // 用来修改状态、触发更新的函数
  function increment() {
    count.value++
  }

  // 生命周期钩子
  onMounted(() => {
    console.log(`The initial count is ${count.value}.`)
  })
</script>

回到目录…

二、Vue 指令

在这里插入图片描述

2.1 {{}} 文本插值

  • {{}} 的作用是:文本替换,内部可以计算数值
<template>
  <h2>{{ message }}世界</h2>      <!-- 你好!世界 -->
  <h2>{{ age + 1 }}</h2>    <!-- 13 -->
</template>
<script>
  export default {
    data() {
      return {
        message: "你好!",
        age: 12
      }
    }
  }
</script>

2.2 v-html 标签元素

  • v-html 指令的作用是:设置元素的 innerHTML
  • 内容中有 html 结构会被解析为标签。
  • 解析文本使用 {{}},需要解析 html 结构使用 v-html。
<template>
  <p v-html="message"></p>  <!-- <p><a href='https://www.baidu.com'>百度百科</a></p> -->
</template>
<script>
  export default {
    data() {
      return {
        message: "<a href='https://www.baidu.com'>百度百科</a>"
      }
    }
  }
</script>

2.3 v-on 绑定事件

  • v-on 指令的作用是:为元素绑定事件,包括:blur, focus, focusin, focusout, load, resize, scroll, unload, click, dblclick, mousedown, mouseup, mousemove, mouseover, mouseout, mouseenter, mouseleave,change, select, submit, keydown, keypress, keyup, error。
  • v-on 指令可以简写为 @,如 v-on:click="func()" 等同于 @click="func()"
  • 绑定的方法定义在 methods 属性中,方法内部通过 this 关键字可以访问定义在 data 中的数据。
<template>
  <p>{{message}}</p>
  <input type="button" value="触发事件1" v-on:click="func">
  <input type="button" value="触发事件2" @click="func2('张三')">
</template>
<script>
  export default {
    data() {
      return {
        message: "Hello,World!"
      }
    },
    methods: {
      func() {
        alert(this.message);
      },
      func2(name) {
        alert("你好," + name);
      }
    }
  }
</script>

2.4 v-show 隐藏元素

  • v-show 指令的作用是:根据真假切换元素的显示状态
  • v-show 原理是修改元素的 display 值,实现显示和隐藏。其值最终会解析为布尔值 (true元素显示,false元素隐藏)。
  • 数据改变之后,对应元素的显示状态会同步更新。
<template>
  <div v-show="isShow">模块一</div>
  <div v-show="num > 10">模块二</div>
</template>
<script>
  export default {
    data() {
      return {
        isShow: false,
        num: 18
      }
    }
  }
</script>

2.5 v-if 消除元素

  • v-if 指令的作用是:根据表达式的真假切换元素的显示状态
  • 本质是通过操纵 dom 元素来切换显示状态。表达式值为true时,元素存在于dom树中;值为false时,从dom树中移除。
  • 频繁的切换使用 v-show,反之使用 v-if,前者的切换消耗小。
<template>
  <div v-if="isShow">模块一</div>
  <div v-if="num > 10">模块二</div>
</template>
<script>
  export default {
    data() {
      return {
        isShow: false,
        num: 18
      }
    }
  }
</script>

2.6 v-bind 属性渲染

  • v-bind 指令的作用是:为元素绑定属性
  • v-bind 指令可简写为 : ,如 v-bind:src="imgSrc" 等同于 :src="imgSrc"
  • 需要动态的增删 class 时,建议使用对象的方式。
<template>
  <a v-bind:href="myHref">百度百科</a>
  <input type="button" :value="myVal">
</template>
<script>
  export default {
    data() {
      return {
        myHref: "https://www.baidu.com",
        myVal: "我的按钮"
      }
    }
  }
</script>

2.7 v-for 列表渲染

  • v-for 指令的作用是:根据数据生成列表结构。经常和数组结合使用。
  • v-for 语法是 item in arr(item,index) in arr,item 和 index 可以结合其他指令一起使用。
  • 当数组长度发生改变时,更新会同步到页面上,是响应式的。但它默认使用 “就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序。为了让 Vue 能跟踪每个节点的身份,从而重新排序现有元素,我们需要为 v-for 渲染的元素添加一个唯一的 key(可以使用index,但建议使用动态数据的唯一ID)
<template>
  <ul>
    <li v-for="item in vegetables">菜品:{{ item.name }}, 价格:{{ item.price }}</li>
  </ul>
  <p v-for="(it,index) in arr" :key="it.id|index">{{ index+1 }}.{{ it }}</p>
</template>
<script>
  export default {
    data() {
      return {
        arr:["北京","上海","广州","深圳"],
        vegetables:[
          {name:"西兰花炒蛋", price:20},
          {name:"蛋炒西蓝花", price:30}
        ]
      }
    }
  }
</script>

2.8 v-model 数据双向绑定

  • v-model 指令的作用是便捷的设置和获取表单元素的值
  • 绑定的数据会和表单元素值相关联,绑定的数据 <=> 表单元素的值。
<template>
  <input type="text" v-model="message">
  <p>动态修改massage值: {{ message }}</p>
</template>
<script>
  export default {
    data() {
      return {
        message:"沙丁鱼"
      }
    }
  }
</script>

回到目录…

三、组件

在这里插入图片描述

3.1 组件组合

①单文件组件(又名 *.vue 文件,缩写为 SFC) 是一种特殊的文件格式,它允许将 Vue 组件的模板逻辑样式封装在单个文件中。

<template>
  <h2>我的单文件组件</h2>
</template>

<script>
  export default {
    name: "MyComponent"
  }
</script>

<style scoped>  <!-- scoped表示只改变该文件的模板样式 -->
  h2 {
    color: red;
  }
</style>

②加载组件
第一步:引入组件 import MyComponent from './components/MyComponent.vue'
第二步:挂载组件 components: { MyComponent }
第三步:显示组件 <MyComponent/>

<template>
  <h2>APP.vue的二级标题</h2>
  <MyComponent/>
</template>

<script>
  import MyComponent from './components/MyComponent.vue';
  export default {
    name: "APP",
    components: {
      MyComponent
    }
  }
</script>

查看效果
在这里插入图片描述

③组件的组织:通常一个应用会以一棵嵌套的组件树的形式来组织。
在这里插入图片描述

回到目录…

3.2 Props 组件交互

  • 父组件向子组件传递数据,Props 可以在组件上注册的一些自定义属性将数据传给子组件。

①传递属性:父组件向子组件传递属性值。

父组件:App.vue

<template>
  <h2>APP.vue的二级标题</h2>
  <MyComponent :title="title" :arr="arr"/>
</template>

<script>
  import MyComponent from './components/MyComponent.vue';
  export default {
    name: "APP",
    data() {
      return {
        title: "传递字符串",
        arr: ["zhangsan","lisi","wangwu"]
      }
    },
    components: {
      MyComponent
    }
  }
</script>

子组件:MyComponent.vue

<template>
  <h2>Props 组件交互</h2>
  <p>{{ title }}</p>
  <p v-for="(item,index) in arr" :key="index">{{ item }}</p>
</template>

<script>
  export default {
    name: "MyComponent",
    props: {
      title: {
        type: String, //数据类型
        default: ""   //默认值
      },
      arr: {
        type: Array,
        default: function() {
          return [];
        }
      }
    }
  }
</script>

②Prop 类型:Prop传递参数其实是没有类型限制的。

注意:数据类型为数组或者对象的时候,默认值是需要返回工厂模式 (使用函数返回)。

props: {
  title: String, // 字符串类型
  likes: Number, // 数字类型
  isPublished: Boolean, // 布尔类型
  commentIds: Array, // 数组类型
  author: Object, // 对象类型
  callback: Function // 函数类型
}

回到目录…

3.3 自定义事件组件交互

  • 子组件向父组件传递数据,自定义事件可以在组件中反向传递数据。

子组件:MyComponent.vue

<template>
  <h2>自定义事件组件交互</h2>
  <input type="button" value="发送数据" @click="sendData">
</template>

<script>
  export default {
    name: "MyComponent",
    methods: {
      sendData() {
        // 参数一: 接收数据的事件名称,参数二: 发送的数据
        this.$emit("onEvent", {name:"zhangsan",age:18});
      }
    }
  }
</script>

父组件:App.vue

<template>
  <h2>APP.vue的二级标题</h2>
  <MyComponent @onEvent="getData"/>
</template>

<script>
  import MyComponent from './components/MyComponent.vue';
  export default {
    name: "APP",
    components: {
      MyComponent
    },
    methods: {
      getData(student) {
        alert("姓名:" + student.name + ",年龄:" + student.age);
      }
    }
  }
</script>

回到目录…

3.4 组件生命周期

每个组件在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。

在这里插入图片描述

为了方便记忆,我们可以将他们分类:

  • 创建时: beforeCreatecreated
  • 渲染时: beforeMountmounted
  • 更新时: beforeUpdateupdated
  • 卸载时: beforeUnmountunmounted

回到目录…

四、Vue 引入第三方 Swiper

在这里插入图片描述

  • 官方文档:https://swiperjs.com/vue
  • Swiper 开源、免费、强大的触摸滑动插件。
  • Swiper 是纯 JavaScript 打造的滑动特效插件,面向手机、平板电脑等移动终端。
  • Swiper 能实现触屏焦点图、触屏 Tab 切换、触屏轮播图切换等常用效果。

①安装指定版本: npm install --save swiper@8.1.6

②基础实现

<template>
    <div class="hello">
        <swiper class="mySwiper" :modules="modules" :pagination="{ clickable:true }">
            <swiper-slide><img src="../assets/1.png"></swiper-slide>
            <swiper-slide><img src="../assets/2.png"></swiper-slide>
            <swiper-slide><img src="../assets/3.png"></swiper-slide>
        </swiper>
    </div>
</template>

<script>
import { Swiper, SwiperSlide } from 'swiper/vue'; //核心组件
import { Pagination } from 'swiper'; //指示器组件
import 'swiper/css';
import 'swiper/css/pagination';

export default {
    name: "HelloWorld",
    data() {
        return {
            modules: [Pagination]
        }
    },
    components: {
        Swiper,
        SwiperSlide
    }
}
</script>

<style scoped>
    img {
        width: 100%;
    }
</style>

效果展示
在这里插入图片描述

回到目录…

五、Axios 网络请求库

官网:https://github.com/axios/axios

在这里插入图片描述

5.1 基本使用

①安装依赖

# Axios 需要单独安装 
npm install --save axios
# post 请求参数是需要额外处理,安装依赖; 参数转换格式: qs.stringify({})
npm install --save querystring

②组件中引入import axios from "axios"

③GET请求

axios({
    method: "get",
    url: "http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php"
}).then(res => {
    console.log(res.data);
})
axios.get("http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php")
.then(res => {
	console.log(res.data);
})

④POST请求

axios({
    method: "post",
	url: "http://iwenwiki.com/api/blueberrypai/login.php",
    data: qs.stringify({
        user_id: "iwen@qq.com",
        password: "iwen123",
        verification_code: "crfvw"
    })
}).then(res =>{
    console.log(res.data);
})
axios.post("http://iwenwiki.com/api/blueberrypai/login.php", qs.stringify({
	user_id: "iwen@qq.com",
	password: "iwen123",
    verification_code: "crfvw"
})).then(res => {
	console.log(res.data);
})

回到目录…

5.2 Axios 网络请求封装

在实际应用过程中,一个项目中的网络请求会很多,此时一般采取的方案是将网络请求封装起来。

①我们先创建 src/utils/request.js 文件,用来存储网络请求对象 axios。
参考文档:Axios 看云

import axios from "axios"
import qs from "querystring"

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(info); break;
    }
}

const instance = axios.create({
    timeout:5000 // 网络请求的公共配置: 请求超时时间
})

// 发送数据前的拦截器
instance.interceptors.request.use(
    config => {
        if(config.method === "post") {
            config.data = qs.stringify(config.data);
        }
        return config; // 包括网络请求的所有信息
    },
    error => Promise.reject(error)
)
// 获取数据前的拦截器
instance.interceptors.response.use(
    response => response.status === 200 ? Promise.resolve(response) : Promise.reject(response),
    error => {
        const { response } = error;
        errorHandle(response.status, response.info);
    }
)

export default instance;

②创建 src/api/path.js 用来存放网络请求路径;创建 src/api/index.js 用来存放网络请求路径

// path.js
const base = {
    baseUrl:"http://iwenwiki.com",
    chengpin:"/api/blueberrypai/getChengpinDetails.php"
}
export default base
// index.js
import path from "./path"
import axios from "../utils/request"

export default {
    getChengpin() {
        return axios.get(path.baseUrl + path.chengpin);
    }
}

③在组件中直接调用网络请求

<script>
import api from './api/index';
export default {
    name: "APP",
    mounted() {
        api.getChengpin().then(res => {
            console.log(res.data);
        })
    }
}
</script>

回到目录…

5.3 网络请求跨域解决方案

JS 采取的是同源策略。同源策略是浏览器的一项安全策略,浏览器只允许 js 代码请求当前所在服务器的域名、端口、协议相同的数据接口上的数据,这就是同源策略
也就是说,当协议、域名、端口任意一个不相同时,都会产生跨域问题,所以又应该如何解决跨域问题呢?

跨域错误提示信息:http://iwenwiki.com/api/FingerUnion/list.php
在这里插入图片描述
目前主流的跨域解决方案有两种:后台解决:cors;前台解决:proxy

①我们找到父工程下的 vue.config.js 或 vite.config.js 文件,向它的 defineConfig 项中添加以下配置:

// vue.config.js配置
devServer: {
  proxy: {
  '/api': {
    target: 'http://xxxxxxxxxxx.xxx/api',
    changOrigin: true,
    pathRewrite: {
      '^/api': ''
    }
  }
}
// vite.config.js配置
server: {
  proxy: {
    '/api': {
      target: 'http://iwenwiki.com/api', // 凡是遇到 /api 路径的请求,都映射到 target 属性
      changeOrigin: true,
      rewrite: path => path.replace(/^\/api/, '') // 重写 /api 为 空,就是去掉它
    }
  }
}

②如何访问跨域的地址?

mounted() {
  // 使用'/url'代替域名部分即可
  axios.get("/api/FingerUnion/list.php")
  .then(res => {
    console.log(res.data);
   })
}

注意:解决完跨域配置之后,要记得重启服务器才行哦!

回到目录…

六、Vue Router 路由

官方文档:https://router.vuejs.org/zh

在这里插入图片描述

在 Vue 中,我们可以通过 vue-router 路由管理页面之间的关系,Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让 Vue.js 构建单页应用变得轻而易举。

6.1 引入路由

第一步:安装路由 npm install --save vue-router

第二步:配置独立的路由文件 src/router/index.js

import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
    {
        path: '/',
        name: 'home',
        component: Home
    },
    {
        path: '/about',
        name: 'about',
        component: () => import('../views/About.vue') //异步加载方式
    }
]

const router = createRouter({
    /**
     * createWebHashHistory
     *      home: http://localhost:5176/#/
     *      about: http://localhost:5176/#/about
     * 原理: a标签锚点链接
     * 
     * createWebHistory, 此种方式需要后台配合做重定向,否则会出现404问题
     *      home: http://localhost:5176/
     *      about: http://localhost:5176/about
     * 原理: HTML5的pushState()
     */
    history: createWebHashHistory(),
    routes
})

export default router

第三步:引入路由到项目,在 src/main.js 中添加 use(router)

import './assets/main.css'

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

createApp(App).use(router).mount('#app')

第四步:指定路由显示入口、路由跳转

<template>
  <nav>
    <RouterLink to="/">主页</RouterLink> | 
    <router-link to="/about">关于</router-link>
  </nav>
  <RouterView></RouterView> <!-- 路由跳转入口 -->
</template>

在这里插入图片描述

回到目录…

6.2 根据URL参数路由

页面跳转过程中,是可以携带参数的,这也是很常见的业务,比如我们的分页功能、商品项详情。

第一步:在路由配置中指定参数的 key

{
    path: '/news/details/:name',
    name: 'newsdetails',
    component: () => import('../views/NewsDetails.vue') //对应新闻详情页
}

第二步:在跳转过程中携带参数

<template>
    <h1>News页面</h1>
    <ul>
        <li><RouterLink to="/news/details/百度">百度新闻</RouterLink></li>
        <li><RouterLink to="/news/details/新浪">新浪新闻</RouterLink></li>
        <li><RouterLink to="/news/details/网易">网易新闻</RouterLink></li>
    </ul>
</template>

第三步:在详情页面读取路由携带的参数

<template>
    <h1>新闻详情</h1>
    <p>{{ $route.params.name }}</p>
</template>

在这里插入图片描述

回到目录…

6.3 多级路由嵌套

路由嵌套是十分常见的需求,比如二级导航。
在这里插入图片描述

第一步:创建子路由要加载显示的页面
关于我们的页面:src/views/aboutsub/AboutUS.vue
更多信息的页面:src/views/aboutsub/AboutInfo.vue

第二步:在路由配置文件中添加子路由配置

{
	path: '/about',
    name: 'about',
    redirect: '/about/us', //重定向到指定的子路由
    component: () => import('../views/About.vue'),
    children: [
        {
            path: 'us', //子路由不加'/'
            component: () => import('../views/aboutsub/AboutUS.vue')
        },
        {
            path: 'info',
            component: () => import('../views/aboutsub/AboutInfo.vue')
        }
    ]
}

第三步:指定子路由显示位置、跳转链接

<template>
    <h1>About页面</h1>
    <RouterLink to="/about/us">关于我们</RouterLink> | 
    <RouterLink to="/about/info">更多信息</RouterLink>
    <RouterView></RouterView>
</template>

在这里插入图片描述

回到目录…

七、Vuex 状态管理

官方文档:https://vuex.vuejs.org/zh/index.html
在这里插入图片描述
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

简单来说,状态管理可以理解成为了更方便的管理组件之间的数据交互,提供了一个集中式的管理方案,任何组件都可以按照指定的方式进行读取和改变数据。

如何引入Vuex?

第一步:安装Vuex npm install --save vuex

第二步:配置Vuex文件,创建 src/store/index.js

import { createStore } from 'vuex'
// Vuex的作用就是帮助我们管理组件之间的状态的
export default createStore({
    state: {
        // 所有状态(数据)都存储在这里
    },
    getters: {
        // 可以通过这里的方法进行数据过滤
    },
    mutations: {
        // 数据更改
    },
    actions: {
        // 数据异步更改
    }
})

第三步:在 main.js 主文件中引入Vuex

import store from './store'
createApp(App).use(store).mount('#app')

回到目录…

7.1 State 数据存储

①所有数据存储在 state 中:

state: {
	num: 13
}

②在组件中读取数据:

<p>{{ $store.state.num }}</p>

或者

<template>
  <p>{{ num }}</p>
</template>

<script>
  import { mapState } from 'vuex';
  export default {
    name: "APP",
    computed: {
      ...mapState(['num'])
    }
  }
</script>

回到目录…

7.2 Getter 数据过滤

①对 Vuex 中的数据进行过滤:

getters: {
	getNum(state) {
		return state.num>18 ? state.num : '未成年'
    }
}

②在组件中获取过滤后的数据:

<p>{{ $store.getters.getNum }}</p>

或者

<template>
  <p>{{ num }}</p>
  <p>{{ getNum }}</p>
</template>

<script>
  import { mapState, mapGetters } from 'vuex';
  export default {
    name: "APP",
    computed: {
      ...mapState(['num']),     // 直接获取数据
      ...mapGetters(['getNum']) // 获取过滤数据
    }
  }
</script>

回到目录…

7.3 Mutation 数据更改

Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type) 和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。

①更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。

mutations: {
	incrNum(state) {
		state.num++
	},
    addNum(state,n) {
        state.num += n
    }
}

②在组件中通过触发事件来修改数据:

<template>
  <button @click="onEvent">修改数据</button>
  <button @click="onEvent2">修改数据2</button>
</template>

<script>
  export default {
    name: "APP",
    methods: {
      onEvent() {
        this.$store.commit('incrNum')
      },
      onEvent2() {
        this.$store.commit('incrNum', 10)
      }
    }
  }
</script>

或者

<template>
  <button @click="onEvent3">修改数据3</button>
</template>

<script>
  import { mapState, mapGetters, mapMutations } from 'vuex';
  export default {
    name: "APP",
    methods: {
      ...mapMutations(['addNum']),
      onEvent3() {
        this.addNum(20)
      }
    }
  }
</script>

回到目录…

7.4 Action 异步更改

Action 类似于 mutation,实际上 Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作。

①对 Vuex 中的数据进行异步更改

mutations: {
    addNum(state,n) {
        state.num += n
    }
},
actions: {
	asyncAddNum({ commit }) {
        axios.get('http://iwenwiki.com/api/generator/list.php')
        .then(res => {
            commit('addNum', res.data[0]) // 调用mutations中的方法
        })
    }
}

②在组件中通过触发事件来进行异步修改:

<template>
  <button @click="asyncEvent">异步修改</button>
</template>

<script>
  export default {
    name: "APP",
    methods: {
      asyncEvent() {
        this.$store.dispatch('asyncAddNum')
      }
    }
  }
</script>

或者

<template>
  <button @click="asyncEvent2">异步修改2</button>
</template>

<script>
  import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
  export default {
    name: "APP",
    methods: {
      ...mapActions(['asyncAddNum']),
      asyncEvent2() {
        this.asyncAddNum()
      }
    }
  }
</script>

回到目录…

八、Vue3 组合式 API

  • Vue3 是目前 Vue 的最新版本,自然也是新增了很多新特性。
  • Performance:性能更比 Vue 2.0 强。
  • Tree shaking support:可以将无用模块“剪辑”,仅打包需要的。
  • Composition API:组合 API。
  • Fragment, Teleport, Suspense:“碎片”,Teleport 即 Protal 传送门,“悬念”。
  • Better TypeScript support:更优秀的Ts支持。
  • Custom Renderer API:暴露了自定义渲染 API。

8.1 ref 和 reactive

  • ref 通常用来定义基本类型数据;reactive 通常用来定义对象或数组类型数据。
  • ref 也可以用来定义对象或者数组类型的数据,内部会通过 reactive 转为代理对象。
<template>
  <div id="app">
    <p>{{ message }}</p>
    <p v-for="(item,index) in citys.arr" :key="index">{{ item }}</p>
    <p v-for="(item,index) in list" :key="index">{{ item }}</p>
    <p>{{ citys.age }}</p>
  </div>
</template>

<script>
import {ref, reactive} from 'vue'
export default {
  setup() {
    const message = ref('张三')
    const list = ref(['a','b','c'])
    const citys = reactive({
      arr: ['北京','上海','广州','深圳'],
      age: 18
    })
    return {
      message,
      citys,
      list
    }
  }
}
</script>

回到目录…

8.2 setup() 定义方法

  • 在 setup() 中不仅可以定义数据,还可以定义方法 (以lamada表达式的方式)。
  • 在 setup() 中定义的数据和方法,都需要使用 return 返回才能被调用。
<template>
  <div id="app">
    <button @click="onEvent">不带参数</button>
    <button @click="onEvent2('张三')">携带参数</button>
    <button @click="changeData">修改数据</button>
  </div>
</template>

<script>
import {ref, reactive} from 'vue'
export default {
  setup() {
    const onEvent = () => {
      alert('触发事件');
    }
    const onEvent2 = (arg) => {
      alert(arg);
    }
    const changeData = () => {
      message.value = '李四'
    }
    return {
      onEvent,
      onEvent2,
      changeData
    }
  }
}
</script>

回到目录…

8.3 props 和 context

在2.x中,组件的方法中可以通过this获取到当前组件的实例,并执行 data 变量的修改,方法的调用,组件的通信等等,但是在3.x中,setup() 在 beforeCreate 和 created 时机就已调用,无法使用和2.x一样的 this,但是可以通过接收 setup(props,ctx) 的方法,获取到当前组件的实例和 props。

父组件发送数据

<template>
  <div id="app">
    <Home title="哈哈"/>
  </div>
</template>

<script>
import Home from './views/Home.vue'
export default {
    components: { Home }
}
</script>

子组件接收数据:props 的新用法。

<template>
    <h1>Home页面</h1>
    <p>{{ title }}</p>
</template>

<script>
export default {
    name: 'home',
    props: {
        title: String
    },
    setup(props) {
        const title = props.title
        return {
            title
        }
    }
}
</script>

子组件发送数据:setup() 中取消了 this 关键字,而是用 context 代替。

<template>
    <h1>Home页面</h1>
    <input type="button" value="发送数据" @click="sendData">
</template>

<script>
export default {
    name: 'home',
    setup(props,ctx) {
        const sendData = () => {
            ctx.emit("onEvent", {name:"zhangsan",age:18});
        }
        return {
            sendData
        }
    }
}
</script>

父组件接收数据

<template>
  <div id="app">
    <Home @onEvent="getData"/>
  </div>
</template>

<script>
import Home from './views/Home.vue'
export default {
	components: { Home },
    setup() {
        const getData = (student) => {
          alert("姓名:" + student.name + ",年龄:" + student.age);
        }
        return {
            getData
        };
    }
}
</script>

回到目录…

8.4 Provide 和 Inject

  • provide() 和 inject() 可以实现嵌套组件之间的数据传递,这两个函数只能在 setup() 函数中使用。
  • 父级组件中使用 provide() 函数向下传递数据;子级组件中使用 inject() 获取上层传递过来的数据。
  • 不限层级。
// 父组件
import {provide} from 'vue'
import Home from './views/Home.vue'
export default {
    components: { Home },
    setup() {
        provide('num', 18);
    }
}
// 子组件
import { inject } from 'vue';
export default {
    setup() {
        const num = inject('num')
        return {
            num
        }
    }
}

回到目录…

8.5 setup中生命周期钩子

Options APIHook inside setup
beforeCreateNot needed*
createdNot needed*
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted

在 setup() 中可以定义多个相同的生命周期函数,并且在周期内都会执行。

export default {
  setup() {
    onMounted(() => {
      console.log('业务一')
    })
    onMounted(() => {
      console.log('业务二')
    })
  }
}

回到目录…

九、Element-plus

官网:Element Plus, 面向设计师和开发者的组件库
在这里插入图片描述

安装 Element-Plusnpm install element-plus --save

9.1 加载组件

方式一:完整引用,如果你对打包后的文件大小不是很在乎,那么使用完整导入会更方便。

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

import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

createApp(App).use(ElementPlus).mount('#app')

方式二:按需导入才是我们的最爱,毕竟在真实的应用场景中并不是每个组件都会用到,这会造成不小的浪费。

①首先你需要安装 unplugin-vue-componentsunplugin-auto-import 这两款插件。

npm install -D unplugin-vue-components unplugin-auto-import

②然后修改 vue.config.js 或 vite.config.js 配置文件

// vue.config.js
const { defineConfig } = require('@vue/cli-service')
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')

module.exports = defineConfig({
  transpileDependencies: true,
  configureWebpack: {
    plugins: [
      AutoImport({
        resolvers: [ElementPlusResolver()]
      }),
      Components({
        resolvers: [ElementPlusResolver()]
      })
    ]
  }
})
// vite.config.js
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      resolvers: [ElementPlusResolver()]
    }),
    Components({
      resolvers: [ElementPlusResolver()]
    })
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})

回到目录…

9.2 加载字体图标

在这里插入图片描述

第一步:安装 icons 字体图标

npm install @element-plus/icons-vue

第二步:全局注册,创建 src/plugins/icons.js 文件,添加以下内容

import * as components from "@element-plus/icons-vue";
export default {
    install: (app) => {
        for (const key in components) {
            const componentConfig = components[key];
            app.component(componentConfig.name, componentConfig);
        }
    }
};

第三步:引入文件,在 main.js 中引入 icons.js 文件

import elementIcon from "./plugins/icons"
createApp(App).use(elementIcon).mount('#app')

第四步:直接复制代码即可

<el-icon><CirclePlus /></el-icon>

回到目录…


总结:
提示:这里对文章进行总结:
本文是对Vue的学习,学习了Vue的选项式API和组合式API,组件之间的交互,引入swiper第三方插件,网络请求封装,还有Router路由,Vuex状态管理,加载Element-plus组件。之后的学习内容将持续更新!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/560006.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux:命令date、ntp查看和修改(校准)时间和地区。

Linux&#xff1a;命令date、ntp查看和修改&#xff08;校准&#xff09;时间和地区。 date -d 不仅可以1还可以加其他数字&#xff0c;表达后多久&#xff0c;-表达前多久&#xff1a; 备注&#xff1a;中国所在的时区是东八区 单独使用date时&#xff0c;会出现一串内容&…

Linux驱动入门——基础概念

文章目录 Linux内核简介Unix的历史Linux简介操作系统和内核简介单内核与微内核设计之比较小结 设备驱动简介驱动程序的角色划分内核设备和模块的分类安全问题版权条款 Linux驱动开发概述驱动程序概述设备驱动程序的作用设备驱动的分类Linux操作系统与驱动的关系Linux驱动开发编…

小程序容器技术在构建超级App的技术价值

今年来&#xff0c;随着软件及开源技术的发展&#xff0c;软件应用架构的概念也随之流行起来。它提供了一种组织和设计软件系统的有效方法&#xff0c;具有许多优势和好处&#xff1a; 模块化和可维护性&#xff1a;软件应用架构将系统拆分为模块化的组件&#xff0c;每个组件…

linux 部署jenkins

安装Jenkins 使用wget 命令下载Jenkins 先安装wget yum install wget ,如果已经安装过了&#xff0c;忽略直接到下一步; 若你的java环境为11~17&#xff0c;可以执行&#xff1a;wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war 若你的java环境为8&#xff0…

Python实战基础10-正则表达式

1、正则表达式 在处理字符串时&#xff0c;经常会有查找符合某些复杂规则的字符串需求。正则表达式就算用于描述这些规则的工具。换句话说&#xff0c;正则表达式就是记录文本规则的代码。 1.1 行定位符 行定位符就是用来描述字符串的边界&#xff0c;“A”表示行的开始&…

2023新星导师活动【electron+vue3】方向,开营知识点提纲(2)

文章目录 前言一、vue是什么&#xff1f;二、vue的优势1.依托数据渲染2.新人的边界2.选项式和组合式 总结 前言 上篇文章主要讲解了electron、nodejs的相关概念。本篇文章将主要介绍vue3&#xff0c;以及vue3如何与electron协作完成桌面端功能。 同上篇文章一样&#xff0c;这…

系统集成项目管理工程师 下午 真题 及考点(2019年上半年)

文章目录 一&#xff1a;第10章 项目质量管理&#xff0c;规划质量管理输出&#xff0c;质量成本法&#xff08;一致性成本【预防、评价】 和 非一致性成本【内部失败、外部失败】&#xff09;&#xff0c;七种工具二&#xff1a;第8章 项目进度管理&#xff0c;总浮动时间&…

2023高频前端面试题合集之网络篇

近期整理了一下高频的前端面试题&#xff0c;分享给大家一起来学习。如有问题&#xff0c;欢迎指正&#xff01; 欢迎大家关注该专栏&#xff1a;点赞&#x1f44d; 收藏&#x1f91e; 大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&…

数据结构学习分享之链式二叉树(二)

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:数据结构学习分享⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你了解更多数据结构的知识   &#x1f51d;&#x1f51d; 数据结构第八课 1. 前言&a…

ClickHouse:(二)数据类型

1.整型 固定长度的整型分为&#xff1a;有符号和无符合整型 有符号整型无符号整型类型范围类型范围Int8 -128 : 127 UInt8 0 : 255 Int16 -32768 : 32767 UInt16 0 : 65535 Int32 -2147483648 : 2147483647 UInt32 0 : 4294967295 Int64 -9223372036854775808 : 9223372036854…

SpringSecurity框架|荣耀磨练

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开兴好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…

Unity之使用Photon Server + PUN2 开发局域网多人游戏

一.前言 Photon Engine是一款跨平台的实时多人游戏引擎,它提供了可靠的基础设施和工具,使开发者能够轻松地构建和部署多人游戏。Photon Engine支持多种平台,包括PC、移动设备和Web,同时还提供了多种语言的SDK,如C++、C#、Java、JavaScript等,使得开发者可以使用自己熟悉…

多元回归预测

多元回归就像线性回归&#xff08;一个变量预测一个值&#xff09;一样&#xff0c;但是具有多个独立值&#xff0c;这意味着我们试图基于两个或多个变量来预测一个值。 比如在线性回归中我们可以根据发动机排量的大小预测汽车的二氧化碳排放量&#xff0c;但是通过多元回归&a…

Kotlin泛型<in, out, where>概念及示例

Kotlin泛型<in, out, where>概念及示例 在 Kotlin 中&#xff0c;泛型用于指定类、接口或方法可以操作的对象类型。 in in关键字用于指定泛型类型是“输入”类型&#xff0c;这意味着它将仅用作函数或类的参数。 interface ReadOnly {fun read(): Any }class ReadW…

设计模式期末复习随笔

1.以下是23种GOF设计模式对应的设计原则&#xff1a; 工厂方法模式&#xff08;Factory Method Pattern&#xff09;&#xff1a;遵循开闭原则&#xff0c;客户端不需要修改就能够新增产品类型。 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;&#xff1a;遵…

【严重】Kibana 8.7.0 任意代码执行漏洞

漏洞描述 Kibana是用于Elasticsearch的数据可视化仪表板。Kibana在8.7.0版本引入了Synthetic监控功能&#xff0c;用户可配置编写playwright中的javascript代码实现web应用监控。 具备Kibana登录权限的攻击者可利用此功能编写恶意playwright脚本&#xff0c; 从而在Kibana主机…

5.28 深圳活动|Jina AI 生态助力云原生场景下的 AIGC 应用开发

亚马逊云科技 Community Day 将于 5 月 28 日 在深圳南山区海德酒店 11 楼举办&#xff0c;Jina AI 软件工程师付杰将带来 《Jina AI 生态助力云原生场景下的 AIGC 应用开发》 的主题演讲。 Community Day 是亚马逊云科技全球品牌和社区旗舰活动&#xff0c;由社区领导者发起&a…

5个替代Zendesk的全面指南!

Zendesk是一种广受欢迎的客户支持软件解决方案&#xff0c;适用于各种规模的企业。然而&#xff0c;还有其他几种产品可以取代Zendesk&#xff0c;提供类似甚至更好的功能。在本文中&#xff0c;我们将探索市场上一些最好的Zendesk替代方案。 1、Zoho Desk Zoho Desk是一款基…

SpringBoot拦截器-解决java.io.IOException: Stream closed问题

1.SpringBoot拦截器是什么 SpringBoot拦截器和过滤器是Spring Boot的一种机制&#xff0c;用于对请求和响应进行操作的拦截&#xff0c;是AOP编程的一种体现。该方法可以在不改变代码基本业务和逻辑的前提下对SpringBoot的一些操作进行拦截、过滤和更改。 SpirngBoot拦截器&a…

检错纠错理论——海明码与海明距离

概念解释 先说明几个概念&#xff08;非严谨定义&#xff09; 码字&#xff1a;一个包含了数据位和校验位的n位单元&#xff0c;也就是“一种”编码 编码&#xff1a;由码字组成的可以表达传递信息的集合&#xff0c;这里不是指编码的过程&#xff0c;而是一个名词。一个编码…