Vue3
目录结构


模版语法
使用 JavaScript 表达式
在我们的模板中,我们一直都只绑定简单的 property 键值,Vue.js 都提供了完全的 JavaScript 表达式支持
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
这些表达式会在当前活动实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。
<!-- 这是语句,不是表达式:-->
{{ var a = 1 }}
<!-- 流程控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}
原始 HTML
双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用v-html 指令
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
data(){
return{
rawHtml:"<a href='https://www.itbaizhan.com'>百战</a>"
}
}
属性 Attribute
Mustache 语法不能在 HTML 属性中使用,然而,可以使用 v-bind 指令
<div v-bind:id="dynamicId"></div>
data(){
return{
dynamicId:1001
}
}
温馨提示
v-bind:可以简写成:
条件渲染
v-if
v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 true 值的时候被渲染。
<p v-if="flag">我是孙猴子</p>
data() {
return {
flag: true
}
}
v-else
你可以使用 v-else 指令来表示 v-if 的“else 块”
<p v-if="flag">我是孙猴子</p>
<p v-else>你是傻猴子</p>
data() {
return {
flag: false
}
}
v-show
另一个用于条件性展示元素的选项是 v-show 指令
<h1 v-show="ok">Hello!</h1>
v-if vs v-show 的区别
v-if 是“真正”的条件渲染,因为它会确保在切换过程中,条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好
Class 与 Style 绑定

绑定 HTML class
普通对象使用



Style绑定


