vue基础总结

目录

1.vue含义

2. Vue和jQuery区别是什么?

3.vue-cli的好处和能力

4.vue-cli 安装

5.vue-cli覆盖webpack配置

6.vue-cli 目录分析与清理

7.指令和语法

7.1.插值表达式(声明式渲染)

7.2.动态属性(v-bind)

3.事件绑定(v-on)

4.v-model(把value属性和vue变量双向绑定到一起)

7.5.v-text和v-html

7.6.v-show和v-if

7.7.v-for

8.事件修饰符

9.v-for更新监测

10.vue的key属性

11.虚拟DOM

12.动态class

13.动态style

14.过滤器

15.计算属性

计算属性完整写法:

16.watch监听器

17.Vue组件创建

18.Vue组件_scoped作用

19.vue组件通信

20.Vue生命周期(钩子函数)

21.跨域

22.axios

23.ref

24.$nextTick使用

25.组件name属性使用

26.动态组件

27.组件缓存

28.组件插槽

29.自定义指令

30.路由vue-router


1.vue含义

渐进式javascript框架,而且自底向上,增量开发,组件集合,便于复用

2. Vue和jQuery区别是什么?

jQuery应该算是一个插件, 里面封装了各种易用的方法, 方便你使用更少的代码来操作dom标签

Vue是一套框架, 有自己的规则和体系与语法, 特别是设计思想MVVM, 让数据和视图关联绑定, 省略了很多DOM操作. 然后指令还给标签注入了更多的功能

3.vue-cli的好处和能力

- 统一的项目结构(文件夹+文件+配置代码)
- 开发过程中的webpack各系列支持
  - babel支持
  - eslint约束语法风格(代码风格)
  - 样式预处理器less
  - vue单文件支持
- 提供一个开发时服务器,预览代码(预览项目)
  - 自动刷新,方便预览
  - 热更新 (只刷新修改的部分)
- 基于nodejs的命令行工具

4.vue-cli 安装

目标: 把@vue/cli模块包按到全局, 电脑拥有vue命令, 才能创建脚手架工程

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

查看vue脚手架版本

vue --version或者输入vue -V都可以查看是否安装成功

总结: 如果出现版本号就安装成功, 否则失败

注意:路径上不要有vue名字的文件夹, 项目名不能带中文和特殊符号

创建项目

1.基于交互式命令行的方式,创建新版vue项目
# vue和create是命令, vuecli-demo是文件夹名
vue create vuecli-demo

选择模板

可以上下箭头选择, 弄错了ctrl+c重来

回车等待生成项目文件夹+文件+下载必须的第三方包们

进入脚手架项目下, 启动内置的热更新本地服务器 cd就好比"双击"

cd vuecil-demo

npm run serve
# 或
yarn serve

 只要看到绿色的 - 啊. 你成功了(底层node+webpack热更新服务)

打开浏览器输入上述地址即可

 总结: vue命令创建工程目录, 项目内置webpack本地热更新服务器, 帮我们打包项目预览项目

5.vue-cli覆盖webpack配置

目标:项目中没有webpack.config.js文件,因为vue用的vue.config.js

/* 覆盖webpack的配置 */
module.exports = {
  devServer: { // 自定义服务配置
    open: true,  // 自动打开浏览器
    port: 3000
  },
  lintOnSave: false // 关闭eslint检查
}

注意:每次配置完vue.config.js之后都要重新启动服务器

6.vue-cli 目录分析与清理

 vuecil-demo        # 项目目录
    ├── node_modules # 项目依赖的第三方包
    ├── public       # 静态文件目录
      ├── favicon.ico# 浏览器小图标
      └── index.html # 单页面的html文件(网页浏览的是它)
    ├── src          # 业务文件夹
      ├── assets     # 静态资源
        └── logo.png # vue的logo图片
      ├── components # 组件目录
        └── HelloWorld.vue # 欢迎页面vue代码文件 
      ├── App.vue    # 整个应用的根组件
      └── main.js    # 入口js文件
    ├── package.json # 描述项目及项目
    ├── .gitignore   # git提交忽略配置
    ├── babel.config.js  # babel配置 
    ├── README.md    # 项目说明
	└── package-lock.json # 项目包版本锁定和缓存地址

src/App.vue默认有很多内容, 可以全部删除留下框

assets 和 components 文件夹下的一切都删除掉 (不要默认的欢迎页面)

public/index.html

 babel.config.js

 main.js

 main.js App.vue public/index.html三者的关系图

 三个主要文件

7.指令和语法

7.1.插值表达式(声明式渲染)

语法: {{表达式}}
作用:
1.可以在标签处,写表达式和值显示
2.只能用在标签夹着的地方
3.{{}}里只能写表达式,不能写if/for语句
4.把vue变量显示在标签上

7.2.动态属性(v-bind)

语法: v-bind:原生属性='vue变量'  
作用: 把vue变量赋予给原生标签的属性
简化写法: 省略v-bind直接写 :

3.事件绑定(v-on)

语法:
v-on:事件类型='一句代码'     <button v-on:click='count++'>数量加+</button>
v-on:事件类型='methods里函数名'
v-on:事件类型='methods里函数名(实参)'
拿到事件对象方式:
@事件类型='methods里方法名'  -  默认接收e
@事件类型='methods里方法名(实参,$event)'   - 需要手动传入$event事件对象到函数里
作用: 当触发标签的事件,会执行methods里的这个方法

4.v-model(把value属性和vue变量双向绑定到一起)

语法:

  • v-model.修饰符="vue数据变量"

    • .number 把值转数字(parseFloat)赋予给vue变量(只要被标签一染手,就变成了字符串,number就是为了把value属性值,转成数字再赋予给变量)

    • .trim 去除两边空格后再赋予给vue变量

    • .lazy 失去焦点值改变后,才会赋予给vue变量

