admin 管理员组

文章数量: 887018

目录

  • Vue 2.x 学习笔记
    • Node
      • node
        • 查看 node 版本
      • npm
        • 查看 npm 版本
        • 查看 npm 当前镜像源
        • 设置 npm 使用淘宝镜像源
      • yarn
        • 安装 yarn
        • 查看 yarn 当前镜像源
        • 设置 yarn 使用淘宝镜像源
    • Vue CLI
      • 安装
      • 创建项目
    • 脚手架文件结构
    • 关于不同版本的 Vue
    • vue.config.js 配置文件
    • refs
    • props
          • 传递数据
          • 接收数据
            • 方式一:简单接收
            • 方式二:限制数据类型
            • 方式三
    • mixin(混入)
          • 第一步:定义混入
          • 第二步:使用混入
            • 全局混入
            • 局部混入
    • plugins(插件)
          • 定义插件
          • 使用插件
    • 样式
      • scoped
    • 总结 TodoList 案例
      • 组件化编码流程(通用)
        • 实现静态组件
        • 展示动态数据
        • 交互:从绑定事件监听开始
      • props
        • props用于组件间通信
          • 父传子
          • 子传父
        • 不能修改 props 的值
    • (webStorage)浏览器本地存储
      • API
        • setItem
        • getItem
        • removeItem
        • clear
    • 自定义事件
      • 绑定自定义事件
        • 第一种方式
        • 第二种方式
      • 触发自定义事件
      • 解绑自定义事件
      • 注意
    • 全局事件总线(GlobalEventBus)
      • 安装全局事件总线
      • 使用事件总线
        • 接收数据
        • 提供数据
      • 解绑自定义事件
    • 消息订阅与发布( pubsub-js )
      • 使用步骤
        • 1. 安装 pubsub 插件。
        • 2. 引入 pubsub 插件。
        • 3. 订阅消息
        • 4. 发布消息
        • 5. 最好在订阅组件的 beforeDestroy 钩子函数中,取消订阅。
    • $ nextTick 实例方法
      • 语法
      • 作用
      • 应用场景
    • Vue 封装的 过渡 & 动画
      • 使用 CSS 动画
        • 准备动画
        • 准备样式
        • 使用 `<transition>`标签
        • 使用 `<transition-group>`标签
      • 使用 CSS 过渡
        • 1. 准备样式
        • 2. 使用 `<transition>` 或 `<transition-group>` 标签
      • 配合使用第三方动画库 `Animate.css`
    • Vue 中的 ajax
      • Vue 脚手架配置代理服务器 devServer
        • 方法一
        • 方法二
    • vue - router
      • 基本概念
        • vue - router
        • SPA 应用
        • 路由 `route`
          • 后端路由
          • 前端路由
      • 基本使用
        • 安装 vue-router 插件
        • 引入
        • 应用
        • 编写 router 配置项
        • 在 Vue 实例中,加入 router 配置项。
        • `router-link` 标签:实现路由切换
        • `router-view` 标签:指定组件的呈现位置,路由占位符
        • 注意
      • 多级路由(嵌套路由)
        • 配置路由规则,使用 `children` 配置项。
        • 路由切换
      • 路由的 query 参数
        • 传递参数
          • 属性 to 的字符串写法
          • 属性 to 的对象写法
        • 接收参数
      • 命名路由
        • 为路由命名
        • 简化跳转
      • 路由的 params 参数
        • 配置路由,声明接收 params 参数。
        • 传递参数
        • 接收参数
      • 路由的 props 配置
        • 接收参数
          • 写法一
          • 写法二
          • 写法三
      • `<router-link>` 标签的 push/replace 属性
      • 编程式路由导航
      • 缓存路由组件
      • 两个路由独有的生命周期钩子
        • `activated`
        • `deactivated`
      • 路由守卫
        • 分类
        • 全局路由守卫
          • 全局前置路由守卫
          • 全局后置路由守卫
        • 独享路由守卫
        • 组件内路由守卫
          • `beforeRouteEnter(to, from, next)`
          • `beforeRouteLeave(to, from, next)`
      • 路由器的两种工作模式
        • hash 值
        • 路由模式
          • hash 模式(默认)
          • history 模式
    • 补充内容
      • ESLint
        • 配置
      • 查看 webpack 所有版本
      • 查看 less-loader@11 依赖的包与版本
      • 安装 less-loader
      • 安装 less
      • 安装 nanoid ( uuid 的简化版 )
      • 一个重要的内置关系
      • Object.hasOwn()
        • 语法
        • 参数
        • 返回值
      • CSS3 动画
        • 1. 定义动画(@keyframes)
        • 2. 在样式中使用动画(animation)
        • 3. 在元素中应用样式
      • 浏览器发送网络请求
        • 跨域问题 XMLHttpRequest
          • 解决方法
          • 跨域问题报错信息
      • Node + Express 搭建测试服务器
      • 在搭建好的服务器端解决 history 模式刷新页面 404 问题
      • ElementUI
        • 按需引入
          • 安装 babel-plugin-component
          • 修改 babel.config.js 文件
          • 按需引入

