首页 前端知识 vue 全家桶 vue教学 vue

vue 全家桶 vue教学 vue

2024-06-08 22:06:37 前端知识 前端哥 408 125 我要收藏

vue全家桶有以下几种

1.vue-cli:

vue-cli也叫脚手架,官方定义为Vue.js 开发的标准工具!相比scirpt标签引入,脚手架具有如下特点:
1)、功能丰富
对 Babel、TypeScript、ESLint、PostCSS、PWA、单元测试和 End-to-end 测试提供开箱即用的支持。
2)、易于扩展
它的插件系统可以让社区根据常见需求构建和共享可复用的解决方案。
3)、无需 Eject
Vue CLI 完全是可配置的,无需 eject。这样你的项目就可以长期保持更新了。
4)、CLI 之上的图形化界面
通过配套的图形化界面创建、开发和管理你的项目。
5)、即刻创建原型
用单个 Vue 文件即刻实践新的灵感。
6)、面向未来
为现代浏览器轻松产出原生的 ES2015 代码,或将你的 Vue 组件构建为原生的 Web Components 组件。

安装:

npm install -g @vue/cli
# OR
yarn global add @vue/cli
 
//安装完成后创建一个项目,vue ui为图形化构建,相对简单(推荐)
vue create my-project
# OR
vue ui


2.vueRouter:

Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:

1)嵌套的路由/视图表
2)模块化的、基于组件的路由配置
3)路由参数、查询、通配符
4)基于 Vue.js 过渡系统的视图过渡效果
5)细粒度的导航控制
6)带有自动激活的 CSS class 的链接
7)HTML5 历史模式或 hash 模式,在 IE9 中自动降级
8)自定义的滚动条行为

版权声明:本文为CSDN博主「互联网杂货店」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:Vue全家桶有哪些?(详细)_中大型单页面应用项目所必须的插件和框架, 对 babel、typescript、eslint、pos-CSDN博客

vueRouter 安装

npm install vue-router
//安装后在mainjs引入
import VueRouter from 'vue-router'
 
Vue.use(VueRouter)

3.vuex:

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。

什么情况下我应该使用 Vuex?
Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。

如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
安装方法

npm install vuex --save


4.Axios:

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
特性
1)从浏览器中创建 XMLHttpRequests
2)从 node.js 创建 http 请求
3)支持 Promise API
4)拦截请求和响应
5)转换请求数据和响应数据
6)取消请求
7)自动转换 JSON 数据
8)客户端支持防御 XSRF
安装方法

npm install axios


5.搭配UI框架如:iview、vant、elementUI:

view 一套基于 Vue的高质量UI 组件库(分为小程序和pc端等不同版本);
vant 轻量、可靠的移动端 Vue 组件库,是有赞开源的一套基于 Vue 2.0 的 Mobile 组件库,旨在更快、更简单地开发基于 Vue 的美观易用的移动站点。
Ant Design Vue 是 Ant Design 的 Vue 实现,开发和服务于企业级后台产品。
elementUI 是基于 Vue 2.0 桌面端中后台组件库。
————————————————
版权声明:本文为CSDN博主「前端韦小宝」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:vue全家桶都有哪些_vue全家桶有哪些-CSDN博客

一、vue-cli

1、Vue基本概念

(1)Vue是什么?
  • Vue是一套用于构建用户界面的渐进式框架
  • 官网地址: https://cn.vuejs.org/ (作者: 尤雨溪)
(2)渐进式是什么?
  • Vue这个框架有很大的生态系统,我们可以使用Vue本身开发项目,也可以在Vue本身的基础上使用它的生态中的某些工具进行开发。

(3)库和框架是什么?
  • 库:库是更多是一个封装好的特定的集合,提供给开发者使用,而且是特定于某一方面的集合(方法和函数),库没有控制权,控制权在使用者手中,在库中查询需要的功能在自己的应用中使用,我们可以从封装的角度理解库;
  • 框架:框架顾名思义就是一套架构,会基于自身的特点向用户提供一套相当于叫完整的解决方案,而且控制权的在框架本身,使用者要找框架所规定的某种规范进行开发。

2、@vue/cli脚手架

  • Vue CLI 致力于将 Vue 生态中的工具基础标准化。它确保了各种构建工具能够基于智能的默认配置即可平稳衔接,这样你可以专注在撰写应用上,而不必花好几天去纠结配置的问题。与此同时,它也为每个工具提供了调整配置的灵活性,无需 eject。

(1)基本使用

(1)使用 npm 命令来全局安装 脚手架工具

npm install -g @vue/cli  # -g全局安装,安装到本地,只需下载一次

(2) 检查脚手架是否安装成功

vue --version

(3)创建项目

 vue create 项目名称
#项目名称不能是中文,也不能是驼峰命名法的项目名称 小写字母的名字或者多个-链接的名称

(4)启动本地热更新开发服务器

cd 项目名称  #切换到当前项目目录下

npm run serve  #启动webpack本地热更新开发服务器
(2)3@vue/cli 目录和代码分析

脚手架里主要文件和作用?

  1. node_modules – 都是下载的第三方包
  2. public/index.html – 浏览器运行的网页
  3. src/main.js – webpack打包的入口
  4. src/App.vue – Vue页面入口
  5. package.json – 依赖包列表文件

(3)关闭检查工具eslint

eslint是一种代码检查的工具

module.exports = defineConfig({
  //...其他配置
    lintOnSave: false,  //关闭eslint 代码检查工具
  });

3、Vue指令

(1)在dom标签中, 直接插入vue数据变量

又叫: 声明式渲染/文本插值/插值表达式

语法: {{ 表达式 }}

 export default {
  // 此语法是固定的
  data() {  //data函数返回的对象上, 用key属性声明
    return {
      // 以后只要你想让数据展示在页面上 就把数据写在这里
    };
  },
};
<!-- // <标签>{{变量}}</标签>  //双大括号, 可以把vue数据变量直接显示在标签内 -->

(2)设计模式与MVVM

设计模式是对代码分层, 引入一种架构的概念

MVVM(模型, 视图, 视图模型双向关联的一种设计模式)

以v-开头的标签属性, 叫指令, 给标签添加额外功能

(3)v-bind 指令 给标签属性设置Vue变量的值
<a v-bind:href="url">我是a标签</a>  /* 语法:v-bind:属性名="vue变量" */
<img :src="imgSrc">    /* 简写::属性名="vue变量" */

v-bind 动态绑定 作用: 及时对页面的数据进行更改, 可以简写成:分号

(4)v-on 指令 绑定事件和修饰符
<buttton v-on:"click"="count + 1">增加1</button>    //v-on:事件名=“要执行的少量代码" 
<buttton v-on:"click"="addFn">增加1</button>   //v-on:事件名=“methods中的函数名" */
<buttton v-on:"click"="addCount(5)">增加5</button> //v-on:事件名=“methods中的函数名(实参)" 
<buttton @click="addCount(5)">增加5</button>   //@事件名=“methods中的函数”

v-on 给标签绑定事件函数,可以缩写为@,例如绑定一个点击事件函数 函数必须写在methods里面

