文章目录
- 一、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 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
为了方便记忆,我们可以将他们分类:
- 创建时:
beforeCreate
、created
- 渲染时:
beforeMount
、mounted
- 更新时:
beforeUpdate
、updated
- 卸载时:
beforeUnmount
、unmounted
回到目录…
四、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 API | Hook inside setup |
---|---|
beforeCreate | Not needed* |
created | Not needed* |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeUnmount | onBeforeUnmount |
unmounted | onUnmounted |
在 setup() 中可以定义多个相同的生命周期函数,并且在周期内都会执行。
export default {
setup() {
onMounted(() => {
console.log('业务一')
})
onMounted(() => {
console.log('业务二')
})
}
}
回到目录…
九、Element-plus
官网:Element Plus, 面向设计师和开发者的组件库
安装 Element-Plus:npm 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-components
和 unplugin-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组件。之后的学习内容将持续更新!!!