Vue 2.x 学习笔记

Node

node

查看 node 版本
node -v
# v16.19.0

npm

查看 npm 版本
npm -v
# 8.19.3
查看 npm 当前镜像源
npm config get registry
设置 npm 使用淘宝镜像源
npm config set registry https://registry.npmmirror/

yarn

安装 yarn

临时使用淘宝镜像全局安装 yarn

npm install -g yarn --registry=https://registry.npm.taobao
查看 yarn 当前镜像源
yarn config get registry
# https://registry.npmmirror/ 表明已成功永久配置成淘宝镜像源
设置 yarn 使用淘宝镜像源
yarn config set registry https://registry.npmmirror/

Vue CLI

安装

npm install -g @vue/cli
# OR
yarn global add @vue/cli

创建项目

vue create my-project		# 命令行创建
# OR
vue ui  # 使用 GUI 创建

脚手架文件结构

├── node_modules
├── public
│   └── favicon.ico			页签图标
│   └── index.html			主页面
├── src
│   └── assets				存放静态资源
│       ├── logo.png
│   └── component			存放组件
│       ├── HelloWorld.vue
│   ├── App.vue				汇总所有组件
│   ├── main.js	入口文件
├── .gitignore			    git版本管制忽略的配置
├── babel.config.js			babel的配置文件(用于ES6->ES5)
├── package.json			应用包配置文件
├── package-lock.json		包版本控制文件
└── README.md				应用描述文件

关于不同版本的 Vue

  • vue.jsvue.runtime.xxx.js 的区别:

    • vue.js 是完整版的 Vue,包含 核心功能 + 模板解析器

    • vue.runtime.xxx.js 是运行版的 Vue,只包含 核心功能,不包含 模板解析器

  • 因为 vue.runtime.xxx.js 没有模板解析器,所以在入口文件 main.js 中,不能使用 template 配置项,需要使用 render 函数接收到的 createElement 函数去指定具体内容。

vue.config.js 配置文件

  • 在终端输入命令 vue inspect > output.js ,可以在根目录下,生成 output.js 文件,在此文件中可以查看 Vue 脚手架的默认配置。

    注意:报错是因为,文件中是一个对象,在文件在前面加上 export default 即可。

  • 使用 vue.config.js 可以对脚手架进行个性化定制,详情见 https://cli.vuejs/zh 。

refs

  1. 被用来给元素或子组件注册引用信息(id的替代者)。

  2. 应用在 html 标签上获取的是 真实 DOM 元素,应用在组件标签上获取的是 组件实例对象(vc)

  3. 使用方式:

    1. 打标识

      <h1 v-text="msg" ref="title"></h1>
      <button @click="showDOM" ref="btn">点我输出上方的 DOM 元素</button>
      <School ref="sch" />
      
    2. 获取 ref

      this.$refs.title	// 真实 DOM 元素
      this.$refs.btn		// 真实 DOM 元素
      this.$refs.sch		// School 组件的实例对象(vc)
      

props

让组件接收外部传来的数据。

传递数据
<Student name="张三" sex="" :age="20" />
接收数据
方式一:简单接收
props: ['name', 'age', 'sex']
方式二:限制数据类型
props:{
    name: String,
    sex: String,
    age: Number
}
方式三
  • 限制数据类型
  • 限制数据必要性
  • 指定数据默认值
props: {
    name: {
        type: String, // name的类型是字符串
        required: true, // name是必要的
    },
    age: {
        type: Number,
        default: 99, // 默认值
    },
    sex: {
        type: String,
        required: true,
    }
}

备注:props 是只读的,Vue 底层会监测你对 props 的修改。如果进行了修改,会在控制台发出警告。若业务需要确需修改,可以复制 props 内容到 data 中一份,然后再去修改 data 中的响应数据。

mixin(混入)

可以把多个组件的配置,提取成一个 mixin 混入对象。

第一步:定义混入
  • 创建 mixin.js 文件。

    {
    	data() {...},
        methods: {...},
        mounted() {...},
        ...
    }
    
第二步:使用混入
全局混入

在 main.js 中

// 引入 mixin
import { mixin, mixin2 } from './mixin'
// 全局应用 mixin
Vue.mixin(mixin).mixin(mixin2)
局部混入

在单个 vue 文件中

import { mixin, mixin2 } from '../mixin'
export default {
	mixins: [mixin, mixin2]
}

plugins(插件)

  • 功能:用于增强 Vue。

  • 本质:包含 install 方法的一个对象,install 的第一个参数是 Vue 构造函数,第二个参数是插件使用者传入的数据。

定义插件

src 目录下,创建 plugins.js 文件。