复习: 输入框事件:

  • focus - 获得焦点

  • blur - 失去焦点

  • change - 失去焦点而且内容改变

  • input事件 - 实时监测内容改变

        其实这里的v-model就相当于input事件,change事件就相当于lazy事件

作用:
1.把vue变量赋予给value属性
2.value属性值改变,同步给vue变量
双向数据绑定
数据变化 -> 更新视图
视图变化 -> 自动同步给vue数据

select绑定v-model,value写在option上

用户选择哪个option,就把对应value值赋予给v-model的vue变量

复选框

  • v-model的变量如果是 非数组,关联的是checked属性(true/false)

  • v-model的变量如果是 数组,关联的是value属性(选中了就把value值加到数组里)

单选框

7.5.v-text和v-html

<p v-text="str"></p>
<p v-html="str"></p>

v-text:把值当成普通字符串显示,相当于innerText
v-html:把值当成标签解析,相当于innerHTML
注意:指令会覆盖声明式渲染的值(会覆盖插值表达式)
使用场景:一般有富文本的地方会用到

7.6.v-show和v-if

1.v-show和v-if用法(控制所在标签显示或隐藏)
v-show或v-if给一个true值,就显示所在的标签
给一个false值得时候,v-show隐藏靠display:none(应用场景:频繁切换)  v-if隐藏直接从DOM树移除掉
2.v-if和v-else配合 和js里的if/else一个意思
3.v-if和v-else-if    (多个分支的时候使用)

7.7.v-for

v-for 用数据结构,遍历生成所在标签DOM

口诀: 你想让谁循环,就把v-for写谁身上
语法:v-for='(变量名1,变量名2) in 目标结构'
注意:in两边必须有空格
执行:str接收到每次遍历的值,index每次遍历的索引
v-for可以遍历数组,对象,和固定数字(值是从1开始,因为只有数组才有下标0)

8.事件修饰符

语法:

  • @事件名.修饰符="methods里函数"

    • .stop - 阻止事件冒泡

    • .prevent - 阻止默认行为

    • .once - 程序运行期间, 事件处理函数只调用一次

    • @keyup.enter - 检测回车按键

    • @keyup.esc - 检测返回按键

    总结: 修饰符给事件扩展额外功能

    注意: 1. 如果需要多个修饰符可以连续一直往后写 eg: @click.prevent.stop

    2.可以加方法名,也可以不加方法名 eg: @click.stop 或者 @click.stop="btn"

 9.v-for更新监测

只要监测到目标结构新增/删除/顺序改变/重新赋予新数组了(替换)  就会发生更新
改变原数组的方法才能让v-for更新, 如果未更新, 使用Vue.set()方法, 或者覆盖原目标结构
数组排序,翻转可导致v-for更新检测,页面更新
数组截取,修改基础类型的值,都不能导致v-for更新检测
能改变(新增/删除/顺序改变/重新赋予新数组)原数组的, 数组方法, 才能引发v-for的更新(页面的自动变化)
数组方法: sort() / reverse() / splice().... 能触发更新
不能更新方法: slice() / concat() / map() / filter() - 返回的新数组不能触发更新
不能更新的解决方案:
- 解决方案1: 直接把新数组,覆盖回去,赋值给新变量
- 解决方案2:使用vue内置的更新方法,Vue.set()  -   相当于this.$set()
          参数1:目标结构,参数2:更新哪个下标,参数3:传入值
           this.$set(this.arr,0,100)
口诀:
1.只要改变原始数组,就会导致v-for更新检测,页面更新
2.数组方法不行,采用覆盖数组方法和Vue.set()也能让v-for更新检测

10.vue的key属性

目的: 提高dom更新性能,不加key也不影响性能

总结:

1.key属性用不用都不影响功能
2.key属性可以提高 v-for 更新时的性能
3.v-for默认就地更新,如果有key,按照key变化更新
   详细: 新的dom结构里没有key(新建),key不存在了-key对应的标签移除,key存在,复用
4.key值不重复的数字或字符串
  (使用):有id用id,没有id用索引(就地更新)

vue用diff算法,新虚拟dom,和旧的虚拟dom比较,规则

  • 如果根元素变了 => 删除重建

  • 如果根元素没变,属性改变 => 元素复用,更新属性

  • 如果根元素没变,子元素改变(内容也算子元素)改变

    • 无key: 就地更新

    • 有key: 根据key 复用标签,更新子元素

11.虚拟DOM

- .vue文件中的template里写的标签,都是模板,都要被vue处理后,才能显示到真实DOM页面上
- 内存中生成一样的虚拟DOM结构(本质是JS对象,包含节点信息)
- 流程:template => 虚拟DOM => 显示到网页index.html上
- 因为真实的DOM属性好几百个,没办法快速的知道哪个属性改变了
- 虚拟DOM就是保存节点信息的一个js对象
- 以后vue数据改变生成新的虚拟DOM结构,和旧的虚拟DOM结构对比,只更新变化的部分(重绘/回流)到页面

const dom = {
    type:"div",
    children:[
    {
       type:"p",
       children:["我是p标签"]
    }
    ]
}

虚拟DOM的好处:
1.更新只更新变化的部分,页面上会减少回流和重绘,提高了更新DOM的性能
2.虚拟DOM是保存在内存中,体积小,运行效率更高
总结:虚拟DOM保存在内存中,只记录dom关键信息,配合diff算法提高DOM更新的性能

12.动态class

  • 不加: 认为后面是普通字符串

  • 加: 认为后面的vue变量

语法:
:class='vue变量'               作用:vue变量的值,用作类名给当前标签
:class="['类名1','类名2']"     作用:把多个类名使用
:class="{类名:布尔值}"         作用:当布尔值为true,就把属性(类名)用给class

13.动态style

:style="{css属性:值}"    值类型可以是字符串也可以是变量
eg:   :style="{color:colorStr, backgroundColor:'red'}"