修饰符:

语法:@事件名.修饰符="methods里函数"

修饰符列表

.stop //阻止事件冒泡

.prevent //阻止默认行为

.once //程序运行期间, 只触发一次事件处理函数

@keyup.键盘按键 // 检测按键

<buttton @click.stop="btn">阻止事件冒泡</button>    
<buttton @click.prevent ="btn">阻止默认行为</button>   
<buttton @click.once="btn">只触发一次事件处理函数</button> 
<buttton @keyup.enter="btn">只触发一次事件处理函数</button> /* 检测enter事件,btn 回调函数 */

Vue事件处理函数的事件对象$event

语法

  • 无传参, 通过形参直接接收
  • 传参, 通过 $event 指代事件对象传给事件处理函数

(5)v-model 指令 和修饰符

value属性和Vue数据变量, 双向绑定到一起

语法: v-model="Vue数据变量"

  • 暂时只能用在表单标签上,把vue的数据变量和表单的value属性双向绑定在一起
<template>
  <div>
   <!-- 把vue的数据变量和表单的value属性双向绑定在一起 -->
    <div>把vue的数据变量和表单的value属性双向绑定在一起</div>
    <input type="text" v-model="txt">
    <div>下拉菜单绑定Vue变量</div>
      
   <!-- 下拉菜单绑定Vue变量,在select, value在option上 -->
    <select name="" id="" v-model="value">
      <option value="北京">北京</option>
      <option value="上海">上海</option>
      <option value="西安">西安</option>
      <option value="长安">长安</option>
    </select>

   <!-- v-model 绑定 checkbox, v-model的vue变量是   非数组 – 关联的是checked属性   数组 – 关联的是value属性 -->
    <span>复选框绑定Vue变量</span>
    <input type="checkbox" name="" id="" value="抽烟" v-model="hobby">抽烟
    <input type="checkbox" name="" id="" value="喝酒" v-model="hobby">喝酒
    <input type="checkbox" name="" id="" value="敲代码" v-model="hobby">敲代码

    <!--   单选框绑定Vue变量 -->
    <div>单选框绑定Vue变量</div>
    <input type="radio" name="sex" id="" v-model="gender">男
    <input type="radio" name="sex" id="" v-model="gender">女
  </div>
</template>

v-model修饰符

语法: v-model.修饰符="Vue数据变量"

.number //以parseFloat转成数字类型

.trim //去除首尾空白字符

.lazy //在change时触发而非inupt时

(6)v-text和v-html 指令

v-html //会解析标签,会覆盖标签内容`<开始标签 v-html="">内容</结束标签>`

v-text //不会解析标签,会覆盖标签内容`<开始标签 v-text="">内容</结束标签>`

(7)v-show和v-if以及v-else 指令

语法:

v-show="Vue变量" //原理: v-show 用的display:none隐藏 (频繁切换使用)

v-if="Vue变量" //原理: v-if 直接从DOM树上移除

高级语法:

  • 当v-if后面表达式的值为true的时候显示v-if所在的元素
  • 当v-if后面表达式的值为false的时候显示v-else所在的元素

v-else的使用 //v-if 可以配合v-else或者v-else-if使用

(8)v-for 指令 循环遍历

v-for 根据数组的个数, 循环数组元素的同时还生成所在的标签

(1) 循环数组

<li v-for="(元素, 索引) in 数组" :key=""></li>

(2) 遍历对象数组

<li v-for="元素 in 数组" :key=""></li>

(3) 遍历对象

<li v-for=")(值, 键) in 对象" :key=""></li>

(4) 遍历一个具体的数字

<li v-for="元素 in 数字" :key=""></li>

注意:

  • 谁想循环就把 v-for 写谁身上
  • v-for=“(值变量, 索引变量) in 目标结构”-一定注意in两边必须有空格
  • 值变量和索引变量不能用到v-for范围以外

(9)自定义指令

全局注册 - 语法

<!-- 全局自定义指令   focus是命令名   定义时不带 -v ,使用时需要带 -v -->
Vue.directive("focus", {
  inserted(el) {
<!-- el 就是绑定标签  可以对el进行标签扩展额外功能 -->
    el.focus();
  },
});

局部注册 – 语法

directives:{
  // color 是命令名   定义时不带 -v ,使用时需要带 -v
    color:{
      inserted(el,binding){
        <!-- el 就是绑定标签  可以对el进行标签扩展额外功能  -->
        el.style.color=binding.value
      }
    }
  }

参考地址:自定义指令 — Vue.js

阶段面试题

面试题

1. Vue的最大优势是什么?

简单易学, 轻量级整个源码js文件不大, 双向数据绑定, 数据驱动视图, 组件化, 数据和视图分离,

vue负责关联视图和数据, 作者中国人(尤雨溪), 文档都是中文的, 入门教程非常多, 上手简单.

相比传统网页, vue是单页面可以只刷新某一部分

2. Vue和jQuery区别是什么?

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

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

3. mvvm和mvc区别是什么?

MVC: 也是一种设计模式, 组织代码的结构, 是model数据模型, view视图, Controller控制器, 在控制器这层里编写js代码, 来控制数据和视图关联

MVVM: 即Model-View-ViewModel的简写。即模型-视图-视图模型, VM是这个设计模式的核心, 连接v和m的桥梁, 内部会监听DOM事件, 监听数据对象变化来影响对方. 我们称之为数据绑定

4. Vue常用修饰符有哪些?

   .prevent: 提交事件不再重载页面;

.stop: 阻止单击事件冒泡;

.once: 只执行一次这个事件

5. Vue2.x兼容IE哪个版本以上

不支持ie8及以下,部分兼容ie9 ,完全兼容10以上, 因为vue的响应式原理是基于es5的Object.defineProperty(),而这个方法不支持ie8及以下。

6. 对Vue渐进式的理解

渐进式代表的含义是:主张最少, 自底向上, 增量开发, 组件集合, 便于复用

7. v-show和v-if的区别

v-show和v-if的区别? 分别说明其使用场景?

v-show 和v-if都是true的时候显示,false的时候隐藏

但是:false的情况下,

v-show是采用的display:none

v-if采用惰性加载

如果需要频繁切换显示隐藏需要使用v-show

8. 说出至少4个Vue指令及作用

v-for 根据数组的个数, 循环数组元素的同时还生成所在的标签

v-show 显示内容

v-if    显示与隐藏

v-else  必须和v-if连用  不能单独使用  否则报错

v-bind  动态绑定  作用: 及时对页面的数据进行更改, 可以简写成:分号

v-on  给标签绑定函数,可以缩写为@,例如绑定一个点击函数  函数必须写在methods里面

v-text  解析文本

v-html   解析html标签

9. 为什么避免v-for和v-if在一起使用

Vue 处理指令时,v-for 比 v-if 具有更高的优先级, 虽然用起来也没报错好使, 但是性能不高, 如果你有5个元素被v-for循环, v-if也会分别执行5次.

4、Vue基础_更新监测, key作用