export default {
  install(Vue,...options) {	// options数组接收调用者传递的其他参数,如Vue.use(plugins,1,2,3),则 options = [1,2,3]
 	// 1. 添加全局过滤器
      Vue.filter(...)
                 
 	// 2. 添加全局自定义指令
      Vue.directives(...)
      
    // 3. 配置全局混入
      Vue.mixin(...)
    
 	// 4. 添加实例方法
      Vue.prototype.myMethod = function() {...}
      Vue.prototype.myProperty = xxx
  }
}
使用插件

main.js 文件中:

// 引入插件
import plugins from './plugins'
// 应用插件
Vue.use(plugins)

样式

scoped

让样式局部生效,防止冲突。

<style scoped>

备注:App.vue 中样式不加 scoped。

总结 TodoList 案例

组件化编码流程(通用)

实现静态组件

抽取组件,使用组件实现静态页面效果。

组件要按照功能点拆分,命名不要与 html 元素冲突。

展示动态数据
  1. 数据的名称、类型是什么?
  2. 数据保存在哪个组件中?

考虑好数据的存放位置,数据是单个组件用,还是多个组件用。

  • 单个组件用:放在组件自身即可。
  • 多个组件用:放在他们共同的父组件上。(状态提升)
交互:从绑定事件监听开始

props

props用于组件间通信
父传子
  • 通过 props 传递。
子传父
  • 父亲先偷偷给儿子传个函数,当儿子需要传递数据给父亲的时候,调用这个函数,通过函数参数传递数据。
不能修改 props 的值
  • 使用 v-modal 时要注意,v-modal 绑定的值不能时 props 传过来的值,因为 props 是不可以修改的。
  • 若 props 传过来的值是对象类型,修改对象中的属性时 Vue 不会报错,但 不推荐 这样做。

(webStorage)浏览器本地存储

  • 存储内容大小一般支持 5MB 左右(不同的浏览器可能不一样)
  • 浏览器通过 Windows.localStorage 和 Windows.sessionStorage 来实现本地存储机制。
  • sessionStorage 存储的内容会随着浏览器窗口的关闭而清除。
  • localStorage 存储的内容,关闭窗口不会自动清除。需要手动清缓存或借助API才会清除。

API

setItem
//该方法接收一个键值对作为参数,会把键值以字符串的格式(调用自身的toString()方法)添加到存储中。
//如果键名存在,则更新其对应的值。
localStorage.setItem('key', 'value')
sessionStorage.setItem('key', 'value')

示例

// String 类型
localStorage.setItem('msg', '你好啊。')	// '你好啊。'
// Number 类型
localStorage.setItem('number', 666) // '666'
// 对象类型
let person = { name: '张三', age: 18 }
localStorage.setItem('person', person)	// '[object Object]'
localStorage.setItem('person', JSON.stringify(p)) // '{"name":"张三","age":18}'
getItem
// 该方法接收一个键名作为参数,返回键名对应的值。
localStorage.getItem('key')
sessionStorage.getItem('key')

备注

// 获取缺失的键名,会返回 null
localStorage.getItem('msg3') // null
JSON.parse(null)	// null
removeItem
// 该方法接收一个键名作为参数,并将响应键值对从村粗中删除。
localStorage.removeItem('key')
sessionStorage.removeItem('key')
clear
// 清空存储中的所有数据。
localStorage.clear()
sessionStorage.clear()

自定义事件

一种组件间通信的方式,适用于 子组件父组件 传递数据。

绑定自定义事件

父组件 中给 子组件 绑定自定义事件。(事件的回调在 父组件 中)

第一种方式
// 在父组件中。
<Student @demo="sayHello" />
<Student v-on:demo="sayHello" />
<Student v-once:demo="sayHello" />	// 只触发一次
第二种方式
// 在父组件中。
<Student ref="student" />
...
mounted(){
	this.$refs.student.$on('demo',this.sayHello)
	this.$refs.student.$once('demo',this.sayHello)	// 只触发一次
}

触发自定义事件

子组件 中触发自定义事件。

// 在子组件中。
this.$emit('demo',value)	// value为传递的数据

解绑自定义事件

子组件 中解绑自定义事件。

// 在子组件中。
this.$off('getStudentName') // 解绑单一自定义事件。
this.$off(['getStudentName', 'demo']) // 解绑多个自定义事件。
this.$off() // 解绑所有自定义事件。 

注意

  • 在自定义组件中,绑定原生 DOM 事件,需要使用 native 修饰符。(不然会被 Vue 当作自定义事件。)

    <Student @click.native="showInfo" />
    
  • 通过 this.$refs.xxx.$on('自定义事件名称',callbackFn) 绑定自定义事件时,callbackFn 要么配置在父组件的 methods 中,要么使用箭头函数,否则 this 指向会出问题。

    • 情况一

      callbackFn 没有定义在 methods 中,并且没有使用箭头函数,则函数内的 this 指向子组件实例对象。

      mouted(){
              this.$refs.student.$on('getStudentName', function (name, ...params) {
              console.log(this) 	// this指向Student组件实例对象
          })
      }
      
    • 情况二

      callbackFn 没有定义在 methods 中,但使用箭头函数,则函数内的 this 指向当前组件实例对象。

      mouted(){
          this.$refs.student.$on('getStudentName', (name, ...params) => {
              console.log('App收到了学生名称:', name, params)
              this.studentName = name // this指向App组件实例对象,因为箭头函数没有自己的this,所以会向父元素找。
          })
      }
      
    • 情况三

      callbackFn 定义在 methods 中,则函数内的 this 指向当前组件实例对象。

      methods:{
          getStudentName(name) {
              this.studentName = name	 // this指向App的组件实例对象
          }
      }
      mouted(){
          this.$refs.student.$on('getStudentName', this.getStudentName)
      }
      

