前言

这篇文章主要给大家介绍关于vue的相关资料,是一篇很完整的vue教程,本文通过理论及示例代码的形式展示给大家。

vue简介

vue是什么
vue是一个渐进式的js框架

什么是渐进式框架
对项目参与的少(在项目中可以使用其他的框架或者类库)

MVC和MVVM

mvc 是一个后台的软件设计模式,将程序分为三部分 M(model 模型) V(view 视图) C(controller 控制器)

model:操作和数据库相关的逻辑
view:和前端相关的所有界面
controll:控制器来协调什么时候显示view 什么时候调用model

mvvm 将mvc中view又细分为M V VM
M:model 数据 自己定义的数据或者请求的接口数据
V:单纯的html
VM:操作html和数据的逻辑

vue的特点

轻量级的框架
Vue.js 能够自动追踪依赖的模板表达式和计算属性,提供 MVVM 数据绑定和一个可组合的组件系统,具有简单、灵活的 API,使读者更加容易理解,能够更快上手。

双向数据绑定
声明式渲染是数据双向绑定的主要体现,同样也是 Vue.js 的核心,它允许采用简洁的模板语法将数据声明式渲染整合进 DOM。

指令
Vue.js 与页面进行交互,主要就是通过内置指令来完成的,指令的作用是当其表达式的值改变时相应地将某些行为应用到 DOM 上。

组件化
组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。

在 Vue 中,父子组件通过 props 传递通信,从父向子单向传递。子组件与父组件通信,通过触发事件通知父组件改变数据。这样就形成了一个基本的父子通信模式。

在开发中组件和 HTML、JavaScript 等有非常紧密的关系时,可以根据实际的需要自定义组件,使开发变得更加便利,可大量减少代码编写量。

组件还支持热重载(hotreload)。当我们做了修改时,不会刷新页面,只是对组件本身进行立刻重载,不会影响整个应用当前的状态。CSS 也支持热重载。

路由
Vue-router 是 Vue.js 官方的路由插件,与 Vue.js 深度集成,用于构建单页面应用。Vue 单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来,传统的页面是通过超链接实现页面的切换和跳转的。

状态管理
状态管理实际就是一个单向的数据流,State 驱动 View 的渲染,而用户对 View 进行操作产生 Action,使 State 产生变化,从而使 View 重新渲染,形成一个单独的组件。

vue的使用

单页面应用

script标签中引入

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue Demo</title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
  <p>{{ message }}</p>
</div>

<script>
new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue.js!'
  }
})
</script>
</body>
</html>

<script src="https://unpkg.com/vue/dist/vue.js"></script>

工程化

脚手架 vue-cli

Vue CLI

这里有之前写好的所以直接上链接了

vue对象的创建

var  vm=new Vue({
		el:"",
		data:{
		}
	})

这里说一下一个问题就是 vue中的data为什么(必须)是一个函数,单页面应用就无所谓了,但是脚手架只有一个html 因为vue是组件化开发,下面来简单说明一下。

vue中的data为什么(必须)是一个函数

往深处说就要扯到 js 的栈 堆 池了,这里我只简单说明一下

1、vue中组件是用来复用的,为了防止data复用,将其定义为函数。

2、vue组件中的data数据都应该是相互隔离,互不影响的,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响,就需要通过data函数返回一个对象作为组件的状态。

3、当我们将组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,拥有自己的作用域,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。

4、当我们组件的data单纯的写成对象形式,这些实例用的是同一个构造函数,由于JavaScript的特性所导致,所有的组件实例共用了一个data,就会造成一个变了全都会变的结果。

注:可以建两个组件测试一下,比如我们新建A,B两个组件在不把data写成函数的情况下 在A组件中的data里面写一个变量name 在B组件中的data里面也写个name 在随意A B 组件中更改name的值 组件A B都会对应着改变

单页面应用、多页面应用

vue-cli是vue的脚手架,可以帮助我们来快速的搭建单页面应用程序,快速实现以vue+webpack的工程化项目

单页面应用
所有的功能都在一个html页面实现,页面功能的切换是通过路由来实现的

优点
跳转速度快

缺点
首屏加载慢

多页面应用
项目功能是由多个html页面组成的,页面功能的切换是通过a标签的href属性或者表单的action属性来实现的

优点:首屏加载快

缺点:跳转的效率不高

vue项目目录

dist —— 打包后生成静态文件目录(可在vue.config.js自行设置打包后的包名)
node_modules —— 项目依赖的js包
src —— 项目根目录
http ——项目所有接口封装目录(自行设置)
assets —— 静态资源文件
components —— 项目中公共的组件
router —— vue-router目录,定义路由跳转
store —— vuex目录,定义项目状态管理
util —— 工具类文件
views —— 项目开发各模块组件
App.vue —— 项目根组件
main.js —— 项目入口js文件
.browserslistrc —— 配置使用css兼容性插件使用范围
.gitignore —— git忽略提交配置文件
babel.config.js —— 工具链,向后兼容
package-lock.json —— 记录当前状态下实际安装的各个npm package的具体来源及版本号
package.json —— 项目所需的各种模块以及项目的配置信息(名称、版本、许可证等)
postcss.config.js —— css代码转换配置文件
vue.config.js —— vue配置文件,用于设置代理,打包配置等(自己创建的)