(1)数组更新监测
  1. 数组变更方法, 就会导致 v-for 更新, 页面更新
  2. 数组非变更方法, 返回新数组, 就不会导致 v-for 更新
  3. 用新数组覆盖 或 用 this.$set(改变哪个结构,位置,改变的目标值)设置
  4. 数组变更方法总共 7 个方法 'push','pop','shift','unshift','splice','sort','reverse'

(2)v-for 就地更新(diff算法 )

在值改变时,会把新旧的虚拟dom从跟节点开始到每一个子节点进行对比。

  1. 如果根节点一样,保留根节点,进行下一级对比,如果不一样,就删除根节点及其所有后代节点
  2. 如果后代节点一样,就原地复用,如果不一样就创建
  3. 如果属性一样,就原地复用,如果不一样就改变
  4. 如果内容一样,就原地复用,如果不一样就重新覆盖
(3)虚拟dom和真实dom的区别
  • 真实dom时显示在浏览器的 html 中
  • 虚拟dom是储存在内存中的 js 对象,储存的是关于dom的关键信息

(4)提高更新性能(key --> 用在 v-for 指令中)
  1. key 的要求是 唯一不重复的数字或字符串
  2. 有 id 用 id, 无 id 用索引,可以提高渲染的性能
  3. key 的好处就是 提高渲染的性能

(5)class 和 style 的绑定

class绑定

语法: `<标签 :class="{类名: 布尔值}"></标签>`

布尔值为 true 代表类名可用,为 flase 代表变量名不可用

style绑定

语法: `<标签 :style="{ css属性:data里定义的变量 }"></标签>`

<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

data: {
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}

5、Vue基础_过滤器

作用:

  • 把传入的值变成另一个值

定义过滤器:

全局过滤器 声明在 main.js

Vue.filter("过滤器的名字", (val)=>{return 经过处理的值})

局部过滤器 声明组件内(xxx.vue)

定义:filters: {过滤器的名字:(val)=>{return 经过处理的值}}

使用:

语法1: {{vue变量 | 过滤器名}}

语法2: :属性="vue变量 | 过滤器1 | 过滤器2"

注意事项:

  • 过滤器只能用在 插值表达式 || 动态属性绑定 中
  • 局部过滤器只能在当前组件中使用,不能出当前组件

格式化时间
  1. 下载包 moment
  2. 引入包 import moment from "moment"
  3. 定义局部过滤器
  4. 使用过滤器

6、Vue基础_计算属性

基础语法

  1. 应用场景: 如果一个值需要依赖于其他值而的来的,就需要计算属性
  1. 使用语法: computed: { 属性名(){ return 值 } }
  1. 特点: 函数内使用的变量改变, 计算属性自动重新计算结果并返回
  2. 注意事项:
  • 计算属性的名字不能和 data 中的属性名重复
  • 计算属性听起来是个属性,写起来是个方法,Vue 规定计算属性最后必须返回一个值
  • 计算属性的名字用在模板中(也可以用在别的计算属性),相当于变量
  • 计算属性的缓存特性: 当计算属性的依赖项不改变,直接从缓存中取值,只有依赖项发生变化,计算属性才会重新执行
  • 计算属性中不能出现异步代码
 computed: {
  计算属性名称: {
    get(){
      return 值
    }
    set(val){
      // 获取 val
      // 设置给计算属性
    }
  }
 }

7、Vue基础_侦听器

  • 作用: 监听 data 中已经定义的数据的
watch: {
  要监听的属性: (newVal, oldVal) => {};
}
watch: {
  要侦听的属性: {
    // 1. 处理函数
    handler(new,old){},
    // 2. 是否深度侦听
    deep: true,
    // 3. 是否立即执行
    immediate: true
  }
}

特点:

  • 当首次打开页面,侦听器不会执行,当要侦听的属性发生了变化,才会执行
阶段面试题

阶段面试题

面试题

1. Vue 中怎么自定义过滤器

  • Vue.js允许自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和动 态属性绑定 中
  • 用法:

全局的用Vue.filter()

局部的用filters属性

2. Vue中:key作用, 为什么不能用索引

  • :key是给v-for循环生成标签颁发唯一标识的, 用于性能的优化
  • 因为v-for数据项的顺序改变,Vue 也不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素
  • :key如果是索引, 因为索引是连续的, 如果删除其中某一个, 会导致最后一个被删除
  • 当我们再删除的时候, :key再根据数据来把新旧的dom对比时, 删除:key不存在的对应的标签(添加也是一样的插入到指定位置, 别的都不会动)

3. 数组更新有的时候v-for不渲染

  • 因为vue内部只能监测到数组顺序/位置的改变/数量的改变, 但是值被重新赋予监测不到变更, 可以用 Vue.set() / vm.$set()

8、Vue组件概念, 创建和使用

基本概念:
  1. 什么组件: 可复用的独立的 Vue 实例 (一段独立 UI 界面及逻辑的封装)
  2. 组件的好处: 提高了代码的维护性、扩展性、复用性、封装性
  3. 什么时候封装组件: 只要出现 能复用的 UI 界面 可以封装成组件(任何东西写 UI 界面 就本身就在组件里面写)

使用组件的方式
  1. 在项目中创建 xxxx.vue 文件
  2. 在另外一个 xx.vue 中 引入 xxxx.vue
  3. 在 xx.vue 中 注册组件
  4. 在 xx.vue 的 template 中使用组件

注意: 在注册组件的时候,希望大家尽量使用大驼峰命名或全部小字母 多个单词使用-链接(home,Home,MyHome, my-home)

组件的创建
  1. 创建 文件名.vue
  2. 注册组件 (全局 / 局部)
// 全局注册:
Vue.component("组件名称", 组件对象);

// 局部注册
export default {
  components: {
    组件名称: 组件对象,
  },
};

  1. 使用组件 (组件名用作标签)

scoped 的作用
  • 给 style 标签添加 scoped,Vue 会给该组件内所有的标签都添加一个 data-v-随机数的属性, 这样就使得组件内的样式只对当前组件内的标签有效了

组件通信_父传子_props

在父组件中使用子组件

  1. 父组件内, 在子组件标签上以属性方式给 props 变量传值
  2. 子组件内, props定义变量, 在子组件使用变量
  3. 使用 this.属性名字 就可以获得该值
props: {
arr:{title: String,  //数据类型
  likes: Number,  
  isPublished: Boolean,
  commentIds: Array,
  author: Object,
  callback: Function,
  contactsPromise: Promise, // or any other constructor
  validator(val){'返回的的是true 校验成功 反之校验失败'}  // val相当于arr
    }
}

  // type (规定数据类型) 
  //   String 字符串
  //   Number 数字
  //   Boolean 布尔
  //   Array 数组 
  //   Object 对象
  //   Date 日期
  //   Function 函数
  //   Symbol 独一无二的值(es6)

  //  default
  //   default : (默认值)
  //     基础数据类型: 直接赋值
  //     对象数据类型: 用函数赋值 ()=>[]
  //   required
  //     required: (必填项)
  //     默认为false,说明父级必须传入,否则会报错
  //   validator
  //     validator: 校验(验证传入的值是否符合规定)
  //     validator(){'返回的的是true 校验成功 反之校验失败'}
  