全局事件总线(GlobalEventBus)

一种组件之间的通信方式,适用于 任意组件间传递数据

安装全局事件总线

// 在 main.js 中
new Vue({
    ...
    beforeCreate(){
    	Vue.prototype.$bus = this	// 安装全局事件总线,$bus就是当前应用的vm
	}
    ...
})

使用事件总线

接收数据

A 组件想接收数据,则在 A 组件中给 $bus 绑定自定义事件,事件的 回调函数 留在 A 组件自身。

// 在 A 组件中。
methods:{
    // 回调函数
    callbackFn(data){ ... }
}
...
mounted() {
    // 给 $bus 绑定自定义事件hello
    this.$bus.$on('hello', this.callbackFn)
}
提供数据
// 在想要提供数据的组件内。
this.$bus.$emit('hello', data)	// data 为提供的数据

解绑自定义事件

最好在 beforeDestroy 钩子中,用 $off 去解绑当前组件所用到的自定义事件。

在哪个组件绑定的,就在哪个组件解绑。

// 在 A 组件中。
beforeDestroy(){
    this.$bus.$off('hello')
}

消息订阅与发布( pubsub-js )

  1. 订阅消息:消息名
  2. 发布消息:消息内容
  3. 退订消息:消息 ID

一种组件之间的通信方式,适用于 任意组件间传递数据

使用步骤

1. 安装 pubsub 插件。
npm i pubsub-js
yarn add pubsub-js
2. 引入 pubsub 插件。
import pubsub from 'pubsub-js'
3. 订阅消息

A 组件想接收数据,则在 A 组件中订阅消息,订阅的 callbackFn 留在 A 组件自身。

// 在 A 组件中。
methods(){
  demo(callbackFn){ ... }
}
...
mounted() {
  this.pid = pubsub.subscribe('hello',this.callbackFn) //订阅消息
}
4. 发布消息
// 在 B 组件中。
pubsub.publish('hello',data)	// hello为发布的消息名,data为发布的消息数据。
5. 最好在订阅组件的 beforeDestroy 钩子函数中,取消订阅。
// 在 A 组件中。
beforeDestroy() {
  pubsub.unsubscribe(this.pid) //取消订阅
}

$ nextTick 实例方法

语法

this.$nextTick(callbackFn)

作用

在下一次 DOM 更新结束后执行其指定的回调。

应用场景

当改变数据后,要基于更新后的新DOM进行某些操作时,要在 nextTick 所指定的回调函数中执行。

Vue 封装的 过渡 & 动画

在插入、更新或移除 DOM 时,在合适的时机给元素动态添加响应式样式类。

  • 元素进入样式

    • v-enter:进入的起点

    • v-enter-active:进入过程中

    • v-enter-to:进入的终点

  • 元素离开样式

    • v-leave:离开的起点

    • v-leave-active:离开过程中

    • v-leave-to:离开的终点

使用 CSS 动画

准备动画

使用 @keyframes 定义一个动画。

@keyframes fairy {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
}
准备样式
/* 没有在 template 标签中配置 name 属性 */
.v-enter-active {
  animation: fairy 0.5s linear;
}
.v-leave-active {
  animation: fairy 0.5s reverse linear;
}
/* 没有在 template 标签中配置 name 属性值为 hello */
.hello-enter-active {
  animation: fairy 0.5s linear;
}
.hello-leave-active {
  animation: fairy 0.5s reverse linear;
}
使用 <transition>标签
<transition name='hello' appear>
    <h1 v-show='isShow'>你好啊!</h1>
</transition>
  • appear属性表示一上来就应用样式。
使用 <transition-group>标签

如果有多个元素需要同时应用同一动画,则需要使用 <transition-group> 标签。

<transition-group name="hello" appear>
    <h1 v-show="isShow" key="1">你好啊</h1>
    <h1 v-show="!isShow" key="2">小仙女</h1>
</transition-group>
  • 注意:每个元素都要指定key值。

使用 CSS 过渡

1. 准备样式
/* 进入的起点,离开的终点 */
.hello-enter,
.hello-leave-to {
  transform: translateX(-100%);
}
/* 进入的终点,离开的起点 */
.hello-enter-to,
.hello-leave {
  transform: translateX(0);
}
/* 进入过程中,离开过程中 */
.hello-enter-active,
.hello-leave-active {
  transition: 0.5s linear;
}
2. 使用 <transition><transition-group> 标签

同上略。