组件

组件的使用就两种方式 在父组件中使用 在路由中使用

组件:是根据ui界面来划分的功能小模块 组件包含三部分 template 模板 script 逻辑功能 css 样式

组件开发的好处

1、代码好维护
2、开发好的组件功能可以复用

组件在工程后的项目中是以 xxx.vue文件来命名的
组件分为两种 基本组件 功能组件

基本组件就是项目的结构组件
功能组件 是可以复用的 比如删除 加入购物车 搜索 排序

这里有使用组件化造的几个轮子(有些知识点后续在讲)
如何使用vue封装组件(造轮子)

新建一个组件的步骤:
1、新建一个 xxx.vue
2、在 xxx.vue 中 包含三部分 tempalte script css

注意 的是template中有且只有一个父元素 根元素

3、将组件挂载到父元素上
1、在父组件中引入新建的组件

import 名 from './components/名'

2、将子组件挂载到父组件上

components:{}

3、在父组件的template中输出

<组件名></组件名><组件名/>

之前写的案列:什么是组件

样式问题:

局部样式的设置 在组件中给style标签添加 scoped的属性

在style中 添加 lang=“scss” <style lang="scss" scoped>

vue的模板语法

1、变量的输出 插值表达式 {{ 变量 }}
在差值表达式中可以写简单的逻辑

<template>
  <div>
      <p>{{ name }}</p>
  </div>
</template>

<script>
export default {
    name:"demo",
    data()
    {
      return{
        name:"学习vue"
      }
    }
}
</script>

<style lang="scss" scoped>

</style>

浏览器显示 学习vue

注:<template></template>里面有且只有一个子元素,可以简单理解成标签内只有一个大盒子div剩下的内容在div里面完成~

2、指令:vue提供的作用在html标签上特殊属性 以v-开头 可以解析变量

vue的常用指令

1v-text 标签上的文本输出

2v-html 可以解析html标签的文本输出

3v-for 循环遍历数组或者对象的输出

语法:v-for="(item,key) in 数组或者对象"

item:元素
key:下标

循环时你给谁加v-for他就循环谁比如给ul添加每次循环都是ul 给li加每次循环遍历只是li增加

注:现在使用v-for时须加key值 那么要解释的话虚拟dom,diff算法都要说了,细节性的东西去问细节吧

key的作用主要是为了高效的更新虚拟DOM。另外vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们,否则vue只会替换其内部属性而不会触发过渡效果。

简单一句话概括 key代表了唯一性,比如说你数据列表里面的name值有好几个相同的值,vue其实只是渲染了第一个,也就是说你改变这个值,其他相同的值会跟着改变,所以要加上key代表唯一性 大白话 易懂

4、v-on 绑定事件

语法:v-on:事件名=“方法名” 可以简写维  @事件名=“方法名”

在哪写呢

export default {
    name:"demo",
    data()
    {
      return{
        name:"123"
      }
    },
    methods: {
      sub()
      {
        alert("111111111111")
      },
      sub1()
      {
        alert("222222222222")
      }
    }
}

使用 methods:和data同级
name在methods里面如何操作data中的数据呢?
直接 this.属性名

5、v-model 实现的是表单元素的数据双向绑定

6、v-if 根据条件显示或者删除元素和组件

7、v-show 根据条件显示或者隐藏元素和组件

8、v-bind 给元素绑定属性 title=“sdsd” v-bind:属性名=“变量” 简写 :属性名=“值”

9、v-cloak 解决差值表达式闪烁问题
用法:
给标签添加此指令,然后给这个指令设置样式

<template>
  <div>
      <p v-text="name"></p>
      <p v-html="name"></p>
      <ul>
        <li v-for="(e,i) in list" :key="i">

        </li>
      </ul>
      <button v-on:click="sub()"></button>
      <button @click="sub1()"></button>
      <input type="text" v-model="name">
      <img :src="name" alt="">
      <img v-bind:src="name" alt="">
  </div>
</template>

vue的宗旨是尽可能少的操作dom,采用的是虚拟dom的思想
虚拟dom是用js描述元素与元素之间的关系,目的是高效快速的渲染

1.prevent:阻止默认事件(常用)
2. stop:阻止事件冒泡(常用)
3. once:事件只触发一次(常用)
4.captrue:使用事件的捕捉模式(不常用)
5.self:只有event.target是当前操作的元素时才触发事件(不常用)
6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕(不常用)

v-if和v-show的区别:

1、条件为真的时候 都会显示元素 条件维假 v-if删除元素 v-show是隐藏元素

2、v-if有更高的切换成本 v-show有更高的渲染成本

怎么解决差值表达式的闪烁问题呢?

给标签添v-cloak指令,然后给这个指令设置样式

标签[v-cloak]{
	display: none;
}