组件通信_父传子_this.$attrs

attrs是一个包含了当前组件所有非prop属性的对象。这些非prop属性是传递给组件的,但是组件并没有声明对应的prop属性。attrs 对象可以用来在组件内部将这些非 prop 属性继承下去,并将它们传递给子组件。

举个例子,如果一个父组件在使用时传入以下代码:

<my-component id="my-id" class="my-class"></my-component>

那么在 my-component 组件中,可以通过访问 this.$attrs 对象来获取 id 和 class 属性的值:

// my-component 组件内部代码
<template>
  <div :id="$attrs.id" :class="$attrs.class">
  <!-- 组件其他代码... -->
  </div>
</template>

需要注意的是,$attrs 对象中包含所有非 prop 属性,包括 class 和 style 等。当需要获取单独的非 prop 属性时,可以使用 $attrs 中对应属性名的方式来访问,如 $attrs.id。

单向数据流
  1. 单向数据流: 从父到子的数据流向, 叫单向数据流
  2. 特点: 只读(不允许在子组件中修改父组件传递的 props 的值,强制修改也不会影响原始数据,而且 vue 会报警告)

组件通信_子向父_自定义事件

技术要点

  1. 父组件内, 给组件@自定义事件="父 methods 函数"
  2. 子组件内, 恰当时机 this.$emit('自定义事件名', 值)

什么时候使用子传父技术?

  • 如果子组件想要改变父组件中的数据

sync用法

sync 修饰符的作用就是实现父子组件数据的双向绑定,v-model 也是可以实现数据的双向绑定,但是,一个组件只有一个 v-model,而 sync 修饰符可以实现多个参数的数据双向绑定。

链接:https://juejin.cn/post/6977022803744653320

父组件
  // 父组件 传值时添加  sync修饰符
<child  :showDialog.sync="showDialog" />

子组件
// 通过 this.$emit('update:props名称', 值) 方法来修改父组件得值
this.$emit('update:showDialog', false) 

组件通信-兄弟通信-EventBus
  1. 创建 eventBus 实例
import Vue from "vue";

export default new Vue();

  1. 组件中发送数据
<template>
  <div class="gg">
    <h2>哥哥组件</h2>
    <button @click="sendMsg">点击我发送一条消息给弟弟</button>
  </div>
</template>
<script>
  import eventBus from "@/eventBus";
  // 通过props属性来接受父组件中传递的数据
  export default {
    methods: {
      sendMsg() {
        eventBus.$emit("sendMessage", "想要一双AJ吗");
        this.$emit("send", "给弟弟5千元买个iPhone");
      },
    },
  };
</script>

<style>
  .gg {
    border: 1px solid green;
  }
</style>

  1. 组件中接受数据
<template>
  <div class="dd">
    <h2>弟弟组件</h2>
    <p>弟弟接收的消息: {{ msg }}</p>
  </div>
</template>
<script>
  import eventBus from "@/eventBus";
  // 通过props属性来接受父组件中传递的数据
  export default {
    props: ["msg"],
    // 钩子函数(自动执行的)
    created() {
        eventBus.$on("sendMessage", (data) => {
        console.log("哥哥给弟弟的消息", data);
     });
    console.log("弟弟接收的消息", this.msg);
    },
  };
</script>

<style>
  .dd {
    border: 1px solid red;
  }
</style>

Mixin混入用法
  • mixin中的生命周期函数会和组件的生命周期函数一起合并执行。
  • mixin中的data数据在组件中也可以使用。
  • mixin中的方法在组件内部可以直接调用。
  • 生命周期函数合并后执行顺序:先执行mixin中的,后执行组件的。

可参考:Mixin混入用法链接:https://juejin.cn/post/7076340796361801759

组件的注册

1、使用import 导入组件

2、使用vue全局注册

vue提供install可供我们开发新的插件及全局注册组件等

install方法第一个参数是vue的构造器,第二个参数是可选的选项对象

可参考:https://www.cnblogs.com/sam-zh/p/15352718.html

阶段面试题

阶段面试题

1. 请说下封装 vue 组件的过程

  • 首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性等问题。

  • 分析需求:确定业务需求,把页面中可以复用的结构,样式以及功能,单独抽离成一个组件,实现复用

  • 具体步骤:Vue.component 或者在new Vue配置项components中, 定义组件名, 可以在props中接受给组件传的参数和值,子组件修改好数据后,想把数据传递给父组件。可以采用$emit方法。

2. Vue组件如何进行传值的

  • 父向子 -> props定义变量 -> 父在使用组件用属性给props变量传值

  • 子向父 -> $emit触发父的事件 -> 父在使用组件用@自定义事件名=父的方法 (子把值带出来)

3. Vue 组件 data 为什么必须是函数

  • 每个组件都是 Vue 的实例, 为了独立作用域, 不让变量污染别人的变量

4. 讲一下组件的命名规范

  • 给组件命名有两种方式(在Vue.Component/components时),一种是使用链式命名"my-component",一种是使用大驼峰命名"MyComponent",

  • 因为要遵循W3C规范中的自定义组件名 (字母全小写且必须包含一个连字符),避免和当前以及未来的 HTML 元素相冲突

9、Vue组件进阶

动态组件

动态组件:在同一个挂载点, 可以切换显示不同组件

使用:vue内置的component组件, 配合is属性,改变is属性的值, 为要显示的组件名就可以切换组件

语法:<component :is="组件名"></component>

组件缓存

为什么需要组件缓存?

  • 频繁的切换会导致组件频繁创建和销毁,影响性能。

使用:Vue内置的keep-alive组件 包起来要频繁切换的组件。

语法:<keep-alive></keep-alive>

组件激活和非激活

组件缓存下 就会多两个钩子函数:

  • activated – 激活时触发
  • deactivated – 失去激活状态触发
<template>
  <div class="">
    <h2>动态组件 组件切换</h2>
    <button @click="name = 'denglu'">点击登录</button>
    <button @click="name = 'zhuce'">点击注册</button>
    <!-- 动态组件  修改 变量 name 的值,就可以达到切换组件的效果-->
    <component :is="name"></component>
 
    <h2>动态组件 组件缓存</h2>
    <button @click="name2 = 'denglu'">点击登录</button>
    <button @click="name2 = 'zhuce'">点击注册</button>
    <!-- 组件缓存    <keep-alive></keep-alive>  避免组件频繁创建和销毁 -->
    <keep-alive>
      <component :is="name2"></component>
    </keep-alive>
  </div>
</template>

<script>
// 导入组件
import denglu from "./denglu.vue";
import zhuce from "./zhuce.vue";
export default {
  data() {
    return {
      name: "denglu",
      name2: "denglu",
    };
  },
  // 注册组件
  components: {
    denglu,
    zhuce,
  },
  // 组件缓存下  多了两个钩子函数
  // activated   激活时触发
  activated() {
    console.log("注册标签激活了");
  },
  // deactivated   失去激活状态触发
  deactivated() {
    console.log("注册标签失去激活状态");
  },
};
</script>
<style scoped></style>