14.过滤器

过滤器只能用在,插值表达式和v-bind表达式
目标:
    转换格式,过滤器就是一个函数,传入值返回处理后的值
Vue中的过滤器场景:
    字母转大写,输入"hello",输出"HELLO"
    字符串翻转,"输入hello,world",输出"dlrow,olleh"
语法:
    Vue.filter("过滤器名字",(值) => {return"返回处理后的值"})
    filters:{过滤器名字:(值) => {return"返回处理后的值"}}
例子:
    全局定义字母都大写的过滤器
    局部定义字符串翻转的过滤器
总结:
    把值转成另一种形式,使用过滤器,Vue3用函数替代了过滤器
    全局注册最好在main.js中注册,一处注册到处使用

过滤器代码:

  • 过滤器本质上就是一个函数,作用:输入一个值,处理后返回

  • 1.定义全局过滤器 - 语法如下

<template>
  <div>
    <p>{{msg}}</p>
    <p>{{msg | toUp}}</p>    // 全局过滤器
    <p :title="msg | toRev">鼠标停留看看</p>   // 局部过滤器
  </div>
</template>

<script>
// 1.先引入vue
import Vue from 'vue'
// 2.定义过滤器(全局)
// 参数1:过滤器名(随便起),参数2:过滤器要执行的代码,必须return一个值
// val变量接收到的是  | 左边的结果
Vue.filter("toUp",val => val.toUpperCase())
export default {
  data() {
    return {
      msg:'hello,world'
    }
  },
  // 局部过滤器
  filters: {
    toRev:val => val.split("").reverse().join("")
  }
 }
</script>

过滤器传参:

 多个过滤器调用:

15.计算属性

目标:
一个数据,依赖另外一些数据计算而得来的结果
语法:
computed:{计算属性名:() => {return计算属性的值}}
注意:
计算属性也是vue数据变量,所以不要和data里重名,用法和data相同
总结:
一个数据,依赖另外一些数据计算而得来的结果

基础语法:

<template>
  <div>
    <!-- 2.使用计算属性 -->
    <p>{{num}}</p>    计算两个数相加的值
	<p>{{reverMessage}}</p>   翻转 
  </div>
</template>

<script>
export default {
  data(){
    return {
      msg:'Hello,world',
      a:10,
      b:20
    }
  },
  // 1.定义计算属性(也是变量,所以不能和data重名)
  computed:{
    num() {  // num是计算属性名(也是变量名)
      return this.a + this.b  // 把a和b的和返回给num变量使用
    },
    reverMessage() {
      return this.msg.split("").reverse().join("")
    }
  }
}
</script>

计算属性和函数的区别:

计算属性  return给reverseMessage这个变量

函数  return给getMessage这个函数调用的地方

<template>
  <div>
    <p>{{ reverseMessage }}</p>
    <p>{{ reverseMessage }}</p>
    <p>{{ reverseMessage }}</p>
    <p>{{ getMessage() }}</p>
    <p>{{ getMessage() }}</p>
    <p>{{ getMessage() }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: "我是个字符串",
    };
  },
  computed: {
    reverseMessage() {
      console.log("计算属性执行");
      return this.message.split("").reverse().join("");   // return给reverseMessage这个变量
    }
  },
  methods: {
    getMessage(){
      console.log("方法执行");
      return this.message.split("").reverse().join("");   // // return给getMessage这个函数调用的地方
    }
  }
};
</script>

console.log打印区别:

结论:

1.计算属性自带缓存,多次使用,直接返回缓存的值,不会频繁触发计算属性函数

2.当计算属性函数里引用的变量发生改变,会自动触发函数执行,重新缓存

使用场景:

当你发现一个变量的值,应该由别人计算而得来,把这个变量定义为计算属性

计算属性根据依赖变量结果缓存,依赖变化重新计算结果存入缓存,比普通方法性能更高

计算属性完整写法:

 目标:计算属性也是变量,如果想要直接赋值,需要使用完整写法

语法:

<template>
  <div>
    <div>
    <span>全称</span>
    <input type="text" v-model="fullName">
  </div>
  <div>
    <span>姓:</span>
    <input type="text" v-model="firstName">
    <span>名:</span>
    <input type="text" v-model="lastName">
  </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      firstName:'',
      lastName:''
    }
  },
  computed:{
  // 计算属性完整写法:
  // 场景: 当你要直接给计算属性赋值的时候,必须写成完整写法
    fullName:{
      set(val) {   // 给fullName赋值(set)的时候,val就是要被赋予的值
      // 把第一个字符当做姓,后面的当做名赋予给firstName和lastName
      this.firstName = val.substr(0,1) //下标0截取,截取1个
      this.lastName = val.substr(1)
        console.log(val)
      },
      get() {   // fullName要取值时,触发
        console.log('get触发了')
        return this.firstName + this.lastName
      }
    }
  }
}
</script>

总结:想要给计算属性赋值,需要使用set方法

16.watch监听器

目标:可以监听data/computed属性值改变

使用场景:监听data/computed里变量的改变

语法:

watch:{
    "被监听的属性名" (newVal,oldVal) {
        
    }
}

总结:想要监听一个属性变化,可使用监听属性watch

例子:监听v-model绑定输入框变量的变化

<template>
  <div>
    <input type="text" v-model="username">
  </div>
</template>

<script>
export default {
  data(){
    return {
      username:''
    }
  },
  watch:{
      // 参数1:改变后新值  参数2:上一刻旧值
    username(newVal,oldVal) {
      // 只要监听的变量的值发生了改变,这里马上就触发,newVal接收到的是最新的值
      console.log(newVal,oldVal)
    }
  }
}
</script>

深度监听和立即执行

目标:监听复杂类型,或者立即执行监听函数

语法:

watch: {
    "要监听的属性名": {
        immediate:true,   // 立即监听
        deep:true,  // 如果监听的变量的值是(数组/对象)复杂数据类型那么就开启深度监听,监听复杂数据类型的变化(想要深度监听里面的值/属性发生改变,则必须设置此项)
            // handler方法名固定
        handler (newVal,oldVal) { 
        // 监听到变量值发生改变就马上触发(如果启用了立即监听,则网页打开就触发一次)
        }
    }
}

总结: immediate立即监听,deep深度监听,handler固定方法触发

例子:

<template>
  <div>
    <input type="text" v-model="user.nickname">
    <input type="text" v-model.number="user.age">
  </div>
</template>

<script>
export default {
  data(){
    return {
      user: {
        nickname:'',
        age:0
      }
    }
  },
  // 监听复杂类型的改变
  // 需要对此属性进行额外的配置,必须加deep:true
  watch:{
    user:{
      deep:true,   // 开启了深度监听(里面属性也监听)
      immediate:true,  // 立即监听(网页打开就触发一次handler执行)
      handler(newVal) { // handler 是固定的
        console.log(newVal)
      }
    }
  }
}
</script>

17.Vue组件创建

组件是可复用的Vue实例,封装标签,样式和JS代码

组件化:封装的思想,把页面上'可重用的部分'封装为'组件',从而方便项目的开发和维护

一个页面,可以拆分成一个个组件,一个组件就是一个整体,每个组件可以有自己独立的结构样式和行为(html,css和js)

17.1vue组件_创建

目标:每个组件都是一个独立的个体,代码里体现为一个独立的.vue文件
口诀:哪部分标签复用,就把哪部分封装到组件内
(重要):组件内template只能有一个根标签
(重要):组件内data必须是一个函数,独立作用域
(重要):组件.vue文件,是独立的个体,在当前组件内的方法和变量一定要写在当前script里
总结: 封装标签 + 样式 + js  - 组件都是独立的,为了复用

17.2vue组件_注册,引入和使用

全局注册 - main.js中

全局注册之后在哪都能用

import Vue from 'vue'
// 1.引入组件对象
import 组件对象 from 'vue文件路径'
eg:import PannelCom from './components/Pannel.vue'
// 2.注册
   // 参数1:组件名(随便定,建议大写开头)
   // 参数2:组件对象
Vue.component('组件名',组件对象)
eg:Vue.component('Pannel',PannelCom)

局部注册

// 1.引入组件对象
import 组件对象 from 'vue文件路径'
eg:import Pannel from './components/Pannel.vue'
export default {
    // 2.注册
      // 注册组件用components
      // key是组件名(也是上面要用的标签名)
      // value是引过来的组件对象
      // 如果key和value同名,可以简写一个key
    components: {
        '组件名':组件对象
        eg:'Pannel':Pannel    省略写法: Pannel
    }
}

使用

<template>
	<div id='app'>
		<h3>案例:折叠面板</h3>
<!--使用组件(把组件的名字当做标签进行使用):运行时,会把这个组件里的template标签替换到这里显示,并且把组件名当做标签使用-->
	    <Pannel></Pannel>
        <Pannel></Pannel>
        <Pannel></Pannel>
	<div>
</template>

总结:

1.组件创建,组件注册,声明组件名,当做标签使用即可

2.组件名第一个字母最好都大写(代码规范)

18.Vue组件_scoped作用

scoped作用:让当前样式只作用于当前这个组件范围内

scoped原理:在webpack打包的时候,遇到scoped,就会给当前"标签和css选择器"都添加一个data-v-随机数的一个属性,让当前样式里的选择器,只能选中当前页面的标签

19.vue组件通信

父传子

步骤:
1.在子组件里props中声明变量
2.在父组件里使用的时候给变量传值

props和data的区别:
data是要给初始值的,而props是要依赖外部给咱传入赋值

总结:
父向子传值的目的,为了让组件显示不同的内容,每次调用组件都是独立的

 

 父传子 - 配合循环

目标:把数据循环分别传入给组件内显示

App.vue

<template>
  <div>
    <MyProduct v-for="obj in list"
    :title="obj.proname" 
    :price="obj.proprice" 
    :info="obj.info"
    :key="obj.id"></MyProduct>
  </div>
</template>

<script>
import MyProduct from "./components/MyProduct_13.1";
export default {
  components: {
    MyProduct
  },
  data() {
    return {
      list: [
        { id: 1, proname: "超级好吃的棒棒糖", proprice: 18.8, info: '开业大酬宾, 全场8折' },
        { id: 2, proname: "超级好吃的大鸡腿", proprice: 34.2, info: '好吃不腻, 快来买啊' },
        { id: 3, proname: "超级无敌的冰激凌", proprice: 14.2, info: '炎热的夏天, 来个冰激凌了' },
      ],
    };
  },
};
</script>

<style>
</style>

components/MyProduct

<template>
  <div class="my-product">
    <h3>标题: {{ title }}</h3>
    <p>价格: {{ price }}元</p>
    <p>{{ info }}</p>
  </div>
</template>

<script>
export default {
  props: ['title', 'price', 'info'] // 声明属性, 等待接收外部传入的值
}
</script>

<style>
.my-product {
  width: 400px;
  padding: 20px;
  border: 2px solid #000;
  border-radius: 5px;
  margin: 10px;
}
</style>

单项数据流

props -> 父向子,单项
props内的变量是只读的,不建议重新赋值
props内的变量的值如果是对象类型的,互相引用,互相影响
注意:不要修改props变量的值
原因:
1.数据导致不一致,(看下图),哪个组件内部改了数据,"基础类型"数据不会影响到props数组的值
2.如果props的值是一个对象(引用关系),改变对象里的属性值,会互相影响

 子传父

子触发父的事件,然后往里传值