计算属性computed:

computed:vue给我们提供了一个类似属性但是又又可以添加逻辑的操作数据的方式 称为计算属性
定义方式:

computed:{
	方法名(){
		每一个计算属性中的方法都必须有一个return
	}
}	

也是和data同级顺序无所谓

<div>
    <input type="text" name="" id="" v-model="num">
    {{newNum}}
  </div>
  <script>
export default {
    data(){
        return{
            num:0
        }
    },
    computed:{
        newNum(){
            console.log('触发了')
            return this.num+'123'
        }
    }
}
</script>

只要属性值发生了变化就会执行没有变化读缓存

computed和methods的区别:

methods没有缓存性 只要调用就会执行

computed具有缓存性 只有data属性值发生改变才会重新调用 否则就是读取缓存中的数据

watch 监听

介绍:watch vue给每个属性设置了监听,只要属性的值发生改变 就会触发所对应的函数

语法:也是与data同级

watch:{
	属性名:{
		handler(newval,oldval){
			//属性值发生改变会触发的函数
		},
		immediate: true 需要我们在有初始值的时候也会触发handler函数 需要添加该属性
		deep:true  我们要监听对象属性的时候需要深度监听  需要添加该属性

	}}

1、普通的属性的怎么监听: 直接监听
2、有初始值该怎么监听:immediate: true
3、深度监听怎么做:deep:true

watch:{
        $route(val, oldVal){//普通的watch监听
            console.log("a: "+val, oldVal);
        },
        b:{//深度监听,可监听到对象、数组的变化
            handler(val, oldVal){
                console.log("b.c: "+val.c, oldVal.c);//但是这两个值打印出来却都是一样的
            },
            deep:true
        }
    }

methods computed watch的区别

1、methods 没有缓存 只要调用就会执行

2、computed 计算属性 具有缓存性 依赖于属性的值 只有属性的值发生改变才会执行

3、watch 监听 没有缓存性,只要属性的值发生改变就可以执行,可以实现属性发生改变异步的调取数据

filter 过滤器

一句话概括作用:格式化文本输出(给数据换一种形式输出但是不改变数据原本值)

filter分为全局过滤器局部过滤器

全局:在main.js中挂载
语法:

Vue.filter("名",(形参1)=>{
	//形参1默认是我们要处理的字符串
})
// 全局多个
var filterObj={
  "addName":(val)=>{
    return val+'++'
  },
  "delName":(val)=>{
    return val+'--'
  },
}
for(let key in filterObj){
  Vue.filter(key,filterObj[key])
}

调用过滤器:过滤器只能通过 差值表达式v-bind属性绑定来实行调用,调用是通过管道符号来实现
{{变量|过滤器}}

要注意的是过滤器是可以传参数的
方法:{{变量|过滤器(参数)}} 参数的个数是没有限制的

定义的时候形参是从第二个开始接受 ,第一形参默认的是要处理的字符串

Vue.filter("名",(形参1,形参2)=>{
	//形参1默认是我们要处理的字符串
})

局部:组件内 写在data同级

filters:{
	函数名/过滤器名(str){
		默认的第一个形参也是要处理的字符串
	}
}

directive 自定义指令

在定义自定义指令的时候指令名是不带v-的但是,调用的时候需要带v-

v-自定义指令

全局自定义指令 挂载到main.js中
语法:

vue.directive("名",{
	// 自定义指令的钩子函数  用到哪个写哪个  不用的可以不用管
})

局部自定义指令
语法:

directives:{
	//自定义指令的钩子函数  用到哪个写哪个  不用的可以不用管
}

钩子
钩子函数
指令定义函数提供了几个钩子函数(可选):

bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。

inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。

update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。

componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。

unbind: 只调用一次, 指令与元素解绑时调用。

钩子函数参数
钩子函数的参数有:

el: 指令所绑定的元素,可以用来直接操作 DOM 。
binding: 一个对象,包含以下属性:
    name: 指令名,不包括 v- 前缀。
    value: 指令的绑定值, 例如: v-my-directive=“1 + 1”, value 的值是 2。
    oldValue: 指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    expression: 绑定值的表达式或变量名。 例如 v-my-directive=“1 + 1” , expression 的值是 “1 + 1”。
    arg: 传给指令的参数。例如 v-my-directive:foo, arg 的值是 “foo”。
    modifiers: 一个包含修饰符的对象。 例如: v-my-directive.foo.bar, 修饰符对象 modifiers 的值是 { foo: true, bar: true }。
vnode: Vue 编译生成的虚拟节点。
oldVnode: 上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
以下实例演示了这些参数的使用

自定义指令钩子的参数:

el:绑定元素的原生dom对象 可以直接操作的

全局和局部使用钩子函数与不使用钩子函数的写法

Vue.directive("isflag",(e)=>{
  e.style.color='red'
})
Vue.directive("isflag",{
  bind:((e)=>{
    e.style.color='red'
  })
})
directives:{
    isflag:((e)=>{
      e.style.color='red'
    }),
    isflag:{
      bind:((e)=>{
        e.style.color='red'
      })
    }
  }

