目录
前置准备
vue是基于nodejs的,需要使用nodejs附带的npm命令安装
官方中文网站:
安装Vue工具 Vue CLI
Vue CLI Vue.js 开发的标准工具,Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统
npm install -g @vue/cli
安装之后,你就可以在命令行中访问 vue 命令。你可以通过简单运行 vue,看看是否展示出了一份所有可用命令的帮助信息,来验证它是否安装成功。
vue --version
创建一个项目
1、运行以下命令来创建一个新项目
vue create 项目名称
重点:项目名称不允许有大写
温馨提示
在控制台中,可以用上下按键调整选择项
在控制台中,可以用空格(spacebar)选择是否选中和取消选中
可以选择默认项目模板,或者选“手动选择特性”来选取需要的特性。
2、我们选择手动选择特性
我们选择Babel和Progressive Web App (PWA) Support 两个选项即可
温馨提示
在学习期间,不要选中 Linter / Formatter 以避免不必要的错误提示
3、Vue目前有两个主流大版本vue2和vue3,我们本套课程选择vue3最新版本
4、配置放在哪里? In dedicated config files 专用配置文件或者 In package.json在package.json文件,选择第一个
5、将其保存为未来项目的预置? y代表保存,并添加名字,n不保存,我们不保存因为以后可能会修改
6、项目创建成功如下提示信息
运行项目
第一步:进入项目根目录cd vue-demo
第二步:运行npm run serve 启动项目
安装Vue高亮插件
VSCode中安装vetur或者volar都可,前者针对Vue2版本,后者针对Vue3版本
目录结构
vue-demo是创建项目时定义的项目名称,以下是目录结构,组件也就是页面,渲染数据的
Vue基础
模板语法
文本插值:
数据绑定最常见的形式就是双大括号语法的插值
注意:一般配合js中的data()函数设置数据,该函数的作用就是定义属性,然后在template标签中引入,template标签就是html标签
<template> <p>{{ msg }}</p> </template> <script> export default { data(){//这是固定写法,返回一个对象,对象里定义属性 return { msg:1 } } } </script>
原始html
双大括号的方式会将引入的数据解释为普通文本,为了输出真正的html,需要使用v-html命令(你可以理解为innerText和innerHtml的区别)
<template> <p>{{ msg }}</p> <p v-html="html"></p> </template> <script> export default { data(){ return { msg:1, html:"<a href='http://www.baidu.com'>baidu</a>" } } } </script>
属性
双括号的语法不能在html的属性中使用,如果需要使用,我们可以通过v-bind的方式进行绑定
<template> <p>{{ msg }}</p> <p v-html="html"></p> <p v-bind:id="id">id</p> </template> <script> export default { data(){ return { msg:1, html:"<a href='http://www.baidu.com'>baidu</a>", id:1001 } } } </script>
如果觉得麻烦我们还可以简写,通过(:属性)的方式就可以解决
<template> <p>{{ msg }}</p> <p v-html="html"></p> <p v-bind:id="id">v-bind id</p> <p :id="id">:id</p> </template> <script> export default { data(){ return { msg:1, html:"<a href='http://www.baidu.com'>baidu</a>", id:1001 } } } </script>
条件渲染if
v-if和v-else
if和else是进行条件判断的,条件满足则执行if,不满足则执行else
<template> <p v-if="flag">你好</p> <p v-else>再见</p> </template> <script> export default { data(){ return { flag:true } } } </script>
v-show
vue还提供了另一种条件判断的方式
<template> <p v-if="flag">你好</p> <p v-else>再见</p> <p v-show="flag">hello world</p> </template> <script> export default { data(){ return { flag:true } } } </script>
![]()
v-if和v-show的区别
v-if 是“真正”的条件渲染,因为它会确保在切换过程中,条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
因此,如果需要非常频繁地切换,则使用 v-show 较好;
如果在运行时条件很少改变,则使用 v-if 较好
列表渲染for
我们可以使用v-for基于一个数组来渲染一个列表,该指令需要使用item in items形式的特殊语法,其中items是源数组,item是被迭代的数组元素的别名
<template> <ul> <li v-for="item in items">{{ item }}</li> </ul> </template> <script> export default { data(){ return { items : [1,2,3,4,5] } } } </script>
维护状态
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一的 key 属性:
<div v-for="(item,index) in items" :key="item.id或者index"> <!-- 内容 --> </div>
事件处理器
监听事件
我们可以使用 v-on 指令 (通常缩写为 @ 符号) 来监听 DOM 事件,并在触发事件时执行一些 JavaScript。用法为 v-on:click="methodName" 或使用快捷方式 @click="methodName"
注意:点击事件通常配合js中的methods属性使用,该属性是一个对象,对象中定义使用到的方法,methods属性和data()方法同级
<template> <button v-on:click="submit">点击</button> <button @click="submit2">点击简写</button> </template> <script> export default { data(){ return { } }, methods:{ submit(){ console.log("点击一次"); }, submit2(){ console.log("点击简写"); } } } </script>
重点:methods中如果想要访问data方法中的数据,直接使用this访问即可
表单输入绑定
通过v-model指令监听输入框,当我们对输入框中的内容进行了修改,那么v-mode会自动将修改的内容同步到绑定的属性中
<template> <input type="text" v-model="msg"> <p>{{ msg }}</p> </template> <script> export default { data(){ return { msg:"" } } } </script>
懒加载lazy
v-model是对输入框进行实时监控的,也就是说我们只要一有修改,就会自动同步,但是这样会大量消耗资源,此时我们就可以通过v-model.lazy实现懒加载,当我们的输入框失去焦点的时候才会同步
<template> <input type="text" v-model.lazy="msg"> <p>{{ msg }}</p> </template> <script> export default { data(){ return { msg:"" } } } </script>
清空空格trim
有时候我们不允许用户使用空格开头或者结尾,此时我们就可以通过v-model.trim去除首尾空格
<template> <input type="text" v-model.trim="msg"> <p>{{ msg }}</p> </template> <script> export default { data(){ return { msg:"" } } } </script>
组件基础
单文件组件
Vue 单文件组件(又名 *.vue 文件,缩写为 SFC)是一种特殊的文件格式,它允许将 Vue 组件的模板(html)、逻辑(js) 与 样式(css)封装在单个文件中
组件模板:
<template><!-- 相当于html标签 --> </template> <script> export default { data(){ return { //定义属性,方便组件使用 } } } <!-- scoped:如果在style标签中添加该属性,就代表当前样式只在当前组件中生效--> </script scoped> <style> </style>
在app.vue根组件中加载组件
第一步:引入组件 import 组件名 from '组件路径'
第二步:挂载组件 components: { 组件名 }
第三步:显示组件 < 组件名 />
Props组件交互
组件之间是需要存在数据交互的,如果组件之间毫无关系,那么组件的意义就很小了
通过Props属性可以实现将父组件的内容交互给子组件
父组件:
在显示子组件的地方添加属性,
语法:
:属性名="属性值"
<template> <HelloWorld :msg="msg"/> </template> <script> import HelloWorld from './components/HelloWorld.vue'; export default { data(){ return { msg:"你好,我是你爹" } }, components:{ HelloWorld } } </script>
子组件:
在子组件中添加props属性,该属性接收父组件传来的属性名,并且定义该属性的类型
<template> <p>{{ msg }}</p> </template> <script> export default { name: 'HelloWorld', props: { msg: String //msg不是乱写的,一定要和父组件中的交互的属性名字对应 } } </script>
自定义事件实现组件交互
如果只能父组件将数据传递给子组件,而子组件不能传递给父组件,那这样局限性太大了,所以我们可以通过$emit实现自定义事件,然后在父组件添加事件即可
子组件:
<template> <p>{{ msg }}</p> <button @click="sendHandle">sendHandle</button> </template> <script> export default { name: 'HelloWorld', props: { msg: String }, methods:{ sendHandle(){ //参数一:属性名 //参数二:传递的数据 this.$emit("consumer","handle") } } } </script>
父组件:
是在子组件显示的标签中添加自定义事件
<template> <HelloWorld :msg="msg" @consumer="getHandle"/> </template> <script> import HelloWorld from './components/HelloWorld.vue'; export default { data(){ return { msg:"你好,我是你爹" } }, components:{ HelloWorld }, methods:{ getHandle(data){//data就是传递过来的数据 console.log(data); } } } </script>
![]()
组件生命周期
每个组件在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会
为了方便记忆,我们可以将他们分类,以下显示的都是函数:
创建时:beforeCreate、created
渲染时:beforeMount、mounted
更新时:beforeUpdate、updated
卸载时:beforeUnmount、unmounted
Axios网络请求
Axios 是一个基于 promise 的异步网络请求库,axios请求过后返回的是一个Promise对象
安装
Axios的应用是需要单独安装的 npm install --save axios
引入方式
1、组件中引入: import axios from "axios"
2、在主入口main.js中全局引用:
import axios from "axios" const app = createApp(App); app.config.globalProperties.$axios = axios app.mount('#app')
// 在组件中使用网络请求要使用this.$axios
this.$axios.get()
this.$axios.post()
网络请求基本实例:
<template> <button @click="getImage">发送</button> <p>{{ msg }}</p> </template> <script> import axios from "axios" export default { data(){ return{ msg:"" } }, methods:{ getImage(){ this.msg = "图片加载中"; axios({ methods:"get", url:"https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE4wHfZ?ver=4a32" }) .then(res => this.msg = res.data) } } } </script>
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 =>{ //回调函数的参数是一个res,通过res.data拿到请求的数据 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网络请求封装
在日常应用过程中,一个项目中的网络请求会很多,此时一般采取的方案是将网络请求封装起来,也就是规范Axios网络请求
1、在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( //类似promise,传递两个方法,一个是成功的方法,一个是失败的方法 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) } ) //导出instance对象 export default instance;
2、在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) } }
3、在组件中直接调用网络请求
import api from "../api/index" api.getChengpin().then(res =>{ console.log(res.data);
Router路由
在Vue中,我们可以通过vue-router路由管理页面之间的关系,比如:页面的跳转
Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举
Router引入
第一步:安装路由 npm install --save vue-router
并且安装路由的依赖:npm i vue-router
第二步:创建参与跳转的组件
//index.vue <template> <h3>首页</h3> </template> <script> export default { } </script>
//view.vue <template> <h3>view</h3> </template>
第三步:在src目录下创建route目录,在该目录总配置独立的路由文件index.js
import { createRouter,createWebHashHistory } from "vue-router"; import view from "../components/view"//引入跳转的组件 import index from "../components/index"//引入跳转的组件 const routes = [ { //一个对象的作用就是将路径和组件绑定 path:"/",//定义跳转路径 component:index//定义跳转的组件 }, { path:"/view", component:view } ] const router = createRouter({//构建router对象,传递routes history:createWebHashHistory(), routes:routes }) export default router//导出router对象
第四步:在main.js中引入路由到项目
import { createApp } from 'vue' import App from './App.vue' import './registerServiceWorker' import index from "./route/index"//引入router配置文件 const app = createApp(App); app.use(index)//将router配置文件添加 app.mount('#app')
第五步:在app.vue的template标签中指定路由显示入口 <router-view/>,在app.vue的template标签中指定路由跳转
<template> <RouterLink to="/">首页</RouterLink> | <!-- 路由跳转 --> <RouterLink to="/view">view</RouterLink> <!-- 路由跳转 --> <RouterView></RouterView> <!-- 路由显示入口 --> </template> <script> export default { } </script>
Router传递参数
页面跳转过程中,是可以携带参数的,这也是很常见的业务
例如:在一个列表项,点击进入查看每个列表项的详情
1、在index.js配置文件中指定参数名
2、在路由跳转的时候添加传递的数据,类似Restful风格
3、在跳转的组件中显示数据
语法:$route.params.参数名
嵌套Router
路由嵌套是非常常见的需求,就是组件的子组件也添加路由
1、index.js中的routes属性中的对象添加children属性
import { createRouter,createWebHashHistory } from "vue-router"; import view from "../components/view"//引入跳转的组件 import index from "../components/index"//引入跳转的组件 import view1 from "../view/view1" import view2 from "../view/view2" const routes = [ { //一个对象的作用就是将路径和组件绑定 path:"/",//定义跳转路径 component:index//定义跳转的组件 }, { path:"/view", component:view, //子路由的path不用加斜杠 children:[ { path:"view1", component:view1 }, { path:"view2", component:view2 } ] } ] const router = createRouter({//构建router对象,传递routes history:createWebHashHistory(), routes:routes }) export default router//导出router对象
2、添加子路由用到的组件
view1:
view2:
3、修改view子组件
<template> <ul> <li><RouterLink to="/view/view1">view1</RouterLink></li> <li><RouterLink to="/view/view2">view2</RouterLink></li> </ul> <RouterView></RouterView> </template>
4、修改app.vue主组件
<template> <RouterLink to="/">首页</RouterLink> | <RouterLink to="/view">view</RouterLink> <RouterView></RouterView> </template> <script> export default { } </script>
首页
view
view1
view2
![]()
Vuex多组件交互
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
简单来说:状态管理可以理解成为了更方便的管理组件之间的数据交互,提供了一个集中式的管理方案,任何组件都可以按照指定的方式进行读取和改变数据
引入Vuex的步骤
第一步:安装Vuex npm install --save vuex
第二步:在src目录下创建store目录,然后创建index.js文件,该文件就是Vuex的配置文件import { createStore } from 'vuex' export default createStore({ state: { counter:0 } })
第三步:在主文件main.js中引入Vuex
import store from './store' app.use(store)
第四步:在组件中读取数据
<p>counter:{{ $store.state.counter }}</p> // 或者 import { mapState } from 'vuex'; computed:{ ...mapState(["counter"]) }
Vuex的核心
最常用的核心概念包含: State、Getter、Mutation、Action
Getter
对Vuex中的数据进行过滤
1、vuex配置文件:
2、组件编写:
Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
1、vuex配置文件:
2、组件编写:
Action
Action 类似于 mutation,不同在于:
1、vuex配置文件:
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]) //调用方法,并传递请求的数据 }) } } })
2、组件编写
import { mapState,mapMutations,mapGetters,mapActions } from 'vuex'; methods:{ ...mapActions(["asyncSetCount"]), clickAsyncHandler(){ // this.$store.dispatch("asyncSetCount") // 或者 // this.asyncSetCount() } }
- Action 提交的是 mutation,而不是直接变更状态
- Action 是异步的,mutation是同步的
Vue3新特性
Vue3是目前Vue的最新版本,自然也是新增了很多新特性
六大亮点
- Performance:性能更比Vue 2.0强。
- Tree shaking support:可以将无用模块“剪辑”,仅打包需要的。
- Composition API:组合API-setup方法(可以使用setup替代vue2中的data属性和methods属性)
- Fragment, Teleport, Suspense:“碎片”,Teleport即Protal传送门,“悬念”
- Better TypeScript support:更优秀的Ts支持
- Custom Renderer API:暴露了自定义渲染API
重点:但是setup()中定义的属性和方法需要通过return {属性… , 方法…}的方式返回
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") //ref设置简单数据 const state = reactive({ //reactive设置复杂数据 list:[] }) name.value = "hello world" //如果需要修改值,那么需要使用属性名.value设置 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') },
Vue3加载ElementPlus
Element,一套为开发者、设计师和产品经理准备的基于 Vue 2.0 的桌面端组件库
Element Plus 基于 Vue 3,面向设计师和开发者的组件库