组件插槽
  1. 组件内用<slot></slot>占位
  2. 使用组件时<组件名></组件名>夹着的地方, 传入标签替换slot
  • 不给组件传标签. slot内容原地显示
  • 给组件内传标签, 则slot整体被换掉

具名插槽
  1. slot使用name属性区分名字
  2. template配合v-slot:名字来分发对应标签
  • v-slot:可以简化成#

作用域插槽

1. 子组件, 在slot上绑定属性和子组件内的值

2. 使用组件, 传入自定义标签, 用template和v-slot="自定义变量名"

3. “自定义变量名”变量名自动绑定slot上所有属性和值

  • ”自定义变量名“ = {值1,值2,...}

<template>
  <div class="">
    <pannel>
      <!-- template配合v-slot:name分发要替换的标签    v-slot: 可以简化成什么 # -->
      <template #title> 
        <h5>123</h5>
      </template>
      <template v-slot:content> 
        <p>12345</p>
        <p>12345</p>
      </template>
    </pannel>
    <pannel>
      
     // 用template和v-slot="自定义变量名" ,变量名自动绑定slot上所有属性和值
      <template v-slot:scope="title"> 
        <h5>{{scope.title}}</h5>
      </template>
      
       //template配合v-slot:name分发要替换的标签v-slot: 可以简化成什么
      <template #scope="title"> 
        <p>我是杨杰</p>
        <p>我就是杨杰</p>
      </template>
    </pannel>
  </div>
</template>

<script>
import pannel from "./pannel.vue";
export default {
  components: {
    pannel,
  },
};
</script>
<style scoped></style>

二、axios

Vue 的生命周期是什么?

  • 从 Vue 被创建到销毁的过程

生命周期函数(钩子)

  1. 初始化
  • beforeCreate 之前: 初始化 事件 和 生命周期函数
  • created 之前: 初始化 data 和 methods 在 created 钩子函数发起 ajax 请求
  1. 挂载
  • beforeMount 之前 编译 template
  • mounted 之前 挂载真实 DOM, 我们可以在 mounted 函数中获取真实 DOM,操作 DOM、
  1. 更新(数据发生变化)
  • beforeUpdate
  • updated: 获取更新后的真实 DOM
  1. 销毁
  • beforeDestroy: 移除全局占用的资源(全局事件、定时器、计时器、eventBus)
  • destroyed

Axios 网络请求

axios 是一个专门用于发送ajax请求的库,官网: axios中文网|axios API 中文文档 | axios

特点:

  • 支持客户端发送Ajax请求
  • 支持服务端Node.js发送请求
  • 支持Promise相关用法
  • 支持请求和响应的拦截器功能
  • 自动转换JSON数据
  • axios 底层还是原生js实现, 内部通过Promise封装的

axios如何请求数据

 axios({
  method: '请求方式', // get post
  url: '请求地址',
  data: {    // 拼接到请求体的参数,  post请求的参数
    xxx: xxx,
  },
  params: {  // 拼接到请求行的参数, get请求的参数
   	xxx: xxx 
  }
}).then(res => {
  console.log(res.data) // 后台返回的结果  axios函数调用原地结果,是一个Promise对象 
}).catch(err => {
  console.log(err) // 后台报错返回
})/* axios默认发给后台请求体数据格式是 json字符串格式 */

axios全局配置

可以在官网看到axios的很多默认配置: 起步 | Axios中文文档 | Axios中文网

axios如何配置基地址:axios.defaults.baseURLaxios.defaults.buseURL= "公共的url"

通过ref属性获取原生DOM

  1. 在标签上添加一个属性 ref="自定义的名字"
  2. 在 mounted 中,通过 this.$refs.自定义的名字 就可以得到真实 dom 元素了
  3. 可以通过ref 获取组件中的实例

通过ref属性获取组件对象

  1. 创建Demo组件, 写一个方法
  2. 目标组件添加ref属性

<子组件 res='自定义名字'></子组件>

  1. 恰当时机, 通过ref属性 获取组件对象, 可调用组件对象里方法等
<!--  目标组件添加ref属性 -->
    <Demo res='de'></Demo>


// 恰当时机, 通过ref属性 获取组件对象 this.$refs.名字 获取组件对象
mounted(){
  // this.$res.自定义名字.子组件的方法
  this.$res.de.fn()
}

$nextTick使用

vue检测到数据更新,开启一个DOM更新队列(异步任务)

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM

语法:

methods:{
  btn(){
    this.count++; // vue监测数据更新, 开启一个DOM更新队列(异步任务)
    console.log(this.$refs.myP.innerHTML); // 0

    // 原因: Vue更新DOM异步
    // 解决: this.$nextTick()
    // 过程: DOM更新完会挨个触发$nextTick里的函数体
    this.$nextTick(() => {
    console.log(this.$refs.myP.innerHTML); // 1
   })
  }
}

我们可以在哪里访问到更新后的DOM呢?

this.$nextTick里的函数体

updated生命周期钩子函数

阶段面试题

面试题

1、Vue 的 nextTick 的原理是什么? (高薪常问)

   \1. 为什么需要 nextTick ,Vue 是异步修改 DOM 的并且不鼓励开发者直接接触 DOM,但有时候业务需要必须对数据更改--刷新后的 DOM 做相应的处理,这时候就可以使用Vue.nextTick(callback)这个 api 了。

   \2. 理解原理前的准备 首先需要知道事件循环中宏任务和微任务这两个概念,常见的宏任务有 script, setTimeout, setInterval, setImmediate, I/O, UI rendering 常见的微任务有 process.nextTick(Nodejs),Promise.then(), MutationObserver;

   \3. 理解 nextTick 的原理正是 vue 通过异步队列控制 DOM 更新和 nextTick 回调函数先后执行的方式。如果大家看过这部分的源码,会发现其中做了很多 isNative()的判断,因为这里还存在兼容性优雅降级的问题。可见 Vue 开发团队的深思熟虑,对性能的良苦用心。

2、vue生命周期总共分为几个阶段?(必会)

Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。

1)beforeCreate

   在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。

2)created

   在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer), 属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。

3)beforeMount

   在挂载开始之前被调用:相关的 render 函数首次被调用。

4)mounted

   el 被新创建的 vm.

el 也在文档内。

5)beforeUpdate

   数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。

6)updated

   由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。

7)activated

   keep-alive 组件激活时调用。该钩子在服务器端渲染期间不被调用。

8)deactivated

   keep-alive 组件停用时调用。该钩子在服务器端渲染期间不被调用。

9)beforeDestroy

   实例销毁之前调用。在这一步,实例仍然完全可用。该钩子在服务器端渲染期间不被调用。

10)destroyed

   Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。

11)errorCaptured(2.5.0+ 新增)

   当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

三、vue-router 路由系统

Vue-Router简介

路由是什么呢? Vue中的路由是什么?

  • 路由是一种映射关系 Vue中的路由是路径和组件的映射关系

前端路由作用:

  • 实现业务场景切换