样式绑定

类的绑定:<p :class="name==123?'active':'hide' ">11111</p>
行内绑定:<p :style="{'color':name=='123'?'red':'yellow'}">22222</p>

这里写的是三目运算剩下的同理很简单直接写变量即可

组件通信

1、父传子
a、在父组件的子组件标签上绑定一个属性,挂载要传输的变量(父组件上做的事)传
b、在子组件中我们要通过组件的props属性来接受,props属性可以是数组也可以是对象,props:["自定义属性"] ,接过来的数据是直接可以当成属性来用

2、子传父
a、在父组件上定义一个方法,然后在父组件的子组件标签上通过绑定自定义事件来挂载这个方法
b、在子组件中的方法中通过 this.$emit("自定义事件名")来调用父组件的方法,子组件中的值是通过$emit的第二个参数开始进行传递的

3、兄弟之间的通信
Bus总线通信
a、在src目录中新建一个Bus.js来充当总线,bus.js中要抛出一个空vue实例
b、在需要传输数据的一方引入总线文件,然后通过Bus.$emit("自定义事件名",要传输的数据)来派发事件
c、在要接受数据的组件中引入总线,在created()钩子函数中通过Bus.$on(“事件名”,(data)=>{data就是接受的数据})
d、在beforeDestory()中销毁事件 Bus.$off("事件名")

方法二:把bus定义在vue的prototype上,在全局都可以使用

main.js中加入如下代码

const bus = new Vue()
Vue.prototype.$bus = bus

这样我们就不需要再自己写bus.js引入了,就可以直接再组建中使用

this.$bus.on(),this.$bus.$emit(),this.$bus.$off()

这里有之前写好的组件通讯介绍:组件通讯

附加组件通讯小demo:使用组件通讯完成的小案列

props验证

props:是一个属性用来接受父组件传输的数据

咱们vue是单项数据流 props用来接受咱么父组件传输的数据

接受方法props:[“父组件自定义属性”]

开启数据类型的验证

props:{
		属性:数据类型
	}

数据类型验证:规范数据的传输

验证的数据类型:

	String
	Number
	Boolean
	Array
	Object
	Date
	Function
	Symbol

可以设置默认数据,如果父组件不传值或者传的是undefinded的数据 那么就会显示默认的数据

props:{
		属性:{
			type:类型,
			default:默认值
		}
	}

生命周期

生命周期:

生命周期对象或者实例的一个从无到有再到无的过程

在这个过程中系统给我们提供了一些钩子函数,这些钩子函数不用手动的调用,在对象或者组件到特定的阶段会自动的执行

作用:
在生命周期的钩子中添加自己的代码,实现特定的功能,来帮助我们实现某些效果

系统给我们提供了8个钩子函数:

实例或者组件的初始化阶段 1次

beforeCreate 在这个钩子上data和methods中的数据都是没有办法使用的 在这个钩子运行的时候只有实例本身的一些事件和钩子

created 在这个钩子上 data和methods中的数据是可以使用的 是最早开始使用data和methods中数据

实例或者组件的挂载阶段 1次

beforeMount 在内存中已经生成html页面,但是还没有跟新到页面上

mounted 内存和一面已经同步 这个时候实例或者组件的挂载已经结束 是最早可以操作的dom元素的钩子函数

实例或者组件的运行阶段 当data的数据被修改的时候调用 (0次或者多次)

beforeUpdate 内存中的数据是新的 页面的数据是旧的

updated 内存和页面已经同步起来 都是新的数据

实例或者组件的注销阶段 当组件或者实例被销毁的时候才会被调用 (1次)

beforeDestroy data和methods 以及一些指令和过滤器等等的还能用 可以做一些释放内存的操作

destroyed 彻底销毁了

keep-alive的生命周期

activated 页面第一次进入的时候,钩子触发的顺序是created->mounted->activated

deactivated 页面退出的时候会触发deactivated,当再次前进或者后退的时候只触发activated

created和mounted的区别

created是最早使用data和methods数据的钩子

mounted是最高操作dom元素的钩子

两个理论问题,面试经常会问道

slot

插槽 slot 子组件中显示父组件的数据

记住两点:
1、怎么在子组件中显示父组件的数据

a、在父组件中子组件的标签内部 写要传输的数据
b、在子组件的模板中用标签给要显示的数据开辟一个地方

2、到底什么数据
父组件传数据 我就显示父组件的数据
父组件不穿数据 如果有默认数据我就显示默认数据 没有默认数据我就是什么都不显示

插槽的作用域
变量在哪个组件中定义 作用域就属于哪个组件
具名插槽:给插槽起名字
具名插槽:就是给<slot name="">标签来起名字

在父组件分发的时候使用<template v-slot:名></template>来指定数据显示的位置


单个 Slot:
在子组件内使用特殊的元素就可以为这个子组件添加一个 slot (插槽),在父组件模板里,插入在子组件标签内的所有内容将替代子组件的标签及它的内容.示例代码如下:

