[TOC]

(一) 父组件修改字组件数据

  1. 父组件使用子组件的时候, 给子组件添加ref属性
  2. 父组件就可以使用 this.$refs[‘xxx’] 获取到子组件的实例, 从而去修改子组件的数据

    (二) 子组件修改父组件数据

    方式二:
    跟普通父子组信一样, 不过父组件传给子组件的对象, 子组件修改这个对象的属性也可以实现子组件修改父组件数据的目的.

方式二:
父组件使用 :msg.sync=”msg”
子组件使用 $emit(‘update:msg’, ‘新数据’)

// 父组件 Demo.vue

<template>
  <div>
    <h3>父组件</h3>
    <p>{{msg}}</p>
    <hr>
    <h5>子组件</h5>
    <Son :msg.sync="msg"></Son>
  </div>
</template>

<script>
import Son from './Son.vue'
export default {
  components: {
    Son
  },
  data() {
    return {
      msg: 'hello'
    }
  }
}
</script>


// 子组件 Son.vue
<template>
  <div>
      <input type="text" :value="msg" @input="onInput">
  </div>
</template>

<script>
export default {
    props: ['msg'],
    methods: {
        onInput() {
            this.$emit('update:msg', event.target.value);
        }
    }
}
</script>

(三) 父子组件双向数据绑定

即父组件可以对子组件使用v-model

// 父组件Demo.vue

<template>
  <div>
    <h3>父组件</h3>
    <p>{{msg}}</p>
    <hr>
    <h5>子组件</h5>
     <!-- 对子组件使用v-model指令 -->
    <Son v-model="msg"></Son>
  </div>
</template>

<script>
import Son from './Son.vue'
export default {
  components: {
    Son
  },
  data() {
    return {
      msg: 'hello'
    }
  }
}
</script>


// 子组件 Son.vue
<template>
  <div>
      <input type="text" :value="msg" @input="onInput">
  </div>
</template>

<script>
export default {
    props: ['msg'],
    model: {
        // 指定对哪个属性进行使用v-model
        prop: 'msg',
        // 指定子组件$emit的事件名称
        event: 'myevent'
    },

    methods: {
        onInput() {
            // $emit指定的事件名称
            this.$emit('myevent', event.target.value);
        }
    }
}
</script>

(四) 路由守卫

和axios拦截器,koa中间件都有些相似的地方

  1. to 即将要进入的目标 路由对象
  2. from 当前导航正要离开的路由
  3. next 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
    • next() 直接进入进行管道中的下一个钩子
    • next({ path: ‘/xxx’ }) 跳转到/xxx 路由
// 路由白名单(不需要检查就可以直接通过进行下一步的路由)
const whitList = ['/login'];
router.beforeEach((to, from, next) => {

    // 已登录,如果目标路由是/login则跳转到首页, 否则放行
    if (store.state.user.token) {
        if (to.path === '/login') {
            next('/home');
        } else {
            next();
        }
    } else {
        // 未登录
        if (whitList.includes(to.path)) {
            // 白名单内的路由直接放行,非白名单的跳转到登录页
            next();
        } else {
            next('/login');
        }

    }
})

(五) 用户权限控制

用户权限控制的思路是:

  1. 前端一开始的路由只配置了一些基本的路由
  2. 用户登录之后, 后台会给前端返回一个角色字段, 表明用户的身份
  3. 前端就根据用户的身份配置不同的路由(有的公司由后台返回)
  4. 使用router.addRoutes方法添加权限路由。
  5. 在后台管理系统的侧边栏一般根据路由数组动态渲染,这样不同角色能看到的列表就不一样。 ```javascript // 基础路由,不需要权限就可以访问的路由 const baseRoutes = [{ path: ‘/login’, name: ‘login’, component: () => import(‘@/views/login/index.vue’) }]

// 创建路由 const router = new Router({ mode: ‘history’, routes: baseRoutes });

export const adminRoutes = [{…},{…},{…}]; export const superRoutes = […adminRoute,{…},{…}];

// 登录成功根据不同角色添加不同的路由 axios.post(‘/user/login’,userInfo).then(res => {
if (res.result.role == 1) { // 动态添加超级管理员权限路由 router.addRoutes(superRoutes); } else if (res.result.role == 2){ // 动态添加管理员权限路由 router.addRoutes(adminRoutes); } })

// 动态渲染侧边栏, 以下是侧边栏核心代码

``` ## (六) 自定义vue指令 ##### 01 一个简单的vue指令(是字体变红色) ```javascript ``` vue指令的三个构造函数: - `bind`:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。 - `inserted`:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。 - `update`:所在组件的 VNode 更新时调用 ##### 02 动态指令参数 ```javascript ``` ```javascript // 只有管理员或者超级管理员才可以编辑 ``` ## (七) axios 拦截器 1. request 发送请求拦截处理, 在请求数据之前做一些处理,比如发起一个 loading,添加请求头等 1. response 返回数据拦截处理, 数据返回之后做一些处理,比如成功之后只把 data 里的数据返回,方便后续数据的处理 ```javascript //1.引入 axios import axios from 'axios'; //引入提示信息 import { Message } from 'element-ui'; import store from '@/store/index'; //2.创建axios 实例 const service = axios.create({ //3.配置baseURL baseURL: process.env.VUE_APP_URL, timeout: 10 * 60 * 1000 //10分钟 }) //4. 请求拦截 service.interceptors.request.use( (config) => { //配置 请求拦截中的token,是添加Authorization还是添加user-token取决于后台的设置 // config.headers['user-token'] = store.state.user.token; config.headers.Authorization = store.state.user.token; return config; }, (err) => { return Promise.reject(err); } ) //5.响应拦截 service.interceptors.response.use( (res) => { const data = res.data; if (data.code != 666) { Message({ message: data.msg, type: "error" }) } return data; }, (err) => { return Promise.reject(err); } ) const get = (url,data={})=> { return service.get(url,{params: data}); } const post = (url,data={})=> { return service.post(url,data); } //6.导出 export default { get,post }; ``` ## (八) nextTick 在vue中, 修改了数据, dom是异步更新的, 所以当修改了数据, 立即去获取dom节点, 你获取到的并不是更新后的dom, 如果你想获取更新后的dom, 可以使用nextTick, 这个函数是在dom更新后立刻执行 ```javascript ``` ## (九) vue中央事件总线机制(bus) 1. vue中非父子组件之间通信除了使用vuex,也可以通过bus总线,两者适用场景不同。 1. vuex适用中大型项目、数据在多组件之间公用的情况。 1. bus适合小项目、数据被更少组件使用的项目,对于中大型项目 数据在很多组件之间使用的情况 bus就不太适用了。**bus其实就是一个发布订阅模式**,利用vue的自定义事件机制,在触发的地方**通过$emit向外发布一个事件**,在需要监听的页面,**通过$on监听事件(订阅)**。 **概念**: 发布订阅模式, 就好像以前一个家庭跟一个报社订报纸, 报社是发布者, 有了新的报纸就派人去送报纸, 家庭是订阅者, 订了的家庭就能收到新报纸, 一个发布者可以对应多个订阅者 ```javascript // main.js 导入事件中线插件 import VueBus from 'vue-bus'; Vue.use(VueBus); // index.vue