步骤:
1.App.vue(父),给父组件绑定自定义事件  @自定义事件="父methods里方法名"
2.MyProduct2.vue(子),给真正点击事件中this.$emit("自定义事件",要传的值)

EventBus

目标:常用于跨组件通信时使用
语法:
main.js - 创建一个空的Vue对象,并挂载到项目Vue的原型上(保证所有vue子组件都能访问到空Vue对象)
在要接收值的页面this.$bus.$on("自定义事件名",函数体)
在要传值的页面this.$bus.$emit("对应自定义事件名",实参值)
总结:main.js注册空的Vue对象,只负责$on注册事件,$emit触发事件,一定要确保$on先执行
步骤:
1.main.js里,注册一个全局的对象 Vue.prototype.$bus = new Vue() - 此对象只负责监听和触发事件
2.准备接收数据的.vue文件中,注册事件this.$bus.$on("事件名",(形参) => {})
3.发送数据的.vue文件中,触发事件  this.$bus.$emit("事件名",实参值)

20.Vue生命周期(钩子函数)

目标:vue框架内置函数,随着组件的生命周期,自动按次序执行
作用:特定的时间点,执行某些特定的操作
场景:组件创建完毕后,可以在created生命周期函数中发起Ajax请求,从而初始化data数据
分类:
初始化:beforeCreate,created
挂载:beforeMount,mounted
更新:beforeUpdate,updated
销毁:beforeDestroy,destroyed
打开生命周期官网图片,编写代码案例,来测试各个生命周期方法

  beforeCreate() {
    // 1. 创建前
    console.log("beforeCreate --- 实例初始化后,数据观测之前,创建data和methods事件监听之前");
    console.log(this.msg); // undefined
  },
  created() {
    // 2. 创建后
    console.log("created ---  实例初始化后, 数据观测以后,创建data和methods事件初始化完毕,创建组件后");
    console.log(this.msg); // "我是变量"
  },
  beforeMount() {
    // 3. 挂载前
      // template里的vue模板标签,会被vue解析成虚拟DOM(本质上就是一个js对象保存节点信息)
    console.log("beforeMount --- 挂载之前,确定替换目标,但是App虚拟DOM未替换到页面上,vue的虚拟DOM, 挂载到真实的网页之前");
    // console.log(document.getElementById("myUl").children[1].innerHTML); // 报错
  },
  mounted() {
    // 4. 挂载后
    console.log("mounted --- 挂载之后,虚拟DOM替换到指定位置上,真实DOM显示,vue的虚拟DOM, 挂载到真实的网页上");
    console.log(document.getElementById("myUl").children[1].innerHTML);
  },
  beforeUpdate() {
    // 5. 更新前
    console.log("beforeUpdate --- 数据更新, 页面更新前,更新真实Dom之前");
    // 比如点击新增数组元素, vue会触发此生命周期函数, 但是此时页面并未更新, 所以获取不到新增的li标签
    // console.log(document.getElementById("myUl").children[4].innerHTML); // 报错
  },
  updated() {
    // 6. 更新后
    console.log("updated --- 数据更新, 页面更新后,更新真实DOM之后");
    console.log(document.getElementById("myUl").children[4].innerHTML);
  },
  beforeDestroy() {
    // 7. 销毁前
    console.log("beforeDestroy --- 实例销毁之前调用,销毁此组件之前");
      // watches和移除孩子们,vue内部会自动触发
      // 此生命周期函数使用场景:  移除事件监听  this.$but.$off('事件名')
  },
  destroyed() {
    // 8. 销毁后
    // (清空一些本地变量 / 全局变量 / 销毁当前组件的eventBus事件, 引用的全局事件)
    console.log("destroyed --- 销毁完成,组件已经销毁");
  }

21.跨域

什么是跨域呢?
口诀:网页所在的协议/域名/端口,和Ajax要请求的协议/域名/端口有一个对不上就会发生跨域访问
解决:
1.JSONP
前端用script标签src属性请求接口地址(不用ajax),后端要返回"函数(数据)"字符串
2.cors
前端(现代浏览器默认都支持-前端不用动) -- 后端开启cors(开启cors的原理:响应头:Allow-Origin-Access-Control:*,就是告诉浏览器有哪些源允许链接后台,这里的*就代表任何源,什么叫做源呢?就是浏览器里的那个地址栏从哪来的)
3.反向代理
前端开一个本地自己的服务器 - 后端不用动(正常提供接口地址)(原理:服务器请求服务器没有跨域限制)
前端ajax -> 本地自己服务器(开cors) -> 后端服务器(不开cors)

22.axios

目标:axios是一个专门用于发送ajax请求的库
特点:
1.支持客户端发送Ajax请求
2.支持服务端Node.js发送请求
3.支持Promise相关用法
4.支持请求和响应的拦截器功能
5.自动转换JSON数据
axios底层还是原生js实现,内部通过Promise封装的
axios原地会返回一个promise,点then专门用来接收promise这个成功的异步任务(因为网络请求是异步任务),catch用来接收失败的任务
总结:axios这个方法原地返回的是一个Promise对象

基本使用:
1.下载axios库 到当前工程 yarn add axios
2.到要使用的vue页面,引入axios包
 import axios from 'axios'
3.使用axios里的方法,执行一次网络请求
export default {
    created() {
        4.使用axios调用接口
        axios((
            url:"http://xxxx",     // 请求地址
            method:"GET",          // get   post
            data: {   // 拼接到请求体的参数,  post请求的参数
            xxx:xxx,
            },
            params: {   // 拼接到请求行的参数,get请求的参数
              xxx:xxx
            }
        )).then(res => {
            console.log(res) // 接收请求后台返回的接口数据
        }).catch(err => {
            console.log(err) // 后台报错返回
        })
    }
}

把请求的数据铺设到页面

<template>
  <div>
    <p>所有书籍信息名字</p>
    <ul>
      <li v-for="obj in list" :key="obj.id">{{ obj.bookname }}</li>
    </ul>
  </div>