配合使用第三方动画库 Animate.css

安装

yarn add animate.css

引入

import 'animate.css'

使用

<transition-group
    appear
    name="animate__animated "
    enter-active-class="animate__swing"
    leave-active-class="animate__backOutDown"
>
    <h1 v-show="isShow" key="1">你好啊</h1>
    <h1 v-show="!isShow" key="2">小仙女</h1>
</transition-group>

Vue 中的 ajax

Vue 脚手架配置代理服务器 devServer

解决发送 ajax 请求的跨域问题。

方法一

在vue.config.js中添加如下配置:

devServer: {
    proxy: 'http://localhost:5000'	// 目标服务器
}

请求时:

// 前端 App 运行的服务器地址为 http://localhost:8080/
axios.get('http://localhost:8080/students').then(...)

备注:

  • 当请求的资源前端没有时,才会转发给目标服务器。(即优先请求前端资源)

    • 如果
  • 优点:配置简单,请求资源时直接发给前端(8080)即可。

  • 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。

public 文件夹相当于 localhost:8080 的根路径。

方法二

在vue.config.js中添加如下配置:

module.exports = {
	devServer: {
      proxy: {
      '/api1': {// 匹配所有以 '/api1'开头的请求路径
        target: 'http://localhost:5000',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api1': ''}	// 重写请求路径,将'/api'替换成''
      },
      '/api2': {// 匹配所有以 '/api2'开头的请求路径
        target: 'http://localhost:5001',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api2': ''}
      }
    }
  }
}

/*
   changeOrigin 设置为 true 时,服务器收到的请求头中的 host 为:localhost:5000
   changeOrigin 设置为 false 时,服务器收到的请求头中的 host 为:localhost:8080
   changeOrigin 默认值为 true
*/

备注:

  • changeOrigin 设置为 true 时,服务器收到的请求头中,host 为 localhost:5000
  • changeOrigin 设置为 false 时,服务器收到的请求头中,host 为 localhost:8080(与本地相同)
  • changeOrigin 默认值为 true 。

vue - router

基本概念

vue - router

vue 的一个插件库,专门用来实现 SPA 应用。

SPA 应用
  • 单页 Web 应用 SPA (singe page web application)
  • 整个应用只有 一个完整的页面
  • 点击页面中的导航链接 不会整体刷新 页面,只会做页面组件的 局部刷新
  • 数据需要通过 ajax 请求获取。
路由 route
  • 一个路由 route 就是一组映射关系( key - value )。

  • 多个路由需要 路由器 router 来管理。

  • key 为路径,value 可能是 functioncomponent

后端路由
  • value 是 function,用于处理客户端提交的请求。
  • 工作过程:服务器收到一个请求时,根据 请求路径 找到匹配的 函数 来处理请求,返回响应数据。
前端路由
  • value 是 component,用于展示页面内容。
  • 工作过程:当浏览器的路径改变时,对应的组件就会显示。

基本使用

安装 vue-router 插件
yarn add vue-router@3 # 安装 vue-router3 的最新版本

备注:

  • vue-router4 只能在 vue3 中使用。
  • Vue-router3 才能在 vue2 中使用。
引入

在 main.js 中

// 引入 VueRouter
import VueRouter from 'vue-router'
应用

在 main.js 中

// 应用插件 VueRouter
Vue.use(VueRouter)
编写 router 配置项

在 src 目录下创建 router 文件夹,新建 index.js 文件。

// 该文件用于创建整个应用的路由器

// 引入 VueRouter
import VueRouter from 'vue-router'
// 引入需要被路由的组件
import Home from '../components/Home'
import About from '../components/About'

// 创建 router 实例对象,来管理一组一组路由规则。
const router = new VueRouter({
  routes: [
    {
      path: '/home',
      component: Home,
    },
    {
      path: '/about',
      component: About,
    },
  ],
})
// 默认暴露 router 实例对象
export default router
在 Vue 实例中,加入 router 配置项。

在 main.js 中

new Vue({
  render: h => h(App),
  router: router
}).$mount('#app')
// 简写成
new Vue({
  render: h => h(App),
  router
}).$mount('#app')
router-link 标签:实现路由切换
<router-link class="list-group-item" active-class="active" to="/about">About</router-link>
<router-link class="list-group-item" active-class="active" to="/home">Home</router-link>
  • to 属性:路由跳转的目标路径。
  • active-class 属性:可配置选中样式。
router-view 标签:指定组件的呈现位置,路由占位符
<router-view />
注意
  • 路由组件通常放在 pages 文件夹中,一般组件通常放在 components 文件夹中。
  • 通过切换,被隐藏的路由组件,默认是被销毁了的,需要的时候再去重新挂载。
  • 每个组件实例身上都有 $route 属性,里面存储自己的路由配置信息。
  • 整个应用只有一个 router,可以通过组件实例的 $router 属性获取。

多级路由(嵌套路由)