// 这是父组件中引入的子组件
 <child-component>
     <p>分发的内容</p>
     <p>更多分发的内容</p>
 </child-component>
// 这是子组件
<slot>
   <p>如果父组件没用插入内容,我将作为默认出现,有的话显示传过来的内容</p>\
</slot>

子组件的模板内定义一个 <slot> 元素,并且用一个 <p> 作为默认的内容,在父组件没有使用 slot 时,会渲染这段默认的文本;如果写入了 slot ,那就会替换整个 <slot>.所以上列渲染后的结果为:

<div id="app">
     <div>
        <p>分发的内容</p>
        <p>更多分发的内容</p>
    </div>
</div>

注意:子组件<slot>内的备用内容,它的作用域时子组件本身。

具名 Slot:
<slot> 元素指定一个 name 后可以分发多个内容,具名 Slot 可以与单个 Slot 共存,例如下面的示例:

// 这是父组件中引入的子组件
<child-component>
      <h2 slot="header">标题</h2>
      <p>正文内容</p>
      <p>更多正文内容</p>
      <div slot="footer">底部信息</div>
</child-component>
// 这是子组件
<div class="component">
     <div class="header">
         <slot name="header"></slot>
     </div>
     
     <div class="main">
         <slot></slot>
     </div>
     
     <div class="footer">
         <slot name="footer"></slot>
     </div>
</div>

子组件内声明了3个 <slot> 元素,其中在<div class="main">内的<slot> 没用使用 name 特性,它将作为默认 slot 出现,父组件没有使用 slot 特性的元素与内容都将出现在这里。

如果没有指定默认的匿名 slot, 父组件内多余的内容片段都将被抛弃.
上例最终渲染后的结果为:

<div id="app">
        <div class="container">
            <div class="header">
                <h2>标题</h2>
            </div>
            <div class="main">
                <p>正文内容</p>
                <p>更多的正文内容</p>
            </div>
            <div class="footer">
                <div>底部信息</div>
            </div>
        </div>
</div>

:在组合使用组件时,内容分发API至关重要。

路由

一、怎么理解路由

就是跳转的机制 然后这个跳转的规则由程序员来指定

二、前端路由 后台路由

前端路由:是由程序员来设置的页面跳转规则,由不同的路径显示不同的组件 但是前端路由的路径在后台服务器上是不存在的

后台的路由:每个路由对应的是一个接口,也就是说后台的路由是在服务器上真实存在的,每个后台的路径都对应的一个接口数据

打个例子来说

/bannerList   轮播的数据接口		
/list  数据列表的接口

三、路由的原理

vue的路由分为两种:hash路由 history路由

hash路由

js原生事件 onhashchange()当页面的hash发生变化就会触发该事件

history路由

是利用h5新增的api history堆栈来实现的

js原生事件 ononpopstate()来检测页面的路径变化 从而根据路径来显示不同的页面

四、路由的配置

vue中的路由默认的为hash路由

src->router->index.js是我们的路由配置文件 所有的路由都会在这个文件中进行配置

怎么由hash模式变为历史模式

给router对象添加 mode:"history", 默认的是hash模式

src->router->index.js文件

在这里插入图片描述

五、路由配置的步骤

一、新建对应路由的组件

二、配置路由规则

		**`router->index.js`**

2.1、引入所有用到的组件

2.2、配置相应的规则

{
	path:
	name:
	component:
}

2.3、给路径对应的组件找到显示的位置

<router-view/>是系统给我们提供的一个显示路径所对应组件的这么一个组件 可以直接使用

2.4、给路由的显示添加导航

<rotuer-link to="路径"></router-link>是提供提供给我们路由导航的组件 可以直接使用 默认的情况下解析为a标签

更换标签 tag="标签名"

2.5、默认的路径在导航上添加router-link-active类

2.6、配置默认路径

{
	path;“/”,
	redirect:"路径"
}

三、二级路由的配置

哪个一级路由下配置二级路由

1、新建组件

2、配置规则

给要配置二级路由的一级路由添加children属性:[
						{
							path:""二级路由是没有`/`,
							name:
							component:
						}
				
					]

3、找地方显示路由组件

给谁配置的二级路由就去当前组件中找位置

4、设置导航路径

记录 设置to=“/一级路由/二级路由”

5、设置二级的默认路径

配置二级路由参考代码(我这里写的是json之前写后台管理自己乱写的数据)

"router": [
        {
            "path": "/index",
            "name": "index",
            "component": "index",
            "children":[
              {
                "path":"a",
                "name": "a",
                "component": "a"
              },
              {
                "path":"b",
                "name":"b",
                "component": "b",
                "children":[
                    {
                      "path":"b1",
                      "name": "b1",
                      "component": "b1",
                      "children":[
                        {
                          "path":"bb1",
                          "name": "bb1",
                          "component": "bb1"
                        }
                      ]
                    }
                  ]
              }
            ]
          },
          {
            "path": "*",
            "name": "404",
            "component":"404"
          }
      ]

