vue.js 核心知识点三

目录

- 3.1 vue中子组件调用父组件的方法

- 3.2 Vue父组件调用子组件的方法

- 3.3 涉及到组件之间的通信的问题

- 3.4 vue中 keep-alive 组件的作用

- 3.5 vue中编写可复用的组件

- 3.6 vue生命周期


- 3.1 vue中子组件调用父组件的方法

  • 第一种方法是 直接在子组件中通过this.$parent.event来调用父组件的方法

父组件

<template>
  <div>
    <child></child>
  </div>
</template>
<script>
  import child from '~/components/dam/child';
  export default {
    components: {
      child
    },
    methods: {
      fatherMethod() {
        console.log('测试');
      }
    }
  };
</script>

子组件

<template>
  <div>
    <button @click="childMethod()">点击</button>
  </div>
</template>
<script>
  export default {
    methods: {
      childMethod() {
        this.$parent.fatherMethod();
      }
    }
  };
</script>
  • 第二种方法是在子组件里用$emit向父组件触发一个事件,父组件监听这个事件就行了。

父组件

<template>
  <div>
    <child @fatherMethod="fatherMethod"></child>
  </div>
</template>
<script>
  import child from '~/components/dam/child';
  export default {
    components: {
      child
    },
    methods: {
      fatherMethod() {
        console.log('测试');
      }
    }
  };
</script>

子组件

<template>
  <div>
    <button @click="childMethod()">点击</button>
  </div>
</template>
<script>
  export default {
    methods: {
      childMethod() {
        this.$emit('fatherMethod');
      }
    }
  };
</script>
  • 第三种方法是父组件把方法传入子组件中,在子组件里直接调用这个方法

父组件

<template>
  <div>
    <child :fatherMethod="fatherMethod"></child>
  </div>
</template>
<script>
  import child from '~/components/dam/child';
  export default {
    components: {
      child
    },
    methods: {
      fatherMethod() {
        console.log('测试');
      }
    }
  };
</script>

子组件

<template>
  <div>
    <button @click="childMethod()">点击</button>
  </div>
</template>
<script>
  export default {
    props: {
      fatherMethod: {
        type: Function,
        default: null
      }
    },
    methods: {
      childMethod() {
        if (this.fatherMethod) {
          this.fatherMethod();
        }
      }
    }
  };
</script>

- 3.2 Vue父组件调用子组件的方法

  • vue中如果父组件想调用子组件的方法,可以在子组件中加上ref,然后通过this.$refs.ref.method调用,例如:

父组件:

<template>
  <div @click="fatherMethod">
    <child ref="child"></child>
  </div>
</template>
<script>
  import child from '~/components/dam/child.vue';
  export default {
    components: {
      child
    },
    methods: {
      fatherMethod() {this.$refs.child.childMethods();
      }
    }
  };
</script>

子组件:

<template>
  <div>{{name}}</div>
</template>
<script>
  export default {
    data() {
      return {
        name: '测试'
      };
    },
    methods: {
      childMethods() {
        console.log(this.name);
      }
    }
  };
</script>

在父组件中, this.$refs.child 返回的是一个vue实例,可以直接调用这个实例的方法

- 3.3 涉及到组件之间的通信的问题。组件之间的通信可以分为以下几种:

父子组件传递,父向子传递采用props,子向父采用事件emit
非父子组件的传递,全局Event bus,new一个vue的实例,采用事件的方式通信,再者采用vuex全局状态管理

- 3.4 vue中 keep-alive 组件的作用

在vue项目中,难免会有列表页面或者搜索结果列表页面,点击某个结果之后,返回回来时,如果不对结果页面进行缓存,那么返回列表页面的时候会回到初始状态,但是我们想要的结果是返回时这个页面还是之前搜索的结果列表,这时候就需要用到vue的keep-alive技术了.
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。

<keep-alive>
<component>
  <!-- 该组件将被缓存! -->
</component>
</keep-alive>