配置路由规则,使用 children 配置项。
// 在 router/index.js 文件中
routes:[
  {
    path:'/about',
    component:About,
  },
  {
    path:'/home',
    component:Home,
    children:[ 	//通过children配置子级路由
      {
        path:'news', 	//此处一定不要写:/news
        component:News
      },
      {
        path:'message',	//此处一定不要写:/message
        component:Message
      }
    ]
  }
]
路由切换
<router-link to="/home/news">News</router-link>

注意:to 属性值要写完整路径

路由的 query 参数

传递参数
属性 to 的字符串写法

在跳转的组件中:

<!-- 跳转并携带 query 参数,to 的字符串写法 -->
<router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
<!-- 模板字符串 -->
<router-link :to="`/home/message/detail?id=${message.id}&title=${message.title}`">
  {{ message.title }}
</router-link>
属性 to 的对象写法
<router-link
  :to="{
  	path: '/home/message/detail',
    query: {
      id: message.id,
      title: message.title,
    }
}"
>{{ message.title }}</router-link>
接收参数

在被跳转的组件中:

<template>
  <ul>
    <li>编号:{{ this.$route.query.id }}</li>
    <li>标题:{{ this.$route.query.title }}</li>
  </ul>
</template>

命名路由

作用:可以通过为路由命名,简化路由的跳转。

为路由命名

在 src/router/index.js 文件中:

routes: [
  {
    path: '/home', 
    component: Home,
    children: [
      {
        path: 'message',
        component: Message,
        children: [
          {
            name: 'detail',	// 为三级路由命名
            path: 'detail', 
            component: Detail,
          },
        ],
      },
    ],
  },
],
简化跳转
<!--简化前,需要写完整的路径 -->
<router-link to="/home/message/detail">跳转</router-link>

<!--简化后,直接通过名字跳转 -->
<router-link :to="{name:'detail'}">跳转</router-link>

<!--简化写法配合传递参数 -->
<router-link
  :to="{
  	name: 'detail',
    query: {
      id: message.id,
      title: message.title,
    }
}"
>{{ message.title }}</router-link>

路由的 params 参数

配置路由,声明接收 params 参数。
routes: [
  {
    path: '/home', 
    component: Home,
    children: [
      {
        path: 'message',
        component: Message,
        children: [
          {
            name: 'detail',
            path:'detail/:id/:title', //使用占位符声明接收params参数
            component: Detail,
          },
        ],
      },
    ],
  },
]
传递参数
<!-- 跳转并携带params参数,to的字符串写法 -->
<router-link :to="/home/message/detail/666/你好">跳转</router-link>

<!-- 跳转并携带params参数,to的对象写法 -->
<router-link 
	:to="{
		name:'detial',
		params:{
		   id:666,
       title:'你好'
		}
	}"
>跳转</router-link>

特别注意

路由携带 params 参数时,若使用 to 的对象写法,则不能使用 path 配置项,必须使用 name 配置项。

接收参数
<template>
  <ul>
    <li>编号:{{ this.$route.params.id }}</li>
    <li>标题:{{ this.$route.params.title }}</li>
  </ul>
</template>

路由的 props 配置

作用:让路由组件更方便地收到参数。

routes: [
  {
    path: '/home', 
    component: Home,
    children: [
      {
        path: 'message',
        component: Message,
        children: [
          {
            name: 'detail',
            path:'detail/:id/:title', //使用占位符声明接收params参数
            component: Detail,
            
            // 写法一:props 值为对象,该对象中所有的 key-value 的组合最终都会通过 props 传给 Detail 组件。
            props:{a:900,b:'hello'}
            
            // 写法二:props 值为布尔值,当布尔值为 true 时,则会把路由收到的所有 params 参数通过 props 传给 Detail 组件。
            props:true
            
            // 写法三:props 值为函数,该函数返回一个对象,对象中每一对 key-value 都会通过 props 传给 Detail 组件。
            props(route){
          		return {
          			id:route.query.id,
          			title:route.query.title
          		}
          	}
      			// 等同于
            props({query}){		// ES6 解构赋值
          		return {
          			id:query.id,
          			title:query.title
          		}
          	}
            // 等同于
            props({ query: { id, title } }) {	// ES6 解构赋值
                return {
                  id: id,
                  title: title,
              }
            }
          }
        ]
      }
    ]
  }
]
接收参数

在 Detail.vue 文件中:

写法一
<template>
  <ul>
    <li>{{ a }}</li> 	<!-- 900 -->
    <li>{{ b }}</li>	<!-- hello -->
  </ul>
</template>

<script>
export default {
  name: 'Detail',
  props: ['a', 'b']	// 写法一:接收 props 对象中配置的 key
}
</script>
写法二
<template>
  <ul>
    <li>编号:{{ id }}</li>
    <li>标题:{{ title }}</li>
  </ul>
</template>

<script>
export default {
  name: 'Detail',
  props: ['id', 'title']	// 写法二:接收 params 参数
}
</script>
写法三

在 Message.vue 文件中:

<router-link
  :to="{
    name: 'detail',
    query: {
      id: message.id,
      title: message.title,
    },
  }"
