单页面SPA应用程序的优点
- 良好的交互体验
- 良好的前后端工作分离模式
- 减轻服务器的压力
单页面缺点
- 首屏加载慢
- 解决:路由懒加载、代码压缩、CDN加速、网络传输压缩
- 不利于SEO
- 解决:SSR服务器端渲染
vite创建SPA项目
- 仅支持3.x,速度快,小而巧,不基于webpack,不建议在企业级项目开发中使用
npm i vite # 下载vite库
npm init vite-app <project-name> # 初始化一个vite项目
cd <project-name> # 进入到项目文件夹
npm install # 下载依赖包
npm run dev # 以开发模式运行项目
Vue3.x的创建spa方法
-
在
main.js
中,import {createApp} from 'vue' import App from '@/App.vue' // createApp()方法创建App的实例, // 再链式调用mount()方法,将实例渲染到index.html中的id为app的区域 const app = createApp(App).mount('#app')
-
<template>
中支持定义多个根节点
<template>
<h1>Hello World!</h1>
<p>你好 Vue.js</p>
</template>
vue3.x中,可以有多个节点,实例渲染时,外层会被原页面中id为app的DOM元素包裹
vue2.x中,只能有一个根节点,且会替换原页面中id为app的DOM元素
- .vue文件中,
<template>
节点是必须的,<script>&<style>
都为可选
全局注册组件
// 首先导入组件
import Swiper from '@/component/swiper.vue'
//全局注册,arg1: 注册后的名称,arg2:导入时的组件名
app.component('my-swiper',Swiper)
// 或直接使用组件自己内部定义的name名称
app.component(Swiper.name,Swiper)
组件命名规则
kebab-case
命名法,俗称短横线命名法,例如my-swiper, my-searchPascalCase
命名法,俗称大驼峰命名法,例如MySwiper,MySearch
PascalCase命名法
可以严格按照帕斯卡名称进行使用,又可以转化为短横线名称进行使用, 适用性更强,故推荐使用PascalCase
样式穿透
- vue2.x:
/deep/ h3
- vue3.x:
:deep(h3)
动态绑定class类名
-
可通过
三元表达式
绑定<!-- 根据isItalic变量控制是否添加italic类名 --> <h3 class="thin" :class="isItalic ? italic : ''"></h3>
-
若需要添加多个,可通过
数组方式
:<!-- 根据isItalic、isDelete变量控制是否添加italic、delete类名 --> <h3 class="thin" :class="[isItalic ? italic : '', isDelete ? delete : '']"></h3>
-
还可用
对象形式
绑定类名:<!-- 对象中的 属性名 即为 要绑定的类名,值为布尔值,true则添加该类名;false则忽略 --> <h3 class="thin" :class="classObj"></h3>
// 其中classObj为: const classObj = { italic: true, // 添加了italic类名 delete: false // 没有添加delete类名 }
-
以
对象语法
绑定内联style样式
:<!-- :style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名: --> <div :style=" {color : active, fontSize : fsize + 'px', 'background-color' : bgcolor} "></div>
// 其中active, fsize, bgcolor 为data中定义的变量 data(){ return { active: 'red', fsize: 18, bgcolor: 'pink' } }
props自定义验证
-
通过定义validator函数,返回true则验证通过,false则验证失败
props:{ propA:{ // propA的值必须为['a','b','c',1,2,3]中的一项 validator(val){ return ['a','b','c',1,2,3].indexOf(val) !== -1 // 若val为数组中的任意一项,返回true;否则返回false } } }
计算属性 vs 方法
- 计算属性会缓存计算结果,只有依赖的数据项发生变化时,才会重新计算,所以性能比方法更好
emits节点
-
新增了 自定义事件 的节点 emits,用来声明自定义事件
export default { emits: ['check'], created() { this.$emit('check') } }
组件上的v-model指令
-
当 需要维护组件内外数据的同步 时,可以在组件上使用v-model指令
-
其中emits中的
update : xxx
函数表示一个更新事件,触发后父组件自动更新对应的值
生命周期函数命名修改
- 销毁阶段的生命周期函数:
- beforeUnmounted():将要销毁前
- unmounted():已销毁
provide方法向后代共享数据
-
祖先节点中声明provide方法,return要共享的数据:
export default { data(){ return { color: 'red' } }, // 同通过provide方法共享了color, count两个数据 provide(){ return { color: this.color, count: 1 } } }
-
在子孙节点中,通过inject数据来接受数据,且可以直接使用
export default { inject: ['color', 'count'] }
<h1>{{ color }}</h1>
-
!!!注意:通过provide() 共享的数据是非绑定的、静态的。当父组件中对应数据更新,子孙组件中不会更新。
-
如要共享响应式的数据,可通过computed函数向下共享响应式的数据:
import {computed} from 'vue' export default { data(){ return { color: 'red' } }, provide(){ return { // 通过computed函数共享响应式的数据 color: computed(() => this.color), count: 1 } } }
此时子组件需要通过 变量名.value 来使用
export default { inject: ['color', 'count'] }
<h1>{{ color.value }}</h1>
vuex
- 组件之间的数据共享方案
axios在vue3中的全局挂载方法
-
配置默认请求根路径
axios.defaults.baseURL = 'http://www.escook.com'
-
vue2中挂载:
Vue.prototype.$http = axios
-
vue3中挂载:
app.config.globalProperties.$http = axios
自定义指令(directives)
-
原
bind()
函数修改命名为mounted()
, 原update
函数修改为updated()
-
声明全局自定义指令并使用:(
mounted()
函数逻辑与updated()
完全一致时可简写)如下:app.directive('color',(el,binding) => {el.style.color = binding.value})
<h3 v-color='red'>更改字体的color为红色</h3>
路由vue-router的使用
-
版本:
vue-router3.x
需配合vue2.x
使用;vue-router4.x
需配合vue3.x
使用 -
vue2中,
- 直接导入构造函数VueRouter进行实例化创建路由,并导入Vue,使用Vue.use() 来安装路由插件;
- 同时还需要在main.js中:在Vue实例中指定router节点
-
vue3中推荐使用按需导入函数的形式来创建路由:
import { createRouter,createWebHashHistory } from 'vue-router' // 创建路由实例对象 const router = createRouter({ // 通过history,指定路由的工作模式 history: createWebHashHistory(), // 通过routes,指定路由规则 routes: [ { path: '/', redirect: '/login' }, { path: '/login', component: Login, name: 'login' }, { path: '/home', redirect: '/home/users', component: Home, name: 'home', children: [ { path: 'users', component: Users }, { path: 'rights', component: Rights }, ], }, ], }) export default router
-
然后在main.js中通过app.use() 来挂载路由,不需要在Vue实例中配置
-
路由高亮效果:被点击选中的路由连接默认为添加一个
router-link-active
的类名,可通过修改这个类名的样式来控制路由高亮- 这个类名可通过修改实例中的
linkActiveClass
属性来配置自定义高亮类名
- 这个类名可通过修改实例中的
-
3.x和4.x版本的路由的主要区别:创建路由模块的方式 ↑
命名路由
-
路由规则中配置name属性,则为命名路由。 name属性必须唯一
{ path: '/login', component: Login, name: 'login' },
-
声明式导航:to属性中直接填写路由的名称
<router-link to="login">go to login</router-link> // 带参数: <router-link to="{ name: login, params: { id: 3 } }">go to login</router-link>
-
编程式导航:传递一个配置对象,通过name指定路由,params指定参数
this.$router.push({name: 'login'}) // 带参数: this.$router.push({name: 'login', params: {id: 3}})
常见组件库
- PC端:
- Element UI:饿了么前端团队开源项目
- vue2 —> Element UI
- vue3 —> Element PLUS
- View UI
- Element UI:饿了么前端团队开源项目
- 移动端:
- MInt UI
- Vant
axios拦截器
-
axios拦截器分为 请求拦截器 和 响应拦截器
-
请求拦截器:即在请求发起阶段,axios先对请求拦截,可进行一些处理,再发起真正的请求
-
响应拦截器同理,在服务器返回响应数据时,axios先对响应回的数据进行拦截,可进行一些处理,再将数据给到浏览器
-
配置请求拦截器:
-
axios.interceptors.request.use (成功的回调, 失败的回调)
-
失败回调可以省略
-
回调函数的形参一般用
config
接收,并且最后需要需要return config
-
- 利用请求拦截器统一配置请求头token
import axios from 'axios' axios.defaults.baseURL = 'http://www.xxx.com' // 配置请求拦截器 axios.interceptors.request.use(function(config){ // 为请求统一配置请求头 config.headers.Authorization = 'Bearer xxx' return config })
- 利用请求拦截器和响应拦截器实现loading效果
let loading = numm // 配置请求拦截器 axios.interceptors.request.use(function(config){ loading开始 return config }) // 配置响应拦截器 axios.interceptors.response.use(function(response){ loading结束 return response })
-
proxy跨域代理
-
在api服务器没有配置 cors 时,前端可以通过proxy代理解决跨域问题:
-
main.js中设置axios请求根路径为当前web项目的根路径:
axios.defaults.baseURL = 'http://localhost:8080'
-
在vue.condig.js中配置devServer.proxy属性值为要请求的服务器根路径即可
module.exports = { devServer : { proxy: 'https://www.escook.cn', }, }
proxy代理功能仅在开发调试阶段生效,当要发布上线时,还是需要 api 服务器配置 cors
-