// C1.vue

// C2.vue

``` ## (十) provide和inject 祖宗和后代通信 1. 祖宗使用provide定义数据 1. 后代(任何层级)都可以使用inject获取数据 ```javascript // 祖宗组件, App.vue

// 后代组件

``` ## (十一) DOM和虚拟DOM的区别 1. DOM 的本质:
DOM 是浏览器概念,浏览器从服务器端读取 html 页面,浏览器将 html 解析成一棵元素嵌套关系的 dom 树,用对象来表示页面上的元素,并提供操作 dom 对象的 api。 2. **虚拟 DOM:** 程序员用 js 对象来模拟页面上 dom 元素的嵌套关系( 本质 ),为了实现页面元素的高效更新( 目的 ) 3. 虚拟 DOM 是真实 DOM 结构的映射,即一个数据集合 3. 虚拟DOM的核心就是一个diff算法:使用一个render()方法就可以将vNodes(虚拟dom节点)还原成真实的Html页面 ```html // 对于这个Html 文件

Hello, the world! Hello, the code!

// 它对应的虚拟DOM就是
<a name="L90hF"></a>
## (十二) vue双向数据绑定原理
**原理: **<br />vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。<br />具体步骤:<br />**第一步:**需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter 这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化

**第二步:**compile 解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图

**第三步:**Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁,主要做的事情是:<br />在自身实例化时往属性订阅器(dep)里面添加自己 自身必须有一个 update()方法 待属性变动 dep.notice()通知时,能调用自身的 update() 方法,并触发 Compile 中绑定的回调,则功成身退。 第四步:MVVM 作为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,通过 Observer 来监听自己的 model 数据变化,通过 Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和 Compile 之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据 model 变更的双向绑定效果。
```typescript
<script>
    var obj = {};
    var temp = null;
    Object.defineProperty(obj, "username", {
        set: function (newValue) {
            console.log('给属性赋值,触发set函数')
            temp = newValue;
        },
        get: function () { 
            console.log('读取属性,触发get函数');
            return temp;
        }
    })

    obj.username = '张三';
   let username = obj.username; 
</script>

(十三) keep-alive

  1. 用户在某个列表页面选择筛选条件过滤出一份数据列表,由列表页面进入数据详情页面,再返回该列表页面,我们希望:列表页面可以保留用户的筛选(或选中)状态。
  2. keep-alive就是用来解决这种场景。当然keep-alive不仅仅是能够保存页面/组件的状态这么简单,它还可以避免组件反复创建和渲染,有效提升系统性能。总的来说,keep-alive用于保存组件的渲染状态。
  3. keep-alive的生命周期
    1. 初次进入时:created > mounted > activated;退出后触发 deactivated
    2. 再次进入:会触发 activated;事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在 activated 中
  4. 应用实例 ```javascript //1.router.js在需要缓存的路由组件添加keepAlive meta: { title: ‘demo’, keepAlive: true },

//2.路由出口配置

//3.添加列表组件和详情组件 // 列表组件

//详情组件

注意: 要把keep-alive放在父路由上, 不然不生效javascript // 列表进详情, 返回时滚动条回原来位置

<a name="aVPTI"></a>
## <br />
<a name="4QRPd"></a>
## (十四) 数字动画
[https://cn.vuejs.org/v2/guide/transitioning-state.html](https://cn.vuejs.org/v2/guide/transitioning-state.html)
```javascript
<template>
  <p>{{ num }}</p>
</template>

<script>
import gsap from "gsap";
export default {
  data() {
    return {
      number: 0,
    };
  },

  computed:{
    // 不显示小数点
    num() {
      return this.number.toFixed(0);
    }
  },

  created() {
    setTimeout(() => {
      let newVal = 1000;
      gsap.to(this.$data, { duration: 0.5, number: newVal });
    }, 2000);
  },
};
</script>