>跳转</router-link>

注意:必须使用 name 配置项。

在 Detail.vue 文件中:

<template>
  <ul>
    <li>编号:{{ id }}</li>
    <li>标题:{{ title }}</li>
  </ul>
</template>

<script>
export default {
  name: 'Detail',
  props: ['id', 'title']	// 写法二:接收 props 函数返回对象中的 key
}
</script>

<router-link> 标签的 push/replace 属性

  • 作用:控制路由跳转时,操作浏览器历史记录的模式。

  • 浏览器的历史记录有两种写入方式:

    • push:追加历史记录。(压栈)
    • replace:替换当前记录。
  • 默认为 push 模式,开启 replace 模式

    <router-link replace ...>News</router-link>
    <!-- OR -->
    <router-link :replace='true' ...>News</router-link>
    

编程式路由导航

不借助 实现路由跳转,让路由跳转更加灵活。

// $router 的两个 API
this.$router.push({
  name:'detail',
  params:{
    id:xxx,
    title:xxx
  }
})

this.$router.replace({
  name:'detail',
  params:{
    id:xxx,
    title:xxx
  }
})

this.$router.forward()	// 前进
this.$router.back()	// 后退
this.$router.go(-2)	// 后退两步
this.$router.go(3)	// 前进三步

缓存路由组件

作用:让不展示的路由组件保持挂载,不被销毁。

<keep-alive include="News">
  <router-view></router-view>
</keep-alive>

<keep-alive :include="['News','Message']">
  <router-view></router-view>
</keep-alive>

备注:include的值为 组件名

两个路由独有的生命周期钩子

路由组件所独有的两个生命周期钩子,用于捕获路由组件的 激活状态 activated失活状态 deactivated

activated
  • 路由组件被激活时触发。
deactivated
  • 路由组件失活时触发。

路由守卫

作用:对路由进行权限控制。

分类
  • 全局路由守卫
  • 独享路由守卫
  • 组件内路由守卫
全局路由守卫

写在 router/index.js 文件中,在 export default router 之前。

全局前置路由守卫
  • 何时被调用
    • 初始化时被调用。
    • 每次路由切换被调用。
router.beforeEach((to, from, next) => {
  console.log('全局前置路由守卫被调用了。')
  console.log('beforeEach', to, from)

  if (to.meta.isAuth) {	// 判断当前路由是否需要权限控制
    if (localStorage.getItem('school') === 'dlut') { // 权限控制的具体规则
      next() // 放行
    } else {
      alert('暂无权限查看!')
      // next({ name: 'about' })	// 跳转到 About.vue 组件
    }
  } else {
    next()	// 放行
  }
})
全局后置路由守卫
  • 何时被调用

    • 初始化时被调用。

    • 每次路由切换被调用。

    • 后置路由守卫没有 next 函数。

router.afterEach((to, from) => {
  console.log('全局后置路由守卫被调用了。')
  console.log('afterEach', to, from)
  if(to.meta.title){
    document.title = to.meta.title	// 修改网页的 title
  }else{
    document.title = 'vue-demo'
  }
})
独享路由守卫
  • 某个路由所独享的路由守卫。
  • 写在具体的路由配置中。
  • 路由切换前被调用。
  • 只有前置路由守卫,没有后置路由守卫。
// router/index.js 文件中
{
  name: 'news',
  path: 'news',
  component: News,
  meta: { isAuth: true, title: '新闻' },
  beforeEnter: (to, from, next) => {
    console.log(to, from, next)
    if (localStorage.getItem('school') === 'dlut') {
      next() // 放行
    } else {
      alert('暂无权限查看!')
    }
  }
}
组件内路由守卫
beforeRouteEnter(to, from, next)
  • 进入守卫:通过路由规则,进入该组件时被调用。
beforeRouteEnter(to, from, next) {
  console.log('beforeRouteEnter', to, from)
  next()
}
beforeRouteLeave(to, from, next)
  • 离开守卫:通过路由规则,离开该组件时被调用。
beforeRouteLeave(to, from, next) {
  console.log('beforeRouteLeave', to, from)
  next()
}

路由器的两种工作模式

hash 值
  • 对于一个 url 来说,# 及其后面的内容就是 hash 值。
  • hash 值不会包含在 HTTP 请求中,即 hash 值不会作为路径的一部分发送给服务器。
路由模式
hash 模式(默认)
  • 地址中带有 #,不美观。
  • 若以后地址通过第三方手机 app 分享,若 app 校验严格,则地址会被标记为不合法。
  • 兼容性较好。
history 模式
const router = new VueRouter({
  mode: 'history',
  routes:[...]
})
  • 地址中没有 #,简洁美观。
  • 兼容性和 hash 模式相比略差。
  • 应用部署上线时,需要后端支持,解决刷新页面服务端 404 问题。

补充内容

ESLint

配置