优点:

  • 整体不刷新页面,用户体验更好
  • 数据传递容易, 开发效率高

缺点:

  • 开发成本高(需要学习专门知识)
  • 首次加载会比较慢一点。不利于seo

单页面应用

  • 所有的业务都在一个页面编写, 只有一个html

vue-router本质是一个第三方包

  • 官网: Vue Router | Vue.js 的官方路由
  • vue-router模块包
  • 它和 Vue.js 深度集成
  • 可以定义 - 视图表(映射规则)
  • 模块化的
  • 提供2个内置全局组件
  • 声明式导航自动激活的 CSS class 的链接

路由系统使用步骤

下包/引入/注册/规则/路由对象/注入/挂载点

  • 下载vue-router模块到当前工程
  • 在main.js中引入VueRouter函数
  • 添加到Vue.use()身上 – 注册全局RouterLink和RouterView组件
  • 创建路由规则数组 – 路径和组件名对应关系
  • 用规则生成路由对象
  • 把路由对象注入到new Vue实例中
  • 用router-view作为挂载点, 切换不同的路由页面

方法2

创建路由项目

在命令行中输入以下命令创建 Vue 项目:

vue create toutiao-m

Vue CLI v4.2.3
? Please pick a preset:
  default (babel, eslint)
> Manually select features

default:默认勾选 babel、eslint,回车之后直接进入装包

manually:自定义勾选特性配置,选择完毕之后,才会进入装包

选择第 2 种:手动选择特性,支持更多自定义选项

? Please pick a preset: Manually select features
? Check the features needed for your project:
 (*) Babel
 ( ) TypeScript
 ( ) Progressive Web App (PWA) Support
 (*) Router
 (*) Vuex
 (*) CSS Pre-processors
>(*) Linter / Formatter
 ( ) Unit Testing
 ( ) E2E Testing

分别选择:
Babel:es6 转 es5
Router:路由
Vuex:数据容器,存储共享数据
CSS Pre-processors:CSS 预处理器,后面会提示你选择 less、sass、stylus 等
Linter / Formatter:代码格式校验

? Use history mode for router? (Requires proper server setup for index fallback in production) (Y/n) n

是否使用 history 路由模式,这里输入 n 不使用

? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default):
  Sass/SCSS (with dart-sass)
  Sass/SCSS (with node-sass)
> Less
  Stylus

选择 CSS 预处理器,这里选择我们熟悉的 Less

? Pick a linter / formatter config:
  ESLint with error prevention only
  ESLint + Airbnb config
> ESLint + Standard config
  ESLint + Prettier

选择校验工具,这里选择 ESLint + Standard config

? Pick additional lint features:
 (*) Lint on save
>(*) Lint and fix on commit

选择在什么时机下触发代码格式校验:

  • Lint on save:每当保存文件的时候
  • Lint and fix on commit:每当执行 git commit 提交的时候

这里建议两个都选上,更严谨。

? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
> In dedicated config files
  In package.json

Babel、ESLint 等工具会有一些额外的配置文件,这里的意思是问你将这些工具相关的配置文件写到哪里:

  • In dedicated config files:分别保存到单独的配置文件
  • In package.json:保存到 package.json 文件中

这里建议选择第 1 个,保存到单独的配置文件,这样方便我们做自定义配置。

? Save this as a preset for future projects? (y/N) N

这里里是问你是否需要将刚才选择的一系列配置保存起来,然后它可以帮你记住上面的一系列选择,以便下次直接重用。

这里根据自己需要输入 y 或者 n,我这里输入 n 不需要。

✨  Creating project in C:\Users\LPZ\Desktop\topline-m-fe89\topline-m-89.
�  Initializing git repository...
⚙  Installing CLI plugins. This might take a while...

[          ........] - extract:object-keys: sill extract json5@2.1.1

向导配置结束,开始装包。
安装包的时间可能较长,请耐心等待......

⚓  Running completion hooks...

�  Generating README.md...

�  Successfully created project topline-m-89.
�  Get started with the following commands:

 $ cd topline-m
 $ npm run serve

安装结束,命令提示你项目创建成功,按照命令行的提示在终端中分别输入:

# 进入你的项目目录
cd toutiao-webapp

# 启动开发服务
npm run serve

 DONE  Compiled successfully in 7527ms


  App running at:
  - Local:   http://localhost:8080/
  - Network: http://192.168.10.216:8080/

  Note that the development build is not optimized.
  To create a production build, run npm run build.

启动成功,命令行中输出项目的 http 访问地址。
打开浏览器,输入其中任何一个地址进行访问。

路由声明式导航