</template>
</script>
import axios from 'axios'
export default {
  data(){
    return {
      list: []
    }
  },
  created() { 
    axios({
      url: "xxx",
      method: "GET"
    }).then(res => {
      this.list = res.data.data;
    })
  }
};
</script>

axios_get和post方式传参

get方式用params传参, 也就是 (url?后面自带你写的参数) ?bookname=书名

为什么obj里的key要和参数名对应上?

data: {
    ...this.obj,   // 这里就可以直接传obj里的key+value给后台
}

axios_全局默认配置

http://www.axios-js.com    axios官网

目标:配置基础前缀地址,统一管理
可以在官网看到axios的很多默认配置
axios.defaults.baseURL = 'http://123.57.109.30:3006'
设置完这句话以后,具体的axios()请求时,会自动在url前面会拼接baseURL 的值

23.ref

目标:利用ref和$refs可以用于获取dom元素,或者组件实例
使用场景1:获取到原生DOM标签
<h1 ref="myH">1.ref获取原生dom</h1>
<button @click='fn'>点击修改上面内容</button>
使用场景2:获取组件对象,调用组件里方法
<h1>2.调用demo组件方法</h1>
<button @click='fn2'>点击demo组件里最后一个高亮</button>
<Demo ref='de'></Demo>
总结:ref定义值,通过$refs.值来获取dom或组件对象

 使用场景1:获取到原生DOM标签

 使用场景2:获取组件对象,调用组件里方法

24.$nextTick使用

目标:等DOM更新后,触发此方法里函数体执行
例子:点击按钮,count增1后,获取dom马上打印内容
问题:发现DOM是异步更新的
解决:使用$nextTick等待DOM更新后再触发此方法
总结:dom是异步更新的,$nextTick可以等待dom更新后触发此方法
扩展知识:$nextTick()返回Promise对象,可以配合async+await改成同步流程去掉回调函数

<template>
  <div>
      <p ref="myP">{{ count }}</p>
      <button @click="btn">点击数字+1</button>
  </div>
</template>

<script>
export default {
    data(){
        return {
            count: 0
        }
    },
    methods: {
        btn(){
            this.count += 1;
            // 问题: 马上获取原生DOM标签的innerHtml打印, 拿不到最新的
            // console.log(this.$refs.myP.innerHTML); // 0
            // vue数据改变后 - 更新DOM是"异步"的
            // 异步代码不会阻塞继续执行, 所以拿到的是p标签原来的内容0
            
            // 异步更新DOM后, 页面上显示了1


            // 解决方案: // 固定this.$nextTick(() => {})   微任务
            // DOM更新后, 会触发$nextTick()里的函数体执行
            this.$nextTick(() => {
                console.log(this.$refs.myP.innerHTML); // 1
            })
        }
    }
}
</script>

$nextTick以及ref的使用场景:

<template>
  <div>
    <!-- 点击按钮, 输出框出来, 自带聚焦行为 -->
    <input type="text" v-if="isShow" ref="myInp"/>
    <button v-else @click="btn">点击弹出搜索框</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isShow: false,
    };
  },
  methods: {
    btn() {
      this.isShow = true;
      // 自动聚焦-获取到标签(原生DOM)
      // 数据改变-页面异步更新的, 所以$nextTick里面等待页面更新完毕, 再去触发focus
      console.log(this.$refs.myInp);
      this.$nextTick(() => {
        this.$refs.myInp.focus();       
      })
    },
  },
};
</script>

25.组件name属性使用

目标:给组件name属性赋值,可在注册组件时使用
作用:给当前组件起名,可以用来注册组件使用组件

1.组件定义name属性和值,值就是组件的名字

2.使用组件时,声明组件名字可用name属性值 ( ComName变量的值就是export default后的{} )

26.动态组件

同一个挂载点,可以切换不同组件进行显示

目标:多个组件使用同一个挂载点,并动态切换,这就是动态组件
缺点:组件被切换的时候,会频繁的创建和销毁,性能不高
解决:组件缓存,在挂载点套Vue内置的组件<keep-alive></keep-alive>

需求:完成一个注册功能页面,2个按钮切换,一个填写注册信息,一个填写用户简介信息

动态组件步骤:
1.准备好要切换使用的组件,引入,注册名字
2.确定挂载点,赋予一个变量给is,只要切换变量里的组件名,页面就会切换组件
<template>
  <div>
    <h1>1.动态组件</h1>
    <p>同一个挂载点,切换不同组件显示:</p>
    <button @click="componentName = 'UserName'">账号密码填写</button>
    <button @click="componentName = 'UserInfo'">个人信息填写</button>
    <div style="border: 1px solid red">
        <!-- component是vue内置组件 - 专门用于挂载组件配合is属性 -->
        <!-- is属性的值就是这个位置要使用的组件名 -->
        <component :is="componentName"></component>
    </div>
  </div>
</template>

<script>
import UserName from "./components/UserName";
import UserInfo from "./components/UserInfo";
export default {
  data() {
    return {
      componentName: "UserName",
    };
  },
  components: {
    UserName,
    UserInfo,
  },
};
</script>

27.组件缓存

<keep-alive></keep-alive>

目标:组件切换会导致组件被频繁销毁和重新创建,性能不高
需求:使用Vue内置的keep-alive组件,可以让包裹的组件保存在内存中不被销毁
演示1:可以先给UserName.vue和UserInfo.vue注册created和destroyed生命周期事件,观察创建和销毁过程
演示2:使用keep-alive内置的vue组件,让动态组件缓存而不是销毁
补充生命周期:
activated - 激活
deactivated - 失去激活状态
问题:组件被切换的时候,会频繁的创建和销毁,性能不高
解决:组件缓存,在挂载点套Vue内置的组件<keep-alive></keep-alive>
效果:频繁切换,组件不会被销毁而是缓存在了内存中

 

 总结:keep-alive可以提高组件的性能,内部包裹的标签不会被销毁和重新创建,触发激活和非激活的生命周期方法