const routes = [
  {
    path:"/",
    redirect:"/login"
  },
  {
    path: '/login',
    name: 'login',
    component: () => import('../views/login.vue')
  }
]

在配置路由的时候会发现有两种引入方式一种是直接import引入import home from "@/views/home"另一种是使用箭头函数引入() => import('../views/login.vue')

下面说一下他们的区别,以及用哪个比较好

1、直接把组件引入进来,不管路径访问或不访问,都会把组件引用进来

2、是当我访问这个路径的时候才加载这个路径,如果一直不访问/logint这个路径是不会加载的。

好处就是当项目比较大,页面比较多,因为vue是单页面应用,一次性加载这么多内容,加载会很慢,这样体验就很不好。

所以在真正的项目中,一般使用第二种异步加载/懒加载,就是访问了才加载,没有访问就不加载。

路由传参

为什么会用到路由传参

由多个路由导航调转到同一个路由页面,又得区分是从哪个导航跳转过来的,那么就需要路由传参

query传值

传值格式路径?参数名=值&参数名=值

步骤:

1、在router-link的to属性后面 设置参数to="/path?参数名=值"

2、获取 在目标组件上获取this.$route.query.id来获取到参数

params传值

传值格式 路径/值/值/值

步骤:
1、在router->index.js中设置参数

{
	path:"/path/:参数名/:参数名"
}

2、在router-link的to属性后面 设置值to="/path/值/值"

3、在在目标组件上获取this.$rotue.params.参数名

路由跳转的几种方式

router-link

1. 不带参数
 <router-link :to="{name:'home'}"> 
<router-link :to="{path:'/home'}"> //name,path都行, 建议用name 
// 注意:router-link中链接如果是'/'开始就是从根路由开始,如果开始不带'/',则从当前路由开始。
 2.带参数
 <router-link :to="{name:'home', params: {id:1}}"> 
// params传参数 (类似post)
// 路由配置 path: "/home/:id" 或者 path: "/home:id" 
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
// html 取参 $route.params.id
// script 取参 this.$route.params.id
<router-link :to="{name:'home', query: {id:1}}"> 
// query传参数 (类似get,url后面会显示参数)
// 路由可不配置
// html 取参 $route.query.id
// script 取参 this.$route.query.id

this.$router.push() (函数里面调用)

1. 不带参数
 this.$router.push('/home')
this.$router.push({name:'home'})
this.$router.push({path:'/home'})
2. query传参 
 this.$router.push({name:'home',query: {id:'1'}})
this.$router.push({path:'/home',query: {id:'1'}})
// html 取参 $route.query.id
// script 取参 this.$route.query.id
3. params传参
 this.$router.push({name:'home',params: {id:'1'}}) // 只能用 name
 
// 路由配置 path: "/home/:id" 或者 path: "/home:id" ,
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
// html 取参 $route.params.id
// script 取参 this.$route.params.id
4. query和params区别
query类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用params刷新页面id还在
 params类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失

this.$router.replace() (用法同上,push)

this.$router.go(n)

向前或者向后跳转n个页面,n可为正整数或负整数

区别:

this.$router.push

跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面

this.$router.replace

跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)

this.$router.go(n)

向前或者向后跳转n个页面,n可为正整数或负整数

axios

Axios是什么?

Axios 是一个基于 promise 的 HTTP 库,简单的讲就是可以发送get、post请求。说到get、post,大家应该第一时间想到的就是Jquery吧,毕竟前几年Jquery比较火的时候,大家都在用他。但是由于Vue、React等框架的出现,Jquery也不是那么吃香了。也正是Vue、React等框架的出现,促使了Axios轻量级库的出现,因为Vue等,不需要操作Dom,所以不需要引入Jquery.js了。

Axios特性

1、可以在浏览器中发送 XMLHttpRequests
2、可以在 node.js 发送 http 请求
3、支持 Promise API
4、拦截请求和响应
5、转换请求数据和响应数据
6、能够取消请求
7、自动转换 JSON 数据
8、客户端支持保护安全免受 XSRF 攻击

Axios用在什么场景?

浏览器发送请求,或者Node.js发送请求都可以用到Axios。像Vue、React、Node等项目就可以使用Axios,如果你的项目里面用了Jquery,此时就不需要多此一举了,jquery里面本身就可以发送请求。

Axios如何使用?

安装模块

npm install axios --save

在vue文件中引入 import axios from axios 写在export default上面

或者直接引入

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

引入模块后可以直接使用

// GET
axios.get('/user', {
  params: {
    ID: 12345
  }
})
.then(function (response) {
  console.log(response);
})
.catch(function (error) {
  console.log(error);
});

// POST
axios.post('/user', {
  name: 'Javan',
  website: 'www.javanx.cn'
})
.then(function (response) {
  console.log(response);
})
.catch(function (error) {
  console.log(error);
});

// 参数时可选的

如果想并发多个请求

function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // 两个请求都执行完成才会执行
  }));

main.js中axios的全局设置
axios的全局设置