使用 JavaScript、JSON 或 YAML 文件指定整个目录及其所有子目录的配置信息。

  • 方法一: .eslintrs.* 文件。

    
    
  • 方法二: package.json 文件中的 eslintConfig 字段。

  • "eslintConfig": {
      "rules": {
        "vue/multi-word-component-names":"off"	/* 关闭组件驼峰命名校验规则 */
      }
    }
    

查看 webpack 所有版本

npm view webpack versions

查看 less-loader@11 依赖的包与版本

npm view less-loader@11 peerDependencies

安装 less-loader

yarn add less-loader	安装最新版本
yarn add less-loader@10		安装最近一个10版本

安装 less

yarn add less	

安装 nanoid ( uuid 的简化版 )

yarn add nanoid

一个重要的内置关系

VueComponent.prototype.__proto__ === Vue.prototype

意义:让组件实例对象(vc),可以访问到 Vue 原型上的属性、方法。

Object.hasOwn()

如果指定的对象自身有指定的属性,则静态方法 Object.hasOwn() 返回 true。如果属性是继承的或者不存在,该方法返回 false

语法
Object.hasOwn(obj, prop)
参数
  • obj:要校验的对象。
  • prop:要测试属性的 String 类型的名称。
返回值

如果指定的对象中直接定义了指定的属性,则返回 true;否则返回 false

CSS3 动画

1. 定义动画(@keyframes)
/* 定义一个动画 */
@keyframes fairy {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0);
  }
}
2. 在样式中使用动画(animation)
.enter {
    /* 0.5s匀速播放刚刚定义的动画 */
	animation: fairy 0.5s linear;
}
3. 在元素中应用样式
<h1 class="enter">你好啊!</h1>

浏览器发送网络请求

  • xhr
    • jQuery
      • 对 xhr 的封装
      • 核心是封装DOM操作(80%左右),其他只占 20% 左右。
      • 不推荐
    • axios
      • 对 xhr 的封装
      • Promise
      • Vue 尤雨溪官方推荐
  • fetch
    • 优点:和 xhr 平级
    • 缺点
      1. 包两层 Promice
      2. 兼容性差,不支持 IE 浏览器。
跨域问题 XMLHttpRequest

浏览器发送网络请求时,违背了 同源策略

同源策略规定了以下内容必须保持一致:

  • 协议名
  • 主机名
  • 端口号

备注:跨域并不是无法发送请求,实际上,请求已经发送,服务器也接收了请求,并且返回了数据,但是因为存在跨域问题,无法让请求方接收。

解决方法
  1. CORS:后端解决,是真正意义上的解决跨域。

    不用前端人员去做任何事情,需要后端人员在返回响应的时候,加几个特殊的响应头。

  2. jsonp

    原理

    • 借助 script 标签里面的 src 属性在引入外部资源时,不受同源策略限制的特点。

    缺点:

    • 需要前后端配合,实际开发中应用很少。
    • 只能解决 Get 请求的跨域问题。
  3. 配置代理服务器

    备注:服务器与服务器之间传递数据,不用 ajax,而是用 http 请求,不存在跨域问题。ajax 是前端独有技术,ajax 才会出现跨域问题。

    • nginx 开启代理服务器
    • vue cli 开启代理服务器
跨域问题报错信息

Node + Express 搭建测试服务器

  1. 创建一个空文件夹 demo-server

  2. 用 vscode 打开文件夹

  3. 执行命令 npm init

  4. 安装 express

yarn add express
  1. 新建 server.js
// 引入 express
const express = require('express')
// 创建实例对象
const app = express()
app.use(express.static(__dirname + '/static'))

app.get('/person', (req, res) => {
  res.send({
    name: 'tom',
    age: 18,
  })
})

app.listen(5005, err => {
  if (!err) console.log('服务器启动成功了。')
})

  1. 将打包好的 dist 文件夹下的文件复制到 static 文件夹中

  2. 启动服务器

    node server.js
    
  3. 在浏览器中访问 http://localhost:5005 即可运行打包后的 vue 应用。

在搭建好的服务器端解决 history 模式刷新页面 404 问题

  • 借助 connect-history-api-fallback 中间件

  • 安装

    yarn add connect-history-api-fallback
    
  • 在 server.js 中引入

    // 引入 connect-history-api-fallback 中间件
    const history = require('connect-history-api-fallback')
    
  • 应用

    app.use(history())
    

    注意:需在静态资源之前应用。

  • 启动服务器

    node server.js
    
  • 访问部署后的应用,验证问题已解决。

ElementUI

按需引入
安装 babel-plugin-component
yarn add babel-plugin-component -D
修改 babel.config.js 文件
module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset',
    ['@babel/preset-env', { modules: false }]
  ],
  plugins: [
    [
      'component',
      {
        libraryName: 'element-ui',
        styleLibraryName: 'theme-chalk',
      }
    ]
  ]
}
按需引入
// 在 main.js 中
// 按需引入
import { Button } from 'element-ui'
// 应用 ElementUI
Vue.component(Button.name,Button)
// or
Vue.use(Button)

本文标签: 学习笔记 Vue