计算属性的使用
列表渲染
v-for
用 v-for 把一个数组映射为一组元素
我们可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。
<ul>
<li v-for="item in items">{{ item.message }}</li>
</ul>
data() {
return {
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
维护状态
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一的 key attribute:
<div v-for="(item,index) in items" :key="item.id|index">
<!-- 内容 -->
</div>
数组变化侦测
Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括:
push()pop()shift()unshift()splice()sort()reverse()


v-for 与对象

事件处理
监听事件
我们可以使用 v-on 指令 (简写为 @) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click="handler" 或 @click="handler"。
事件处理器 (handler) 的值可以是:
-
内联事件处理器:事件被触发时执行的内联 JavaScript 语句 (与
onclick类似)。<button @click="counter += 1">Add 1</button>data() { return { counter: 0 } } -
方法事件处理器:一个指向组件上定义的方法的属性名或是路径。
然而许多事件处理逻辑会更为复杂,所以直接把 JavaScript 代码写在
v-on指令中是不可行的。因此v-on还可以接收一个需要调用的方法名称。<button @click="greet">Greet</button>methods: { greet(event) { // `event` 是原生 DOM event if (event) { alert(event.target.tagName) } } }
事件修饰符


按键修饰符
计算属性

侦听器


表单事件

复选框

单选框

选项框

多选框

修饰符


模版引用
dom操作

组件基础
使用组件
<script>
import ButtonCounter from './ButtonCounter.vue'
export default {
components: {
ButtonCounter
}
}
</script>
<template>
<h1>Here is a child component!</h1>
<ButtonCounter />
</template>
组件注册

父传子组件传值prop
组件与组件之间是需要存在交互的,否则完全没关系,组件的意义就很小了
Prop 是你可以在组件上注册的一些自定义 attribute
<my-componentVue :title="标题"/>
<template>
<h3>单文件组件</h3>
<p>{{ title }}</p>
</template>
<script>
export default {
name:"MyComponent",
props:{
title:{
type:String,
default:""
}
}
}
</script>
动态数据(父传子 )

Prop 类型
Prop传递参数其实是没有类型限制的 prop是只读的
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function
}
温馨提示
数据类型为数组或者对象的时候,默认值是需要返回工厂模式

子组件向父组件传值
组件事件

子组件:

父组件:

父子组件的访问方式

组合事件和v-model一起使用

组件数据传递prop 子传父
子组件

父组件

插槽
双标签 ,之前的是单标签

父组件:

子组件:

通过插槽来分配内容
具名插槽
子组件有多个插槽

父组件:

子组件:

简写:

渲染作用域

备用内容
作用插槽域

插槽使用父子组件的数据:
普通方式:
父组件:

子组件:

具名方式
父组件:

子组件:

组件之间的跨级通信(依赖注入)
将数据传递得更深:

privide 和 inject

祖先:

孙子:

生命周期钩子


应用
获取dom:

异步组件:

vue应用

组合式API

Vue3新特性1
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
ref或者reactive
在2.x中通过组件data的方法来定义一些当前组件的数据
data() {
return {
name: 'iwen',
list: [],
}
}
在3.x中通过ref或者reactive创建响应式对象
import { ref,reactive } from "vue"
export default {
name: 'HelloWorld',
setup(){
const name = ref("iwen")
const state = reactive({
list:[]
})
return{
name,
state
}
}
}
methods中定义的方法写在setup()
在2.x中methods来定义一些当前组件内部方法
methods:{
http(){}
}
在3.x中直接在setup方法中定义并return
setup() {
const http = ()=>{
// do something
}
return {
http
};
}
setup()中使用props和context
在2.x中,组件的方法中可以通过this获取到当前组件的实例,并执行data变量的修改,方法的调用,组件的通信等等,但是在3.x中,setup()在beforeCreate和created时机就已调用,无法使用和2.x一样的this,但是可以通过接收setup(props,ctx)的方法,获取到当前组件的实例和props
export default {
props: {
name: String,
},
setup(props,ctx) {
console.log(props.name)
ctx.emit('event')
},
}
响应式 API
- 响应式 API:例如
ref()和reactive(),使我们可以直接创建响应式状态、计算属性和侦听器。 - ref() 基础类型
- reactive() 引用类型

torefs 响应式

在setup 中使用watch
基础类型

引用类型 watchEffect

使用watch

生命周期函数
Vue3新特性2
在setup中使生命周期函
你可以通过在生命周期钩子前面加上 “on” 来访问组件的生命周期钩子。
下表包含如何在 setup () 内部调用生命周期钩子
| Options API | Hook inside setup |
|---|---|
| beforeCreate | Not needed* |
| created | Not needed* |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeUnmount | onBeforeUnmount |
| unmounted | onUnmounted |
export default {
setup() {
// mounted
onMounted(() => {
console.log('Component is mounted!')
})
}
}
Provide / Inject
- provide() 和 inject() 可以实现嵌套组件之间的数据传递。
- 这两个函数只能在 setup() 函数中使用。
- 父级组件中使用 provide() 函数向下传递数据。
- 子级组件中使用 inject() 获取上层传递过来的数据。
- 不限层级
// 父组件
import { provide } from "vue"
setup() {
provide("customVal", "我是父组件向子组件传递的值");
}
// 子组件
import { inject } from "vue"
setup() {
const customVal = inject("customVal");
return {
customVal
}
}
Fragment
Fragment翻译为:“碎片”
- 不再限于模板中的单个根节点
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App" />
</template>
setup函数中的参数prop
父传子

setup函数中的参数 context
听懵逼了、
provide和inject
< script setup>
script setup 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。

vue-router
Vue引入路由配置(初级)
在Vue中,我们可以通过vue-router路由管理页面之间的关系
Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举
在Vue中引入路由
第一步:安装路由 npm install --save vue-router
第二步:配置独立的路由文件
// index.js
import { createRouter, createWebHashHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue')
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
export default router
第三步:引入路由到项目
// main.js
import router from './router'
app.use(router)
第四步:指定路由显示入口 <router-view/>
第五步:指定路由跳转
<router-link to="/">Home</router-link> |
<router-link to="/about">About</router-link>
路由传递参数
页面跳转过程中,是可以携带参数的,这也是很常见的业务
例如:在一个列表项,点击进入查看每个列表项的详情
第一步:在路由配置中指定参数的key
{
path:"/list/:name",
name:"list",
component:() => import("../views/ListView.vue")
}
第二步:在跳转过程中携带参数
<li><router-link to="/list/内蒙">内蒙旅游十大景区</router-link></li>
<li><router-link to="/list/北京">北京旅游十大景区</router-link></li>
<li><router-link to="/list/四川">四川旅游十大景区</router-link></li>
第三步:在详情页面读取路由携带的参数
<p>{{ $route.params.name }}城市旅游景区详情</p>
基础使用
路由表
index.js
import {
createRouter,
createWebHashHistory,
createWebHistory
} from 'vue-router'
// 1. 定义路由组件.
// 也可以从其他文件导入
// 静态导入
// import Home from '../views/Home.vue'
import About from '../views/About.vue'
import User from '../views/User.vue'
import NotFound from '../views/NotFound.vue'
import News from '../views/News.vue'
import Parent from '../views/Parent.vue'
import StyleOne from '../views/StyleOne.vue'
import StyleTwo from '../views/StyleTwo.vue'
import Page from '../views/Page.vue'
import ShopTop from '../views/ShopTop.vue'
import ShopMain from '../views/ShopMain.vue'
import ShopFooter from '../views/ShopFooter.vue'
// 路由懒加载,用到时再加载
const Home=()=>import('../views/Home.vue')
// 2. 定义一些路由
// 每个路由都需要映射到一个组件。
// 我们后面再讨论嵌套路由。
const routes = [{
path: "/",
// 重定向
// redirect:'/home'
// 命名路由
// redirect:{name:"home"}
// 方法
redirect: (to) => {
// console.log(to);
return {
path: "/home"
}
}
},
{
path: '/home',
name: "home",
component: Home
},
{
path: '/about',
component: About,
// 每路守卫(路由独享的守卫)
beforeEnter:(to,from,next)=>{//token
console.log(to);
console.log(from);
if(123 === 123453){
next()
}
}
},
{
// 动态路由
path: '/user/:id',
component: User,
props: true
},
{
// 动态路由的参数一定是数字
// path: "/news/:id(\\d+)",
// 有多个参数 +
// path: "/news/:id+",
// 参数可有可无 * ,参数可以重复叠加
name: "news",
path: "/news/:id*",
// 参数可有可无 ? ,但是参数不可以重复叠加
// path: "/news/:id?",
component: News
},
{
path: "/parent",
alias: ['/father', '/fuqin'], //起别名
component: Parent,
children: [{
path: "styleone",
component: StyleOne
},
{
path: "styletwo",
component: StyleTwo,
}
],
},
{
path: "/page",
component: Page
},
{
path: "/shop/:id",
components: {
default: ShopMain,
// 它们与 `<router-view>` 上的 `name` 属性匹配
ShopTop: ShopTop,
ShopFooter: ShopFooter
},
props: {
default: true,
ShopFooter: true,
ShopTop: false
}
},
{
// 404页面
//使用正则的方式,匹配任意的
path: '/:path(.*)',
component: NotFound
},
]
// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置,但我们在这里
// 暂时保持简单
const router = createRouter({
// 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
// history: createWebHashHistory(),
// history模式,二者区别,有无#
history: createWebHistory(),
routes, // `routes: routes` 的缩写
})
// 全局守卫
// router.beforeEach((to,from,next)=>{
// console.log(to);
// console.log(from);
// next()//通行证
// })
export default router
使用
<script>
export default{
data(){
return {
list:[]
}
}
}
</script>
<template>
<div>
<!-- vue-router是基于路由和组件的,路由是用来设定访问路径,将路径和组件映射起来, -->
<h1>Hello App!</h1>
<router-view name="ShopTop"></router-view>
<router-view></router-view>
<p>
<!--使用 router-link 组件进行导航 -->
<!--通过传递 `to` 来指定链接 -->
<!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签-->
<!-- 使用一个自定义组件 router-link 来创建链接。这使得 Vue Router 可以在不重新加载页面的情况下更改 URL,处理 URL 的生成以及编码 -->
<!-- to="路径" -->
<router-link to="/">Go to Home</router-link>
<router-link to="/about">Go to About</router-link>
<router-link to="/user/123">Go to User</router-link>
<!-- <router-link to="/news/456">Go to News</router-link> -->
<router-link :to="{name:'news',params:{id:456}}">Go to News</router-link>
<router-link to="/parent">Go to Parent</router-link>
<router-link to="/page">Go to Page</router-link>
</p>
<!-- 路由出口,占位符 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view name="ShopFooter"></router-view>
</div>
</template>
<style>
</style>
挂载
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app=createApp(App)
app.use(router)
app.mount('#app')
动态路由
路由表
{
// 动态路由
path: '/user/:id',
component: User,
props: true
},
组件
<template>
<div>用户</div>
</template>
<!---<script>
export default {
props:['id'],
mounted(){
// $route表示当前活跃的路由对象
console.log(this.$route.params.id);
console.log(this.id);
}
}
</script>
--->
<script setup>
import {useRoute} from 'vue-router'
console.log(useRoute().params.id);
const props= defineProps({
id:String
})
console.log(props.id);
</script>
404路由
路由表
{
// 404页面
//使用正则的方式,匹配任意的
path: '/:path(.*)',
component: NotFound
},
路由正则和重复参数
路由正则 重复参数
{
// 动态路由的参数一定是数字
// path: "/news/:id(\\d+)",
// 有多个参数 +
// path: "/news/:id+",
// 参数可有可无 * ,参数可以重复叠加
name: "news",
path: "/news/:id*",
// 参数可有可无 ? ,但是参数不可以重复叠加
// path: "/news/:id?",
component: News
},
嵌套路由配置

路由嵌套是非常常见的需求
第一步:创建子路由要加载显示的页面
第二步:在路由配置文件中添加子路由配置
{
path:"/news",
name:"news",
redirect:"/news/baidu",
component:() => import("../views/NewsView.vue"),
children:[
{
path:"baidu",
component:() => import("../views/NewsList/BaiduNews.vue"),
},
{
path:"wangyi",
component:() => import("../views/NewsList/WangyiNews.vue"),
}
]
}
第三步:指定子路由显示位置<router-view></router-view>
第四步:添加子路由跳转链接
<router-link to="/news/baidu">百度新闻</router-link> |
<router-link to="/news/wangyi">网易新闻</router-link>
第五步:重定向配置 redirect:"/news/baidu"
{
path: "/parent",
alias: ['/father', '/fuqin'], //起别名
component: Parent,
children: [{
path: "styleone",
component: StyleOne
},
{
path: "styletwo",
component: StyleTwo,
}
],
},
js跳转
<template>
<div>
<h2>Page页面</h2>
<button @click="goPage">跳转页面</button>
</div>
</template>
<script>
export default {
methods: {
goPage: function () {
// console.log(this.$router);
// if(123==1221343){
// this.$router.push('/')
// 通过传入对象
// this.$router.push({path:"/"})
// 带参数
// this.$router.push({path:"/user/123456"})
// this.$router.push({name:"news",params:{id:123456}})
// 带问号
this.$router.push({path:"/about",query:{name:"zhangsan"}})
//替换当前位置
// this.$router.push({ path: "/about", query: { name: "zhangsan" },replace:true });
// this.$router.replace({path:"/about",query:{name:"zhangsan"}})
// }
},
},
};
</script>
接受
<template>
<div>
<div>about</div>
<button @click="goBack">后退</button>
</div>
</template>
<script>
export default {
mounted(){
console.log(this.$route.query.name);
},
methods:{
goBack(){
// 前进,传入为正值,后退,传入的值则为负值
// this.$router.go(-1)
this.$router.back()//后退,等于go(-1)
this.$router.forword()//前进,等于go(1)
}
},
}
</script>
替换页面
export default {
methods: {
goPage: function () {
// console.log(this.$router);
// if(123==1221343){
// this.$router.push({ path: "/about", query: { name: "zhangsan" },replace:true });
// this.$router.replace({path:"/about",query:{name:"zhangsan"}})
// }
},
},
};
历史页面
<template>
<div>
<div>about</div>
<button @click="goBack">后退</button>
</div>
</template>
<script>
export default {
mounted(){
console.log(this.$route.query.name);
},
methods:{
goBack(){
// 前进,传入为正值,后退,传入的值则为负值
// this.$router.go(-1)
this.$router.back()//后退,等于go(-1)
this.$router.forword()//前进,等于go(1)
}
},
}
</script>
命名路由
命名
{
// 动态路由的参数一定是数字
// path: "/news/:id(\\d+)",
// 有多个参数 +
// path: "/news/:id+",
// 参数可有可无 * ,参数可以重复叠加
name: "news",
path: "/news/:id*",
// 参数可有可无 ? ,但是参数不可以重复叠加
// path: "/news/:id?",
component: News
},
使用
<router-link :to="{name:'news',params:{id:456}}">Go to News</router-link>
命名视图
一个页面显示 多个组件
定义
{
path: "/shop/:id",
components: {
default: ShopMain,
// 它们与 `<router-view>` 上的 `name` 属性匹配
ShopTop: ShopTop,
ShopFooter: ShopFooter
},
props: {
default: true,
ShopFooter: true,
ShopTop: false
}
},
使用
<template>
<div>
<!-- vue-router是基于路由和组件的,路由是用来设定访问路径,将路径和组件映射起来, -->
<h1>Hello App!</h1>
<router-view name="ShopTop"></router-view>
<router-view></router-view>
<!-- 路由出口,占位符 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view name="ShopFooter"></router-view>
</div>
</template>
重定向和别名
重定向
path: "/",
// 重定向
// redirect:'/home'
// 命名路由
// redirect:{name:"home"}
// 方法
redirect: (to) => {
// console.log(to);
return {
path: "/home"
}
}
别名
{
path: "/parent",
alias: ['/father', '/fuqin'], //起别名
component: Parent,
children: [{
path: "styleone",
component: StyleOne
},
{
path: "styletwo",
component: StyleTwo,
}
],
},
路由组件传参
不同的历史模式
Hash 模式
import { createRouter, createWebHashHistory } from 'vue-router'
const router = createRouter({
history: createWebHashHistory(),
routes: [
//...
],
})
html5
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [
//...
],
})
路由守卫
就是路由跳转 可以进行判断的地方
全局路由
// 你可以在这里输入更多的配置,但我们在这里
// 暂时保持简单
const router = createRouter({
// 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
// history: createWebHashHistory(),
// history模式,二者区别,有无#
history: createWebHistory(),
routes, // `routes: routes` 的缩写
})
// 全局守卫
// router.beforeEach((to,from,next)=>{
// console.log(to);
// console.log(from);
// next()//通行证
// })
每路守卫
{
path: '/about',
component: About,
// 每路守卫(路由独享的守卫)
beforeEnter:(to,from,next)=>{//token
console.log(to);
console.log(from);
if(123 === 123453){
next()
}
}
},
组件类的守卫
<template>
<div>新闻</div>
</template>
<script>
export default {
data() {
return {
age: 18,
};
},
beforeRouteEnter(to, from,next) {//拿不到实例对象,通过next的回调函数
console.log(to);
console.log(from);
next((vm)=>{
console.log(vm.age);
})
console.log("路由进入组件之前");
},
beforeRouteUpdate() {
console.log("路由更新组件之前");
},
beforeRouteLeave() {
console.log("路由离开组件之前");
},
};
</script>
路由懒加载
// 路由懒加载,用到时再加载
const Home=()=>import('../views/Home.vue')
状态管理
状态 == 数据
在不使用 vuex的情况下 使用 // provide/inject 跨级通信 进行数据管理
导入数据
<script>
import Home from "./views/Home.vue";
import store from "./store";
// vue3中如何设置状态管理
// provide/inject 跨级通信
export default {
provide: {
store,
},
components: {
Home,
},
};
</script>
<template>
<Home />
</template>
<style>
</style>
fetch获取数据
// http://localhost:3001/banner
// fetch//原生JS,是http数据请求的一种方式
created() {
// fetch返回promise对象
// fetch('http://localhost:3001/banner').then((res)=>{//默认执行get请求
// //json()将响应的body,解析json的promise
// // console.log(res.json());
// return res.json()
// }).then((res)=>{
// console.log(res);
// // this.bannersList=res.banners
// this.store.updateBannersList(res.banners)
// })
// axios:基于promise的http库
// axios.get('http://localhost:3001/banner').then((res)=>{
// console.log(res);
// })
// https://i.maoyan.com/api/mmdb/movie/v3/list/hot.json?ct=%E9%95%BF%E6%B2%99&ci=70&channelId=4
// 跨域请求数据,浏览器同源策略的保护机制,通过proxy实现跨域请求数据
axios.get("/path/api/mmdb/movie/v3/list/hot.json?ct=%E9%95%BF%E6%B2%99&ci=70&channelId=4").then((res) => {
console.log(res);
});
},
Axios网络请求
Axios 是一个基于 promise 的网络请求库
安装
Axios的应用是需要单独安装的 npm install --save axios
引入
组件中引入: import axios from "axios"
全局引用:
import axios from "axios"
const app = createApp(App);
app.config.globalProperties.$axios = axios
app.mount('#app')
// 在组件中调用
this.$axios
网络请求基本示例
get请求
axios({
method: "get",
url: "http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php"
}).then(res => {
console.log(res.data);
})
// axios:基于promise的http库
// axios.get('http://localhost:3001/banner').then((res)=>{
// console.log(res);
// })
// https://i.maoyan.com/api/mmdb/movie/v3/list/hot.json?ct=%E9%95%BF%E6%B2%99&ci=70&channelId=4
// 跨域请求数据,浏览器同源策略的保护机制,通过proxy实现跨域请求数据
axios.get("/path/api/mmdb/movie/v3/list/hot.json?ct=%E9%95%BF%E6%B2%99&ci=70&channelId=4").then((res) => {
console.log(res);
});
},
post请求
温馨提示
post请求参数是需要额外处理的
- 安装依赖:
npm install --save querystring- 转换参数格式:
qs.stringify({})
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);
})
快捷方案
get请求
axios.get("http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php")
.then(res =>{
console.log(res.data);
})
post请求
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);
})
Axios网络请求封装
在日常应用过程中,一个项目中的网络请求会很多,此时一般采取的方案是将网络请求封装起来
在src目录下创建文件夹utils,并创建文件request,用来存储网络请求对象 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,并创建文件index和path分别用来存放网络请求方法和请求路径
// 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)
}
}
在组件中直接调用网络请求
import api from "../api/index"
api.getChengpin().then(res =>{
console.log(res.data);
})
vite通过proxy代理解决跨域问题
vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server:{//中转服务器
proxy:{//通过代理实现跨域
//https://i.maoyan.com
'/path':{
target:'https://i.maoyan.com',//替换的服务端地址
changeOrigin:true,//开启代理,允许跨域
rewrite:path=>path.replace(/^\/path/,'')//设置重写的路径
}
}
}
})
通过vue_cli创建项目
Vue状态管理(Vuex)
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
简单来说,状态管理可以理解成为了更方便的管理组件之间的数据交互,提供了一个集中式的管理方案,任何组件都可以按照指定的方式进行读取和改变数据
引入Vuex的步骤
第一步:安装Vuex npm install --save vuex
第二步:配置Vuex文件
import { createStore } from 'vuex'
export default createStore({
state: {
counter:0
}
})
第三步:在主文件中引入Vuex
import store from './store'
app.use(store)
第四步:在组件中读取状态
<p>counter:{{ $store.state.counter }}</p>
// 或者
import { mapState } from 'vuex';
computed:{
...mapState(["counter"])
}
Vue状态管理核心(Vuex)
最常用的核心概念包含: State、Getter、Mutation、Action
Getter
对Vuex中的数据进行过滤
import { createStore } from 'vuex'
export default createStore({
state: {
counter: 0
},
getters: {
getCount(state){
return state.counter > 0 ? state.counter : "counter小于0,不符合要求"
}
}
})
import { mapState,mapGetters } from 'vuex';
computed:{
...mapGetters(["getCount"])
}
Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
import { createStore } from 'vuex'
export default createStore({
state: {
counter: 0
},
getters: {
},
mutations: {
setCounter(state, num) {
state.counter += num
}
}
})
import { mapState,mapMutations } from 'vuex';
methods:{
...mapMutations(["setCounter"]),
clickHandler(){
// this.$store.commit("setCounter",20)
// 或者
// this.setCounter(10)
}
}
Action
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态
- Action 可以包含任意异步操作
import { createStore } from 'vuex'
import axios from "axios"
export default createStore({
state: {
counter: 0
},
getters: {
getCount(state){
return state.counter > 0 ? state.counter : "counter小于0,不符合要求"
}
},
mutations: {
setCounter(state, num) {
state.counter += num
}
},
actions: {
asyncSetCount({ commit }){
axios.get("http://iwenwiki.com/api/generator/list.php")
.then(res =>{
commit("setCounter",res.data[0])
})
}
}
})
import { mapState,mapMutations,mapGetters,mapActions } from 'vuex';
methods:{
...mapActions(["asyncSetCount"]),
clickAsyncHandler(){
// this.$store.dispatch("asyncSetCount")
// 或者
// this.asyncSetCount()
}
}
使用state