可用组件router-link来替代a标签

  • vue-router提供了一个全局组件 router-link
  • router-link实质上最终会渲染成a链接 to属性等价于提供 href属性(to无需#) ,必须传入to属性
  • router-link提供了声明式导航高亮的功能(自带类名)
 <div class="footer_wrap">
      <!-- <router-link> 是vue-router 提供的一个全局组件,最终会换染成 a 标签,属性 to 相当于 a 标签的 href    作用:提供了声明式导航高亮的功能(自带类名)-->
      <!-- 传参方法1:导航跳转, 传值给MyGoods.vue组件 以 (?参数名:值) 的形式
      接收:对应页面以 ($route.query.参数名) 的形式接收-->
      <router-link to="/find?name=张三">发现音乐</router-link>

      <!-- 传参方法2:路由定义  
        *在路由规则上以 (/:参数名) 的形式定义   
        *参数名  在<router-link>的属性to上以(/值)的形式定义值
      接收: ($route.params.参数名) 的形式接收
    -->
      <router-link to="/my/李四">我的音乐</router-link>
    </div>
    <div class="top">
<!--       挂载 router-link -->
      <router-view></router-view>
    </div>
  </div>

路由声明式导航 - 跳转传参

方法1:

  • path?参数名=值(传值) ==> $route.query.参数名 (接收)

方法2:

  • path/值 – 需要路由对象提前配置 path: “/path/参数名” (需在路由规则里配置/path/:参数名) (传值)==> $route.params.参数名 (接收)
<!-- 跳转并携带query参数,to的字符串写法 -->
<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">跳转</router-link>

路由编程式导航

目标: 编程式导航 - js方式跳转路由

语法:

this.$router.push({path: "路由路径"})

this.$router.push({name: "路由名"})

注意:

虽然用name跳转, 但是url的hash值还是切换path路径值

场景:

方便修改: name路由名(在页面上看不见随便定义)

path可以在url的hash值看到(尽量符合组内规范)

{
  path: "/find",
    name: "Find",
    component: Find
},
{
  path: "/my",
    name: "My",
    component: My
},
{
  path: "/part",
    name: "Part",
    component: Part
},
<template>
  <div>
    <div class="footer_wrap">
      <span @click="btn('/find', 'Find')">发现音乐</span>
      <span @click="btn('/my', 'My')">我的音乐</span>
      <span @click="btn('/part', 'Part')">朋友</span>
    </div>
    <div class="top">
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
// 目标: 编程式导航 - js方式跳转路由
// 语法:
// this.$router.push({path: "路由路径"})
// this.$router.push({name: "路由名"})
// 注意:
// 虽然用name跳转, 但是url的hash值还是切换path路径值
// 场景:
// 方便修改: name路由名(在页面上看不见随便定义)
// path可以在url的hash值看到(尽量符合组内规范)
export default {
  methods: {
    btn(targetPath, targetName){
      // 方式1: path跳转
      this.$router.push({
        // path: targetPath,
        name: targetName
      })
    }
  }
};
</script>

编程式导航 - 跳转传参

this.$router.push({
    path: "路由路径"
    name: "路由名",
    query: {
    	"参数名": 值
    }
    params: {  
		"参数名": 值
    }
})
// 使用path会忽略params 两者不能一起用   name两者都可以使用
//推荐 :name + query 传参
// 对应路由接收   $route.params.参数名   取值
// 对应路由接收   $route.query.参数名    取值
//注意: 如果当前url上"hash值和?参数"与你要跳转到的"hash值和?参数"一致, 爆出冗余导航的问题, 不会跳转路由

路由的重定向

匹配path后, 强制跳转path路径

  • 网页打开url默认hash值是/路径
  • redirect是设置要重定向到哪个路由路径
const routes = [
  {
   path:"/",  // 指定路径   / 代表默认路径
   redirect:"跳转地址", // 强制跳转
  },
  ...
]

路由 - 404

const routes = [
  ...
  {
   path:"*",  // 指定路径   * 代表默任意路径
   component:"跳转地址",
  }
]
// 路由最后, path匹配 * (任意路径) – 前面不匹配就命中最后这个

路由 模式

两种模式:

  • hash路由例如:  http://localhost:8080/#/home
  • history路由例如: http://localhost:8080/home  (以后上线需要服务器端支持, 否则找的是文件夹)
const router = new VueRouter({
  routes,
  mode: "history" // 打包上线后需要后台支持, 模式是hash
})

vue路由 - 嵌套

定义配置2级路由规则
   //一级路由path从/开始定义
   //二级路由往后path直接写名字, 无需/开头
   //嵌套路由在上级路由的children数组里编写路由信息对象  

注意:
//二级路由path一般不写根路径 '/'
//跳转时路径要从/开始写全

//router-link-exact-active  (精确匹配) url中hash值路径, 与href属性值完全相同, 设置此类名 (一般给二级路由)
//router-link-active        (模糊匹配) url中hash值,    包含href属性值这个路径  (一般给二级路由)
const routes = [
  // ...省略其他
  {
    path: "/find",
    name: "Find",
    component: Find,
    children: [
      {
        path: "recommend",
        component: Recommend
      },
    ]
  }
  // ...省略其他
]

vue路由 - 前置路由守卫

前置路由守卫:路由跳转之前, 先执行一次前置守卫函数, 判断是否可以正常跳转

目标: 前置路由守卫

场景: 当你要对路由权限判断时

语法: router.beforeEach((to, from, next)=>{//路由跳转"之前"先执行这里, 决定是否跳转})

  • 参数1: 要跳转到的路由 (路由对象信息) 目标
  • 参数2: 从哪里跳转的路由 (路由对象信息) 来源
  • 参数3: 函数体 - next()才会让路由正常的跳转切换,next(false)在原地停留, next("强制修改到另一个路由路径上")

注意: 如果不调用next, 页面留在原地

使用例子: 在跳转路由前, 判断用户登陆了才能去<我的音乐>页面, 未登录弹窗提示回到发现音乐页面

在路由对象上使用固定方法beforeEach

<!-- // 例子: 判断用户是否登录, 是否决定去"我的音乐"/my -->
const isLogin = true; // 登录状态(未登录)
router.beforeEach((to, from, next) => {
  if (to.path === "/my" && isLogin === false) {
    alert("请登录")
    next(false) // 阻止路由跳转
  } else {
    next() // 正常放行
  }
})

vant 组件库

Vant组件库: Vant 4 - A lightweight, customizable Vue UI library for mobile web apps.

特点

  • 提供 60 多个高质量组件,覆盖移动端各类场景
  • 性能极佳,组件平均体积不到 1kb
  • 完善的中英文文档和示例
  • 支持 Vue 2 & Vue 3
  • 支持按需引入和主题定制

递归算法案例

/** *
 *
 *  将列表型的数据转化成树形数据 => 递归算法 => 自身调用自身 => 一定条件不能一样, 否则就会死循环
 *  遍历树形 有一个重点 要先找一个头儿
 * ***/
export function tranListToTreeData(list, rootValue) {
  let arr = [];
  // 循环数组
  list.forEach((item) => {
    // 判断当前菜单item 是否是 rootValue 对应菜单 的子菜单
    if (item.pid === rootValue) {
      // 调用自身 再次循环数组list  传入当前菜单item 的id  判断当前菜单有没有子菜单
      // tranListToTreeData()返回arr  arr装的是满足 item.pid === rootValue 的对象,将值赋给children
      const children = tranListToTreeData(list, item.id);
      // 判断当前菜单item是否有子菜单 ,
      if (children.length >= 0) {
        // 如果有 就在当前item中添加children 属性,值等于 children
        item.children = children;
      }
      //将所有 一级菜单添加到 arr数组中  这里一级菜单包含了子菜单,不能卸载二层函数外,因为这里arr只装一级菜单
      arr.push(item);
    }
  });
  // 当地一层函数执行完 ,
  console.log(arr);
  return arr;
}

四、vuex

Vuex 的概述

  • Vuex 主要是为了解决跨组件组件通信问题的的一个官方状态(状态就是数据)管理插件
  • vuex 是采用集中式(所有的数据是放在一个文件中的)管理组件依赖的共享数据的一个工具,可以解决不同组件数据共享问题。

Vuex 核心概念

  1. state 存储共享状态数据的
  2. mutation 专门用来改变 state 中存储的数据的(存的是方法)
  3. action 专门用来发起异步操作的(存的也是方法)

Vuex 工作流程

  1. 把 state 中的数据 显示到组件中
  2. 如果没有异步操作,调用 mutations 中的方法去改变 state 中的数据
  3. 如果有异步操作,组件中先调用 actions 中的方法,由 actions 中的方法调用 mutations 中的方法,进而来改变 state 中的数据

Vuex 的初始化

  1. 下载 vuex
  2. 把 vuex 引入到 main.js
  3. 使用 Vue.use()方法把 vuex 挂载到 Vue 的组件实例 this.$store
  4. 实例化 store -> new Vuex.Store
  5. 把 Vuex 的 store 变量挂在 Vue 实例对象上

创建src/store/index.js该文件用于创建Vuex中最为核心的store

import Vue from 'vue'
import Vuex from 'vuex'	// 引入Vuex

Vue.use(Vuex)	// 应用Vuex插件

const actions = {}		// 准备actions——用于响应组件中的动作
const mutations = {}	// 准备mutations——用于操作数据(state)
const state = {}			// 准备state——用于存储数据

// 创建并暴露store
export default new Vuex.Store({
	actions,
	mutations,
	state,
})

在src/main.js中创建vm时传入store配置项

import Vue from 'vue'
import App from './App.vue'
import store from './store'	// 引入store

Vue.config.productionTip = false

new Vue({
	el: '#app',
	render: h => h(App),
	store,										// 配置项添加store
	beforeCreate() {
		Vue.prototype.$bus = this
	}
})

Vuex的基本使用

  1. 初始化数据state,配置actions、mutations,操作文件store.js
  2. 组件中读取vuex中的数据 $store.state.数据
  3. 组件中修改vuex中的数据 $store.commit('mutations中的方法名',数据)
  4. 组件中使用action 的异步操作 $store.dispatch('action中的方法名',数据)
  5. 若没有网络请求或其他业务逻辑,组件中也可越过actions,即不写dispatch,直接编写commit
  6. 组件中读取数据getters 的方法 $store.getters.方法名

vuex基础-state

state是放置所有公共状态的属性,如果你有一个公共状态数据 , 你只需要定义在 state对象中

定义state

// 初始化vuex对象
const store = new Vuex.Store({
  state: {
    // 管理数据
    count: 0
  }
})

原始形式- 插值表达式

组件中可以使用  this.$store 获取到vuex中的store对象实例,可通过state属性属性获取count, 如下

<div> state的数据:{{ $store.state.count }}</div>

计算属性 - 将state属性定义在计算属性中

// 把state中数据,定义在组件内的计算属性中
  computed: {
    count () {
      return this.$store.state.count
    }
  }
 <div> state的数据:{{ count }}</div>

辅助函数  - mapState

mapState是辅助函数,帮助我们把store中的数据映射到 组件的计算属性中, 它属于一种方便用法

用法 : 第一步:导入mapState

import { mapState } from 'vuex'

第二步:采用数组形式引入state属性

mapState(['count'])

第三步:利用延展运算符将导出的状态映射给计算属性

  computed: {
    ...mapState(['count'])
  }
 <div> state的数据:{{ count }}</div>

vuex基础-mutations

state数据的修改只能通过mutations,并且mutations必须是同步更新,目的是形成数据快照

数据快照:一次mutation的执行,立刻得到一种视图状态,因为是立刻,所以必须是同步

定义mutations

const store  = new Vuex.Store({
  state: {
    count: 0
  },
  // 定义mutations
  mutations: {

  }
})

格式说明

mutations是一个对象,对象中存放修改state的方法

mutations: {
    // 方法里参数 第一个参数是当前store的state属性
    // payload 载荷 运输参数 调用mutaiions的时候 可以传递参数 传递载荷
    addCount (state) {
      state.count += 1
    }
  },

如何在组件中调用mutations

原始形式-$store

新建组件child-a.vue,内容为一个button按钮,点击按钮调用mutations

<template>
  <button @click="addCount">+1</button>
</template>

<script>
export default {
    methods: {
    //   调用方法
      addCount () {
         // 调用store中的mutations 提交给muations
        // commit('muations名称', 2)
        this.$store.commit('addCount', 10)  // 直接调用mutations
    }
  }
}
</script>

带参数的传递

    addCount (state, payload) {
        state.count += payload
    }
    this.$store.commit('addCount', 10)

辅助函数 - mapMutations

mapMutations和mapState很像,它把位于mutations中的方法提取了出来,我们可以将它导入

import  { mapMutations } from 'vuex'
methods: {
    ...mapMutations(['addCount'])
}

上面代码的含义是将mutations的方法导入了methods中,等同于

methods: {
      // commit(方法名, 载荷参数)
      addCount () {
          this.$store.commit('addCount')
      }
 }

此时,就可以直接通过this.addCount调用了

<button @click="addCount(100)">+100</button>

但是请注意: Vuex中mutations中要求不能写异步代码,如果有异步的ajax请求,应该放置在actions中

vuex基础-actions

state是存放数据的,mutations是同步更新数据,actions则负责进行异步操作

定义actions

 actions: {
  // 获取异步的数据 
  // context 相当于精简版的 $store 
  // 可以通过 context.state 获取状态 
  // 也可以通过context.commit 来提交mutations, 
  // 也可以 context.diapatch调用其他的action
    getAsyncCount (context) {
      setTimeout(function(){
        // 一秒钟之后 要给一个数 去修改state
        context.commit('addCount', 123)
      }, 1000)
    }
 }

原始调用 - $store

 addAsyncCount () {
     this.$store.dispatch('getAsyncCount')
 }

传参调用

 addAsyncCount () {
     this.$store.dispatch('getAsyncCount', 123)
 }

辅助函数 -mapActions

actions也有辅助函数,可以将action导入到组件中

import { mapActions } from 'vuex'
methods: {
    ...mapActions(['getAsyncCount'])
}

直接通过 this.方法就可以调用

<button @click="getAsyncCount(111)">+异步</button>

vuex基础-getters

除了state之外,有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters

例如,state中定义了list,为1-10的数组,

state: {
    list: [1,2,3,4,5,6,7,8,9,10]
}

组件中,需要显示所有大于5的数据,正常的方式,是需要list在组件中进行再一步的处理,但是getters可以帮助我们实现它

定义getters

  getters: {
    // getters函数的第一个参数是 state
    // 必须要有返回值
     filterList:  state =>  state.list.filter(item => item > 5)
  }

使用getters

原始方式 -$store

<div>{{ $store.getters.filterList }}</div>

辅助函数 - mapGetters

computed: {
    ...mapGetters(['filterList'])
}
 <div>{{ filterList }}</div>

Vuex模块化中的命名空间

命名空间  namespaced

这里注意理解

高封闭性?可以理解成 一家人如果分家了,此时,你的爸妈可以随意的进出分给你的小家,你觉得自己没什么隐私了,我们可以给自己的房门加一道锁(命名空间 namespaced),你的父母再也不能进出你的小家了,如下

  user: {
       namespaced: true,
       state: {
         token: '12345'
       },
       mutations: {
        //  这里的state表示的是user的state
         updateToken (state) {
            state.token = 678910
         }
       }
    },

使用带命名空间的模块 action/mutations

Vuex命名空间调用方法

方案1:直接调用-带上模块的属性名路径

test () {
   this.$store.commit('user/updateToken') // 直接调用方法
}

方案2:辅助函数-带上模块的属性名路径

  methods: {
       ...mapMutations(['user/updateToken']),
       test () {
           this['user/updateToken']()
       }
   }
  <button @click="test">修改token</button>

方案3: createNamespacedHelpers  创建基于某个命名空间辅助函数

import { mapGetters, createNamespacedHelpers } from 'vuex'
const { mapMutations } = createNamespacedHelpers('user')
<button @click="updateToken">修改token2</button>

方案4: 辅助函数 第二种写法

  methods: {
       ...mapMutations('user',['updateToken'])   //辅助函数('组件名',['方法名'])
   }
  <button @click="test">修改token</button>
转载请注明出处或者链接地址:https://www.qianduange.cn//article/11589.html
标签
评论
发布的文章

JQuery中的load()、$

2024-05-10 08:05:15

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!