28.组件插槽

目标:用于实现组件的内容分发,通过slot标签,可以接收到写在组件标签内的内容
vue提供组件插槽能力,允许开发者在封装组件时,把不确定的部分定义为插槽
组件插槽:给组件内传递(分发)不同的标签展示,你插入什么就展示什么
插槽指的就是slot
需求:折叠面板案例,想要实现不同内容显示
我们把折叠面板里的Pannel组件,添加组件插槽方式
口诀:
1.(<Pannel>)组件内用<slot></slot>占位
2.使用组件时<Pannel></Pannel>夹着的地方,传入标签替换slot
总结:组件内容分发技术,slot占位,使用组件时传入替换slot位置的标签

组件插槽-插槽默认内容

目标:如果外面不给传,想给这个默认显示内容
口诀:
1.插槽指的是slot标签,slot标签夹着的地方写好默认显示内容
2.<slot>夹着的地方默认写显示内容,如果不给插槽slot传东西,则使用<slot>夹着的内容在原地显示
效果:使用组件不给slot传标签,就显示slot夹着的默认内容  <slot>我是默认的内容</slot>

组件插槽-具名插槽

目标:当一个组件内有2处以上需要外部传入标签的地方
传入的标签可以分别派发给不同的slot位置
要求:v-slot一般用跟template标签使用(template是html5新出标签内容模板元素,不会渲染到页面上,一般被vue解析内部标签)
使用具名插槽:
1.template包裹标签
2.template上v-slot:插槽名
优化:v-lost可以简化成#

组件插槽-作用域插槽

目标:子组件里的值,在给插槽赋值时在父组件环境下使用
复习:插槽内slot中显示默认内容
例子:默认内容在子组件中,但是父亲在给插槽传值,想要改变插槽显示的默认内容
口诀:
1.创建组件,准备slot,在slot上绑定属性和子组件值
2,使用组件,传入自定义标签,用template和v-slot='自定义变量名'
自定义变量名会自动绑定slot上所有属性,就可以使用子组件内的值,并替换slot位置
总结:组件内变量绑定在slot上,然后使用组件v-slot='变量',变量上就会绑定slot身上属性和值
作用: 外部使用组件插槽处, 可以使用组件内变量

 

作用域插槽口诀:
1.把子组件内容绑定在slot标签属性上 -为了准备传给外面使用组件插槽的地方
2.父使用组件时,template上v-slot='变量名'
变量名上有slot上所有的属性和值
=后面是变量名               :后面是name值

 使用场景:

目标:  了解作用域插槽使用场景,自定义组件内标签+内容

场景:  list数组需要在子组件中使用,这时候我们需要把list数组通过父向子传值props传递过去,然后进行渲染,假如其中有一个标签不知道自己以后到底是使用图片还是文字,这时候我们先用slot插槽占位,把图片地址渲染上去,页面会显示图片地址,而不是图片,那么就需要用到作用域插槽自定义标签,作用域插槽可以把组件内的值取出来自定义内容

 总结:插槽可以自定义标签,作用域插槽可以把组件内的值取出来自定义内容

29.自定义指令

目标:获取标签,扩展额外的功能
使用:在标签上使用v-focus

语法:局部创建

需求:在input框一上来就获取焦点:

 全局创建

目标:获取标签,扩展额外的功能
语法:全局注册
Vue.directive("fofo",{
    inserted(el){
        el.focus()
    }
})
使用:在标签上使用v-fofo
全局和局部的区别:
1.全局注册的,到处"直接"使用
2.局部注册的,只能在当前.vue文件内使用

自定义指令-传值

目标:定义color指令-传入一个颜色,给标签设置文字颜色
语法:

Vue.directive("color",{
    inserted(el,binding){  // 插入时(第一次创建)触发此函数
        console.log(el)
        console.log(binding)
        el.style.color = binding.value
    },
    update(el,binding){    // 当指令更新的时候(对应变量变化)-指令会触发这个函数
        el.style.color = binding.value
    }
})
使用:在标签上使用v-color='red'

总结:
1.v-xxx,自定义指令,获取原生DOM,自定义操作
2.自定义指令是给标签添加额外的功能,而且还可以传入值来操作原生dom标签

30.路由vue-router

路由地址: Vue Router

vue路由就是url的哈希值和组件的映射关系
哈希值和对应vue文件的映射关系就是路由

 路由原理手写

目标:了解hash改变,如何显示不同的组件的过程
基本思路:
1.用户点击了页面上的a链接
2.导致了URL地址栏中的Hash值发生了变化
3.前端js监听(window.onhashchange)到Hash地址的变化
4.前端js把当前Hash地址对应的组件渲染到浏览器中(暂时用动态组件显示)
总结:改变浏览器url的hash值,JS监听到hash值改变,把对应的组件显示到同一个挂载点

前端路由原理:hash值和组件的映射关系
思路:
1.创建3个页面组件,创建3个a标签,可以切换hash值
2.暂用动态组件,切换显示页面
3.(关键),JS代码监听hash值改变,修改comName的值  - 切换页面目的

 vue-router基本使用 - 7步骤

目标:学会vue官方提供的vue-router路由系统功能模块使用
不自己写js检测和动态组件切换了,让vue-router封装起来了,我们遵守vue-router规则使用即可
步骤:
1.下载vue-router模块到当前工程
 yarn add vue-router
2.在main.js中引入vue-router函数
 import VueRouter from 'vue-router'
3.在main.js中添加到Vue.use()类中 - 类似于中间件
 Vue.use(VueRouter)