加载
访问

mitaion
改变存储data
定义:

使用:

getter

Action
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
让我们来注册一个简单的 action:
const store = createStore({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。当我们在之后介绍到 Modules 时,你就知道 context 对象为什么不是 store 实例本身了。
pinia
Store 是什么?
Store (如 Pinia) 是一个保存状态和业务逻辑的实体,它并不与你的组件树绑定。换句话说,它承载着全局状态。它有点像一个永远存在的组件,每个组件都可以读取和写入它。它有三个概念,state、getter 和 action,我们可以假设这些概念相当于组件中的 data、 computed 和 methods。
定义 Store
在深入研究核心概念之前,我们得知道 Store 是用 defineStore() 定义的,它的第一个参数要求是一个独一无二的名字:
import { defineStore } from 'pinia'
// 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useAlertsStore = defineStore('alerts', {
// 其他配置...
})
这个名字 ,也被用作 id ,是必须传入的, Pinia 将用它来连接 store 和 devtools。为了养成习惯性的用法,将返回的函数命名为 use... 是一个符合组合式函数风格的约定。
defineStore() 的第二个参数可接受两类值:Setup 函数或 Option 对象。
Option Store
与 Vue 的选项式 API 类似,我们也可以传入一个带有 state、actions 与 getters 属性的 Option 对象
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters: {
double: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
})
你可以认为 state 是 store 的数据 (data),getters 是 store 的计算属性 (computed),而 actions 则是方法 (methods)。
为方便上手使用,Option Store 应尽可能直观简单。
Setup Store
也存在另一种定义 store 的可用语法。与 Vue 组合式 API 的 setup 函数 相似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。
js
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
return { count, increment }
})
在 Setup Store 中:
ref()就是state属性computed()就是gettersfunction()就是actions
Setup store 比 Option Store 带来了更多的灵活性,因为你可以在一个 store 内创建侦听器,并自由地使用任何组合式函数。不过,请记住,使用组合式函数会让 SSR 变得更加复杂。
使用 Store
虽然我们前面定义了一个 store,但在我们使用 <script setup> 调用 useStore()(或者使用 setup() 函数,像所有的组件那样) 之前,store 实例是不会被创建的:
vue
<script setup>
import { useCounterStore } from '@/stores/counter'
// 可以在组件中的任意位置访问 `store` 变量 ✨
const store = useCounterStore()
</script>
你可以定义任意多的 store,但为了让使用 pinia 的益处最大化(比如允许构建工具自动进行代码分割以及 TypeScript 推断),你应该在不同的文件中去定义 store。
如果你还不会使用 setup 组件,你也可以通过映射辅助函数来使用 Pinia。
State
在大多数情况下,state 都是你的 store 的核心。人们通常会先定义能代表他们 APP 的 state。在 Pinia 中,state 被定义为一个返回初始状态的函数。这使得 Pinia 可以同时支持服务端和客户端。
js
import { defineStore } from 'pinia'
const useStore = defineStore('storeId', {
// 为了完整类型推理,推荐使用箭头函数
state: () => {
return {
// 所有这些属性都将自动推断出它们的类型
count: 0,
name: 'Eduardo',
isAdmin: true,
items: [],
hasChanged: true,
}
},
})