import axios from 'axios'
Vue.prototype.$axios=axios

在组件中可以直接通过 this.$axios来使用

这里就不写这么多了,下面来封装 axios

封装axios请求

基本不用封装,因为Axios本身是一个基于 promiseHTTP 库只是对请求的接口地址,超时报错处理

首先在src目录中创建一个http文件夹,在http目录下新建request.js api.js

request.js

import Axios from 'axios'
// Axios.defaults.withCredentials = true

// console.log('request.js中的环境变量:', process.env.BUILD_ENV)

// 针对npm run 来自动读取不同环境变量
// const config_env = require(`../build/${process.env.BUILD_ENV}.js`)

// eslint-disable-next-line
const config_env = require(`../build/${process.env.BUILD_ENV}.js`)

// 创建axios实例
const service = Axios.create({
  baseURL: 'https://www.liulongbin.top:8888/api/private/v1',
  timeout: 3000
})

// 请求拦截
service.interceptors.request.use(config => {
  // console.log('请求被拦截:', config)
  const token = localStorage.getItem('token')
  // 配置头信息
  if (token) {
    config.headers.Authorization = token
  }
  return config
}, _error => {
  // eslint-disable-next-line prefer-promise-reject-errors
  return Promise.reject('请求出错,请检查')
})

// 响应拦截
service.interceptors.response.use(res => {
  // console.log('响应拦截')
  return res
}, error => {
  // eslint-disable-next-line prefer-promise-reject-errors
  return Promise.reject('出错啦', error)
})

export default service

这里只需要简单配置一下请求拦截,相应拦截 header头token 在请求拦截相应拦截里面配置对应的相应,比如token过期,服务器异常等等

api.js

import request from './request'
import qs from 'qs'

export function login (obj) {
  return request({
    url: 'login',
    method: 'post',
    data: qs.stringify(obj)
  })
}

/**
 * 用户列表接口
 */

export function getUser (params) {
  return request({
    url: 'users',
    method: 'get',
    params
  })
}

首先引入request,qs呢是一个转换用的,给后台发送数据时需要

使用:
那个文件请求在哪个文件中引入

import { login } from '@/http/api'

直接异步请求

 login(this.ruleForm).then((res) => {
            // console.log(res)
            // 搞到token
            const token = res.data.data.token
            // console.log(token)
            // 存放到本地
            localStorage.setItem('token', token)
            // 登录ok咱就跳转到首页 /
            this.$router.push('/index')
          })
        } else {
          this.$message.error('登录失败')
          return false
        }
      })

跨域

由于浏览器的同源策略,我们只能通过ajax访问同域名 同协议 同端口号的数据,如果域名不同、协议不同、端口号不同、ip地址和域名之间的访问都属于跨域。跨域的其中一种解决方案是jsonp,因为script img的src属性没有被同源策略限制,所以我们可以通过script标签src属性来实现调用不同域名 不同协议 不同端口号的数据。jsonp的原理是利用动态的创建script标签来请求后端接口的地址,然后传递一个callback参数,后端接受到callback后将数据处理完成,将数据以callback函数调用的方式来返回,callback的参数就是我们要的json数据

我这里简单明了说一下,以及在本地写好后,打包上传需要注意的事情

首先在vue.config.js中写入

module.exports = {
    devServer: {
        proxy: {
            '/api': {
                target: 'http://40.00.100.100:3002',//对应自己的接口
                changeOrigin: true,
                ws: true,
                pathRewrite: {
                    '^/api': ''
                    //这里理解成用‘/api’代替target里面的地址
                    //后面组件中我们掉接口时直接用api代替 
                }
            }
        }
    }
}

比如我要调用http://40.00.100.100:3002/user/add,直接写/api/user/add即可

:这只是在本地我们看效果,如果要发布到线上,把配置的跨域删掉就行了,打包发布过后域名啥的都一样了不存在跨域了,还需要注意的是之前接口前面写的/api如果后台配置了那就配置了,不用管它,如果没有配置那么请求的时候域名就会变成http://40.00.100.100:3002/api/user/add多了api肯定是不对的,那么把/api删掉即可 (在baseURL中配置会更方便的更改)

keep-alive

keep-alive是vue提供给我们的一个组件 来缓存我们页面的数据

全部缓存

直接把 router-viewkeep-alive 包裹起来

部分缓存

1、router.js中设置要缓存的页面

{
  	path: '/child1',
  	name: 'Child1',
  	component: Child1,
  	meta:{
  		keepAlive:true
  	}
},
{
  	path: '/child2',
  	name: 'Child2',
  	component: Child2,
  	meta:{
  		keepAlive:false
  	}
}

2、用 v-if 来显示 router-view 是否在 keep-alive 中出现

<keep-alive>
   <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive> 

<router-view v-if="!$route.meta.keepAlive"></router-view>
	

有些页面数据需要缓存,但是数据更新时怎么办,结合keep-alive的生命周期去做逻辑处理

activated

activated 页面第一次进入的时候,钩子触发的顺序是created->mounted->activated

deactivated

