vue 的两个核心🌟🌟
组件系统、数据驱动
什么是双向数据绑定?🌟🌟🌟
v-model,数据发生变化,同步视图,视图发生变化,同步数据
什么是单向数据流?🌟🌟🌟
在父向子传值的时候,如果改变父组件的值,子组件会跟着同步更新,反之不允许
MVVM 的设计思想的优势?🌟🌟🌟
- 双向绑定技术,当 Model 变化时,View 也会自动变化,view 发生更新,model 也跟着同步
- 我们减少了 dom 的操作,因为我们只需要关注数据就可以
- mvvm 的设计思想大大提高了代码的耦合性
事件传参🌟🌟🌟🌟
- 没有传递参数,事件函数的默认第一个参数是事件对象
- 如果传递了参数,事件函数就没有了默认参数,全部变为对应位置的实参的形参,就没有了事件对象
- 既有自己传的的参数,也有事件对象,通过$event 传递事件对象,在事件函数内部通过对应位置的形参来接收事件对象,传递 $event 没有强制性的位置,但是建议放在最后
自定义指令:directive🌟🌟🌟
为什么自定义指令?
vue 提供的系统指令满足不了我们的需求,那么我们就需要自定义指令
通过 Vue.directive 进行自定义指令的定义
bind
:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted
:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。update
:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
计算属性:computed🌟🌟🌟🌟🌟
定义的时候是一个方法,使用的时候当作属性使用
只要 return 后面的数据发生变化,该计算属性就会重新计算
计算属性具有缓存特性
监听器:watch🌟🌟🌟🌟🌟
可以监听数据发生变化,可以监听的数据有(props、data、computed、$route) watch 侦听器如果监听的是一个对象,需要开启深度监听
watch:{ num:{ // 监听数据发生变化的处理函数 handler(newNum) { console.log(newNum) }, // 是否开启深度监听 deep: true } }
如果想实现首次监听配置 immediate 为 true
过滤器🌟🌟🌟🌟
可以对数据格式进行处理,例如常用的例如格式化时间 使用方式通过 数据名 |(管道符)后面跟过滤器的名字
生命周期函数🌟🌟🌟🌟🌟
生命周期:是指一个对象从创建到运行到销毁的整个过程,被称为生命周期
生命周函数:在不同的生命周期阶段会自动执行对应的函数,而这些函数则被成为生命周期函数
// 创建阶段 beforeCreate() { // 这个生命周函数,代表开始创建实例了 console.log('beforeCreate',this.num) }, created () { // 代表数据和方法已经初始化成功了,此处dom还没有挂载到页面上 console.log('created',this.num,this.$el) }, beforeMount () { // 挂在之前 console.log('beforeMount',this.$el) }, mounted () { // dom已经挂载了 console.log('mounted',this.$el) }, // 运行更新阶段 beforeUpdate () { // 数据更新,页面还没有同步 console.log('beforeUpdated',this.num,document.getElementById('app').innerHTML) }, updated () { // 数据更新,页面已经同步 console.log('updated',this.num,document.getElementById('app').innerHTML) }, // 销毁阶段 beforeDestroy () { // 销毁之前 console.log('beforeDestroy') }, destroyed () { // 已经销毁了 console.log('destroy') }
在 vue 中通过索引直接在修改数组中的某一项数据,页面是否更新?🌟🌟🌟
在 vue 中对 对象新添加属性,页面是否更新?
不更新,如果想解决这个问题,vm.$set(vm.list, 1, ‘or’)或者 Vue.set
但是 vm.list[3].a = 456,通过索引修改某一项的对象内部的属性是没问题的
vue 组件中的 data 为什么是一个函数,返回一个对象?🌟🌟
如果不是一个函数返回一个新的对象,组件如果多次使用,实际公用的是同一个数据
但是如果是通过函数 返回一个新的对象,这样的话,每个组件的使用数据是独立的
组件🌟🌟🌟🌟
如何创建一个全局组件🌟🌟🌟
通过 Vue.component 来创建一个全局组件,第一个参数是组件名字,第二个参数是组件的配置对象,可以通过 template 配置组件的结构,data 定义数据等等
如何创建一个局部组件🌟🌟🌟
在组件内部通过 components 来创建一个局部组件
全局组件和局部组件的区别
局部组件:只能在当前的父组件中使用
全局组件: 在任意地方使用
如何定义局部自定义指令🌟🌟🌟
在组件内部通过 directives 来创建一个局部指令
全局指令和局部指令的区别
局部指令:只能在当前的组件中使用
全局指令: 在任意地方使用
如何定义局部过滤器🌟🌟🌟
在组件内部通过 filters 来创建一个局部过滤器
全局过滤器和局部过滤器的区别
局部过滤器:只能在当前的组件中使用
全局过滤器: 在任意地方使用
组件传值🌟🌟🌟🌟🌟
Props
- 父亲怎么传:通过属性绑定形式传
- 儿子怎么接收:通过 props 来接收
Emit
- 子怎么传:通过 this.$emit 触发一个自定义事件,并且发送一个值
- 父怎么接收:通过定义自定义事件的事件函数的形参来接收
ref
- 通过添加 ref 和 $refs 配合, 也可以很方便的获取子组件, 访问调用子组件的属性或方法
// 父组件中 <template> <div class="hello_world"> <com-a ref="coma"></com-a> // this.$refs.coma.count = 200 <com-b ref="comb"></com-b> // this.$refs.comb.addFn() </div> </template>
$children
$parent
v-model
sync
兄弟组件传值🌟🌟🌟🌟
定义一个事件中心,或者是第三方
接收值的组件:通过该事件中心的$on 来定义自定义事件的事件函数来接收值
eventBus.$on('getTab1', data => { console.log('接收tab1传递的值', data) })
另一个兄弟组件怎么传:通过事件中心的$emit 触发对应的 $on 的事件,并且把值传递过去
eventBus.$emit('getTab1', this.num)
跨组件传值🌟🌟🌟🌟
Vue.component('my-sub1', { template: '#my-sub1', data() { return { money: 10000000 } }, provide: { money: 1000 }, components: { 'sub-a': { template: '<div>子组件<sub-b></sub-b></div>', components: { 'sub-b': { template: '<div>子组件{{money}}</div>', inject: ['money'] } } } } }) new Vue({ el: '#app' })
vuex
provide inject
- 成对出现:provide 和 inject 是成对出现的
- 作用:用于父组件向子孙组件传递数据
使用方法:
- provide 在父组件中, 返回要传给下级的数据
- inject 在需要使用这个数据的子孙组件中注入数据。(不论组件层次有多深)
组件插槽🌟🌟🌟🌟
- 默认插槽:
- 在组件标签中间可以传递一些子节点
- 组件内部利用 slot 标签进行接收
具名插槽
- 在组件标签中间通过定义 slot 的名字传递子节点
<my-banner> <div slot="header"> 头部 </div> <div slot="footer"> 底部 </div> </my-banner>
组件内部利用 slot 的 name 进行对应接收
<template id="banner"> <div> <slot name="header"></slot> <slot name="footer"></slot> </div> </template>
作用域插槽
- 在组件内部定义数据,将数据传递给插槽的结构
- 通过给 slot 动态绑定属性
<template id="my-li"> <ul> <li v-for="item in arr"> <slot :row="item"></slot> </li> </ul> </template>
插槽内部:通过 slot-scope=“scope”来接收
<my-li> <template slot-scope="scope"> <p>{{scope.row}}</p> </template> </my-li> <my-li> <template slot-scope="scope"> <a href="04-侦听器.html">{{scope.row}}</a> </template> </my-li>
插槽内部:通过 slot-scope=“scope”来接收
<my-li> <template slot-scope="scope"> <p>{{scope.row}}</p> </template> </my-li> <my-li> <template slot-scope="scope"> <a href="04-侦听器.html">{{scope.row}}</a> </template> </my-li>
Promise 的使用🌟🌟🌟🌟🌟
利用 Promise 处理异步解决回调地狱的问题
Promise 的 all 的方法
Promise 的 race 的方法
面试题:
现在有三个接口地址,需要三个接口地址请求完事之后进行下一步的逻辑处理(不一定按顺序请求完成)
// .then回调 axios.get('http://xxx').then(res => { console.log(res) axios.get('http://xxx').then(res => { console.log(res) axios.get('http://xxx').then(res => { console.log(res) }) }) }) // .then返回新的Promise继续调用.then axios .get('http://xxx') .then(res => { return axios.get('http://xxx') }) .then(res => { return axios.get('http://xxx') }) .then(res => { console.log('三个请求完事') }) // async await const asyncHandle = async function() { const res1 = await axios.get('http://xxx1') const res2 = await axios.get('http://xxx') const res3 = await axios.get('http://xxx') console.log(res1, res2, res3) } asyncHandle() // Promise all方法 const getComments = new Promise(() => { axios.get('http://xxx') }) Promise.all([ axios.get('http://xxx'), axios.get('http://xxx'), axios.get('http://xxx') ]).then(res => { console.log(res) })
axios 拦截器🌟🌟🌟🌟
请求拦截
axios.interceptors.request.use
响应拦截
axios.interceptors.response.use
路由🌟🌟🌟🌟
什么是路由?
路由就是对应关系,组件和 url 地址,根据不同的地址显示不同的组件,路由也是实现 spa(单页面应用程序)的主要核心,因为单页面应用程序,就是只有一个 html,在这个 html 里面切换组件,根据 url,例如地址为/home,在这个页面中就显示 home 组件
前端路由:url 和组件
后端路由:根据不同的地址请求不同的接口
在 vue 中路由传参
- params 传参
- 在跳转的时候可以通过/home/10
- 路由规则:
new VueRouter({ routes: [ { path: '/home/:id', component: Home } ] })
组件内部怎么来接收参数
this.$route.params.id
query 传参
- 在跳转的时候可以通过/home?id=10
- 组件内部怎么来接收参数
this.$route.query.id
路由 history 模式注意的问题
嵌套路由🌟🌟🌟
编程式导航🌟🌟🌟
路由钩子🌟🌟🌟🌟
全局钩子:都会对所有的路由进行拦截
beforeEach:进入之前
afterEach:已经进入了
路由独享钩子:可以针对某一个路由进行拦截,这个需要写在路由规则里
{ path: '/', name: 'home', beforeEnter: (to,from,next)=>{ console.log('即将进入home') }, component: Home }
组件内的守卫:
针对组件进行拦截
beforeRouteEnter (to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 next() }, beforeRouteUpdate (to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 // 可以访问组件实例 `this` }, beforeRouteLeave (to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` console.log('即将离开about') if(confirm('当前表单没有提交?确定要离开首页?')){ next() } }
webpack 中 babel.loader.plugin 有什么区别?🌟🌟🌟
babel: 将高级语法转换成浏览器可以识别的语法
loader: 加载器, 结合 webpack 来处理非 js 资源文件 .css .less .sass .png
plugin: webpack 的各种各样的插件,能够增强 webpack 的功能
vue 脚手架的安装和使用🌟🌟
命令行方式
利用 vue.config.js 关闭 esLint
ui 界面方式
安装 element-ui
- 安装 vue-cli-plugin-element 插件
使用 element 中 select 组件
- 注册组件
import Vue from 'vue' import { Button, Select } from 'element-ui' Vue.use(Button) Vue.use(Select)
使用组件
<el-select v-model="value" placeholder="请选择"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" ></el-option> </el-select>
复制数据
options: [{ value: '选项1', label: '黄金糕' }, { value: '选项2', label: '双皮奶' }, { value: '选项3', label: '蚵仔煎' }, { value: '选项4', label: '龙须面' }, { value: '选项5', label: '北京烤鸭' }], value: ''