4.在main.js中创建路由规则(规则就是数组套对象)-路径和组件名对应关系
import MyHome from "./views/MyHome";
import MyMovie from "./views/MyMovie";
import MyAbout from "./views/MyAbout";
// 4.创建路由规则数组套对象(hash值和组件映射关系)
const routes = [    // 规则数组
  {  // 每个对象就是一套一对一的映射规则
    path: "/home",  // 检测的hash值(不带#)
    component: MyHome   // 如果url的hash值命中了path,展示此组件页面
  },
  {
    path: "/movie",  
    component: MyMovie  
  },
  {
    path: "/about",
    component: MyAbout
  },
]
5.利用规则生成路由对象
const router = new VueRouter({
  routes: routes  // key固定的叫routes(传入路由规则),value是上面规则数组变量名   (可简写)
})
6.把路由对象注入到new Vue中
new Vue({
  render: h => h(App),
  // 把路由对象(内涵规则) - 注入到vue对象中 - 让vue拥有路由功能
  router: router  // (可简写)
}).$mount('#app')
7.把components和is,替换成router-view(内置的组件用于挂载切换的页面组件)
 // vue-router模块,给vue全局注册的路由内置组件
 // 作用: 当hash值改变,命中路由规则数组里的对象,会把对应的component组件显示到这里
<router-view></router-view>
总结:下载路由模块,编写对应规则注入到vue实例上,使用router-view挂载点显示切换的路由

链接导航router-link

目标:可用全局组件router-link来替代a标签
1.vue-router提供了一个全局组件router-link:作用用于提供路由链接
2.router-link实质上最终会渲染成a链接 to属性等价于提供href属性(不要写#)
3.router-link提供了链接导航高亮的功能
总结:链接导航,用router-link配合to,实现点击切换路由
好处:
1.router-link实际上还是a标签,to属性等价于href的值,默认帮我们添加#前缀
2.router-link内置高亮的类名

 链接导航router-link -- 高亮类名使用_区别

目标:a标签和router-link区别就是,路由组件激活时自带class
我们只需要声明具体class类名,设置好具体的样式即可
    router-link-exact-active  (精确匹配)url中hash值,与to属性值完全相同,设置此类名
    router-link-active (模糊匹配) url中hash值,包含to属性值,设置此类名
可以再添加个路由路径为/的,观察自动添加的类名
总结:
匹配:浏览器url地址栏里hash值和a标签的href的值  进行匹配
例如:  /home      /home  - 有2个类名
例如:  /home      /      - 只有router-link-active一个类名

 链接导航router-link -- 自定义高亮类名active-class

目标:a标签和router-link区别就是,路由组件激活时自带class
router-link上有一个固定的active-class属性名,用于自定义高亮的类名,默认替换router-link-active这个类名
exact-active-class 替换默认的 router-link-exact-active这个类名
active-class 替换默认的 router-link-active这个类名
1.router-link设置属性和类名
<router-link active-class='active' to='/home'>首页</router-link>
2.style中定义类名和具体样式
.active {
    color:orange;
}

 

 链接导航router-link - 跳转传参2种方式

两种传参方式
目标:在跳转路由时,可以给路由对应的组件内传值
在router-link上的to属性传值,语法格式如下:
方式一:
传递:to="/path?参数名=值"
接收:$route.query.参数名  -  query收集的就是?后面的参数和值
方式二: 动态路由
1.路由规则上,留好参数名
{
    path:"/path/:参数名"
    eg: path:"/path/:b"
}
2.路由跳转的时候,需要在对应路径传值
to="/path/值"
3.接收:$route.params.参数名
      eg:$route.params.b

 链接导航-路由重定向和404兜底

目标:默认上来强制显示某个路由页面,找不到路径给个提示页面
网页打开url默认hash值是 空字符串或者/路径
redirect是设置要重定向到哪里
路由最后,path匹配*(任意路径) - 前面不匹配就命中最后这个
路由重定向目的:网页打开就显示一个页面
{     
    path:'/',    // 网页打开默认的hash值  /  根路径
    redirect:'/home'   // 重定向,马上修改url的hash值为/home,强制切换路由路径
}
// *代表的是通配符,本配置最好写在最后面,路由路径是从上往下匹配
// 404配置
{
    path:'*',
    component:NotFound  // 如果找不到路径,就显示404组件
}

 

路由模式

目标:修改路由在地址栏的模式
hash路由例如:http://localhost:8081/#/home
hash模式:路由以#/形式展示在url上
history路由例如:http://localhost:8081/home
history模式:路由以路径形式展示在url上

编程式导航

编程式导航其实就是js跳转

注意:要跳的路径一定要跟你路由规则数组里的path对应上

注意: 如果当前已经在/home,你还想往导航里push一个/home就会发生一个警告错误(冗余导航,不要添加重复的路径)

格式3(了解)

其实和上面的两种传参方式没啥区别,就是多传入一个name值,然后把path改换成了name,用name来控制导航跳转

编程式导航 - 跳转传参

目标:JS跳转路由,传参
口诀:
用name+params传 => $route.params.key  - 接
用path+query传 => $route.query.key  - 接
两个传参区别:
path+query在地址栏上,刷新后还能获取到
name+params在内存中,刷新后就不存在了

路由嵌套

一级路由从根开始写
其他级路由都不要'/'这个根

路由嵌套步骤:
1.根据业务想好,在哪个一级路由页面里嵌入router-link和router-view
2.配置路由规则数组,在哪个一级path里嵌入children,子路由规则
3.给router-link添加to属性,注意从/开始写

全局前置守卫

目标:路由跳转之前,会触发一个函数
使用例子:在跳转路由前,判断用户登陆了才能去<我的音乐>页面,未登录弹框提示回到发现音乐页面
语法:router.beforeEach((to,from,next) => {})
最后要调用next()才会跳转到正常下一个路由页面

 全局后置守卫

目标:路由跳转后,触发的函数
语法:router.afterEach((to,from) => {})

路由总结:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值