deactivated 页面退出的时候会触发deactivated,当再次前进或者后退的时候只触发activated

路由导航守卫

作用

当从一个路由页面到另一个路由页面,如果有权限,能进入,没权限,阻止进入

类别:

全局守卫
路由独享守卫
组件内部守卫

其实就是利用路由跳转之前的那一刹那我们让他们帮我干一些事情

路由导航守卫就是利用路由导航钩子来添加自己代码,实现我们想要的功能

路由守卫是由路由钩子完成

全局守卫

只要涉及到路由跳转 这个钩子就会执行

配置router->index.js中去配置

router.beforeEach((to, from, next) => {
    console.log(to) => // 到哪个页面去?
    console.log(from) => // 从哪个页面来?
    next() => // 一个回调函数
})

// to和from都是一个对象
// next是一个回调函数 next()==next(true) 放行 next(false)阻止

注意
to 对象 去哪个路由的对象
from 从哪来的对象
next() 是否继续回调函数

如果不写  ---  next(false)
next() --- next(true)
next(path) 相当于调转	

路由独享守卫

路由独享守卫是在路由配置页面单独给路由配置的一个守卫

{
     path: '/',
     name: 'home',
     component: 'Home',
     beforeEnter: (to, from, next) => {
               // ...*************
     }
}

组件独享守卫

组件路由守卫是写在每个单独的vue文件里面的路由守卫

beforeRouteEnter (to, from, next) {
     // 注意,在路由进入之前,组件实例还未渲染,所以无法获取this实例,只能通过vm来访问组件实例
    next(vm => {})
}

beforeRouteUpdate (to, from, next) {
    //当路由参数发生改变的时候被调用
}

beforeRouteLeave (to, from, next) {
   // 离开当前路由页面时调用
}

vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化

vuex的工作流程

在vue的组件中通过dispatch来调用actions中的方法,在actions中通过commit来调用mutations中的方法,在mutations中可以直接操作state中的数据,只要state中的数据发生改变就会立刻响应到咱们的组件中

之前使用vuex还得需要npm install vuex --save 下载,现在安装脚手架的时候直接可以选择下载了

state:是仓库 也就是存储数据的 相当于银行的金库

组件使用state中的数据

this.$store.state.属性

mutations:是唯一可以修改vuex中数据的选项 ,每个方法都有一个回调函数 回调函数有一个形参state 就是咱们的state数据

在组件中触发mutations中的方法

this.$store.commit("方法名",参数)

action:不能直接修改状态值 调用mutation的方法 mutation修改状态值 可以包含异步操作

在组件中触发action中的方法

this.$store.dispatch("方法名",参数)

getters:类似于我们的计算属性 可以对state中的数据做一些逻辑计算

在组件中使用:

this.$store.getters.方法名

vuex module

vuex的工作流程:
state:存储数据的仓库
mutations:定义的是操作state数据的方法
getter:定义的state数据一些逻辑处理 相当于我们的computed
actions:实现的是异步操作数据 通过commit调用mutations中的方法
module:将vuex中的数据分块来存储 模块中state是局部的,getters mutations actions都是全局的直接使用就是 只有局部的是要加模块名 $store.state.模块名.属性名

Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter

调用模块中state中的数据

$store.state.模块名.属性名

调用模块中getter中的方法

$store.getter.名

调用模块中的mutations

$store.commit("名",参数)

调用模块中actions

$store.dispath("名",参数)

注意的是

模块中state是局部的,getters mutations actions 都是全局的直接使用就是 只有局部的是要加模块名

vant、elementUI、ECharts

这里不多介绍了,我们都知道vue呢他是一个渐进式的框架,轻量级,可以在项目中可以使用其他的框架或者类库。

vant (移动端使用)

上手也是比较简单的直接去官网看快速上手

快速上手

首先安装 npm i vant -S

在main.js引入

import Vant from 'vant';
import 'vant/lib/index.css';
Vue.use(Vant);

找到代码复制
在这里插入图片描述
如果你想更改颜色样式什么的,下面有对应的api以及事件,自行去看

elementUI (pc端使用)

elementUI就和vant这种一样了,会一个别的也就差不多了,直接上链接

快速上手

ECharts

ECharts呢也是一样的

快速上手

这里简单介绍一下

首先 npm install echarts --save 下载安装

使用

首先在组件中准备一个具备高宽的 DOM 容器,用来展示echarts

引入:

import * as echarts from 'echarts';

找到示例,随便找出一张

在这里插入图片描述
点进去有对应的代码还有效果图

在这里插入图片描述
复制的是一个option对象,那么如何写入呢,分为三步
首先获取容器

var myChart = echarts.init(document.getElementById('main'));

第二部写入option对象

最后使用刚指定的配置项和数据显示图表

myChart.setOption(option);

在这里插入图片描述
可以使用ref获取元素

最终效果:

在这里插入图片描述

Vue.prototype 详解及使用

Vue.prototype 详解及使用


总结

本文简单介绍了vue的使用,如有遗漏,留言后补~

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