props

  • include - 字符串或正则表达,只有匹配的组件会被缓存
  • exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
// 组件 a
export default {
  name: 'a',
  data () {
    return {}
  }
}
<keep-alive include="a">
  <component>
    <!-- name 为 a 的组件将被缓存! -->
  </component>
</keep-alive>可以保留它的状态或避免重新渲染
<keep-alive exclude="a">
  <component>
    <!-- 除了 name 为 a 的组件都将被缓存! -->
  </component>
</keep-alive>可以保留它的状态或避免重新渲染


<keep-alive include="a,b">
  <!-- 将缓存name为a或者b的组件,结合动态组件使用 -->
  <component :is="view"></component>
</keep-alive>

<!-- 使用正则表达式,需使用v-bind -->
<keep-alive :include="/a|b/">
  <component :is="view"></component>
</keep-alive>

<!-- 动态判断 -->
<keep-alive :include="includedComponents">
  <router-view></router-view>
</keep-alive>

但实际项目中,需要配合vue-router共同使用.
router-view 也是一个组件,如果直接被包在 keep-alive 里面,所有路径匹配到的视图组件都会被缓存:

<keep-alive>
    <router-view>
        <!-- 所有路径匹配到的视图组件都会被缓存! -->
    </router-view>
</keep-alive>

如果只想 router-view 里面某个组件被缓存,怎么办?
增加 router.meta 属性

// routes 配置
export default [
  {
    path: '/',
    name: 'home',
    component: Home,
    meta: {
      keepAlive: true // 需要被缓存
    }
  }, {
    path: '/:id',
    name: 'edit',
    component: Edit,
    meta: {
      keepAlive: false // 不需要被缓存
    }
  }
]
<keep-alive>
    <router-view v-if="$route.meta.keepAlive">
        <!-- 这里是会被缓存的视图组件,比如 Home! -->
    </router-view>
</keep-alive>

<router-view v-if="!$route.meta.keepAlive">
    <!-- 这里是不被缓存的视图组件,比如 Edit! -->
</router-view>

【加盐】使用 router.meta 拓展
假设这里有 3 个路由: A、B、C。

需求:

首页是A页面
B页面跳转到A,A页面需要缓存
C页面跳转到A,A页面不需要被缓存

实现方式
思路是在每个路由的beforeRouteLeave(to, from, next)钩子中设置to.meta.keepAlive

在 A 路由里面设置 meta 属性:

{
        path: '/',
        name: 'A',
        component: A,
        meta: {
            keepAlive: true // 需要被缓存
        }
}

在 B 组件里面设置 beforeRouteLeave:

export default {
        data() {
            return {};
        },
        methods: {},
        beforeRouteLeave(to, from, next) {
             // 设置下一个路由的 meta
            to.meta.keepAlive = true;  // 让 A 缓存,即不刷新
            next();
        }
};

在 C 组件里面设置 beforeRouteLeave:

export default {
        data() {
            return {};
        },
        methods: {},
        beforeRouteLeave(to, from, next) {
            // 设置下一个路由的 meta
            to.meta.keepAlive = false; // 让 A 不缓存,即刷新
            next();
        }
};

这样便能实现 B 回到 A,A 不刷新;而 C 回到 A 则刷新。

keep-alive生命周期钩子函数:activated、deactivated
使用<keep-alive>会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在activated阶段获取数据,承担原来created钩子中获取数据的任务。

路由大法不错,不需要关心哪个页面跳转过来的,只要 router.go(-1) 就能回去,不需要额外参数。

实现前进刷新,后退不刷新参考 https://github.com/iceuncle/vue-navigation

- 3.5 vue中编写可复用的组件

组件,是一个具有一定功能,且不同组件间功能相对独立的模块。高内聚、低耦合。

开发可复用性的组件应遵循以下原则:

1.规范化命名:组件的命名应该跟业务无关,而是依据组件的功能命名。
2.数据扁平化:定义组件接口时,尽量不要将整个对象作为一个 prop 传进来。每个 prop 应该是一个简单类型的数据。这样做有下列几点好处:
(1) 组件接口清晰。(2) props 校验方便。(3) 当服务端返回的对象中的 key 名称与组件接口不一样时,不需要重新构造一个对象。
扁平化的 props 能让我们更直观地理解组件的接口。

<!-- 反例 -->
<card :item="{ title: item.name, description: item.desc, poster: item.img }></card>

<card
  :title="item.name"
  :description="item.desc"
  :poster="item.img">
</card>

3.可复用组件只实现 UI 相关的功能,即展示、交互、动画,如何获取数据跟它无关,因此不要在组件内部去获取数据。
4.可复用组件应尽量减少对外部条件的依赖,所有与 vuex 相关的操作都不应在可复用组件中出现。
5.组件在功能独立的前提下应该尽量简单,越简单的组件可复用性越强。
6.组件应具有一定的容错性。
7.组件应当避免对其父组件的依赖,不要通过 this.parent 来操作父组件的示例。父组件也不要通过 this.children 来引用子组件的示例,而是通过子组件的接口与之交互。
8.可复用组件除了定义一个清晰的公开接口外,还需要有命名空间。命名空间可以避免与浏览器保留标签和其他组件的冲突。特别是当项目引用外部 UI 组件或组件迁移到其他项目时,命名空间可以避免很多命名冲突的问题。

- 3.6 vue生命周期

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

2、vue生命周期的作用是什么?
答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。

3、vue生命周期总共有几个阶段?
答:它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后

  • 创建前/后

在beforeCreated阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。  在created阶段,vue实例的数据对象data有了,el还没有。

  • 载入前/后

在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。
  在mounted阶段,vue实例挂载完成,data.message成功渲染。

  • 更新前/后

当data变化时,会触发beforeUpdate和updated方法。

  • 销毁前/后

在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在

4、第一次页面加载会触发哪几个钩子?
答:第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子

5、DOM 渲染在 哪个周期中就已经完成?
答:DOM 渲染在 mounted 中就已经完成了。

6、简单描述每个周期具体适合哪些场景?
答:生命周期钩子的一些使用方法:
beforecreate : 可以在这加个loading事件,在加载实例时触发
created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
mounted : 挂载元素,获取到DOM节点
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 可以做一个确认停止事件的确认框
nextTick : 更新数据后立即操作dom


vue组件生命周期

生命周期推荐看http://web.jobbole.com/94470/

  1. created阶段的ajax请求与mounted请求的区别:前者页面视图未出现,如果请求信息过多,页面会长时间处于白屏状态

  2. mounted 不会承诺所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以用 vm.$nextTick

  3. vue2.0之后主动调用$destroy()不会移除dom节点,作者不推荐直接destroy这种做法,如果实在需要这样用可以在这个生命周期钩子中手动移除dom节点

单个组件的生命周期

  • 初始化组件时,仅执行了beforeCreate/Created/beforeMount/mounted四个钩子函数
  • 当改变data中定义的变量(响应式变量)时,会执行beforeUpdate/updated钩子函数
  • 当切换组件(当前组件未缓存)时,会执行beforeDestory/destroyed钩子函数
  • 初始化和销毁时的生命钩子函数均只会执行一次,beforeUpdate/updated可多次执行

父子组件的生命周期

  • 仅当子组件完成挂载后,父组件才会挂载
  • 当子组件完成挂载后,父组件会主动执行一次beforeUpdate/updated钩子函数(仅首次)
  • 父子组件在data变化中是分别监控的,但是在更新props中的数据是关联的(可实践)
  • 销毁父组件时,先将子组件销毁后才会销毁父组件

兄弟组件的生命周期

  • 组件的初始化(mounted之前)分开进行,挂载是从上到下依次进行
  • 当没有数据关联时,兄弟组件之间的更新和销毁是互不关联的

宏mixin的生命周期

-mixin中的生命周期与引入该组件的生命周期是仅仅关联的,且mixin的生命周期优先执行

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容