Getter
Getter 完全等同于 store 的 state 的计算值。可以通过 defineStore() 中的 getters 属性来定义它们。推荐使用箭头函数,并且它将接收 state 作为第一个参数:
js
export const useStore = defineStore('main', {
state: () => ({
count: 0,
}),
getters: {
doubleCount: (state) => state.count * 2,
},
})
大多数时候,getter 仅依赖 state,不过,有时它们也可能会使用其他 getter。因此,即使在使用常规函数定义 getter 时,我们也可以通过 this 访问到整个 store 实例,但(在 TypeScript 中)必须定义返回类型。这是为了避免 TypeScript 的已知缺陷,不过这不影响用箭头函数定义的 getter,也不会影响不使用 this 的 getter。
Vue3加载Element-plus
Element,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库
Element Plus 基于 Vue 3,面向设计师和开发者的组件库
安装Element-Plus
npm install element-plus --save
完整引用
如果你对打包后的文件大小不是很在乎,那么使用完整导入会更方便
import { createApp } from 'vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import App from './App.vue'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
按需导入
按需导入才是我们的最爱,毕竟在真实的应用场景中并不是每个组件都会用到,这会造成不小的浪费
首先你需要安装unplugin-vue-components 和 unplugin-auto-import这两款插件
npm install -D unplugin-vue-components unplugin-auto-import
然后修改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()]
})
]
}
})
最后,可以直接在组件中使用
<template>
<el-button>Default</el-button>
<el-button type="primary">Primary</el-button>
</template>
Vue3加载Element-plus的字体图标
Element-plus不仅仅是提供了各种组件,同时还提供了一整套的字体图标方便开发者使用
安装icons字体图标
npm install @element-plus/icons-vue
全局注册
在项目根目录下,创建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";
app.use(elementIcon)
使用方式
接下来就可以直接在组件中引入使用了
<el-icon class="expand" color="#409EFC" :size="30">
<expand />
</el-icon>

浙公网安备 33010602011771号