Vue组件

趁team leader的安排,在团队内部进行一次技术分享的机会。整理下这半年用的比较多的Vue.js内容,从开发使用层面上做一个简单的总结和入门,开两个专题:Vue组件和Vue Router。

1.工程搭建

打开pycharm后,file–>new–>project.按照下图一路next到底。
在这里插入的图片描述

2.组件总述

个人理解,Vue中的组件技术类似于后端开发中常用的一些工具类或方法,如果一个方法或功能在多个地方要用到,我们就需要将其进行抽离出来,在Vue中,组件就是一种很好的复用一个功能的手段。比如页面上的按钮、输入框等都可以以组件的形态存在,以供多个页面去复用使用。
下面,本文档将以组件的使用流程为主线进行简单的梳理和总结。

  • 创建组件 (第四部分)
  • 注册组件 (第三部分)
  • 调用组件 (穿插在第三四部分)

3.注册组件

创建组件放在后面讲,先看下注册组件。首先假设存在一个已经开发好的组件M(可能是个人开发的,也可能是别人开发的,亦可能是通过npm install安装的第三方库的组件),在我们的项目中如何去注册。
组件注册主要分**全局注册局部注册**。
全局组件通常使用 Vue.component(tagName, {options})的格式注册;
局部组件则在实例中的components中注册。
注意:
要确保在初始化根实例之前注册了组件,即:先注册组件,再初始化Vue实例;
建议将组件提取出来放在单独js文件中,按需引用。

4.创建组件

如果页面A上使用某个组件M,统一称呼的口径,全文约束调用方页面A为父组件,被调用方组件M称之为子组件。
组件使用和开发的核心就是父子组件的数据传递(通信)问题,按照数据传递方向可分为三类:

  • 父组件(调用方)与子组件(被调用方)的数据传递:props
  • 子组件向父组件传递数据:$emit()
  • 子组件与子组件(兄弟组件)数据传递:vuex

4.1 父–>子组件 props:

<template>
    <div>
      <p>我是子组件,父组件通过props传递过来的值是</p>
      {{postTitle}}
    </div>
</template>

<script>
export default {
  name: 'parent-child',
  // props: ['postTitle'],
  props: {
    'postTitle': String
  }
}
</script>

<style scoped>
</style>

注意:
1.子组件中的驼峰命名的 prop 名在父组件赋值的时候需要使用其等价的短横线分隔命名;
2.props如果不加类型校验则是一个数组;若加上类型校验则是一个对象。

4.2 子–>父组件 :$emit()
props里面的属性字段值是单向的,只能是父组件传递给子组件,如果在子组件对其进行修改父组件是无感知的。子组件如果想跟父组件进行反馈,通过在子组件利用emit()定义一个事件回调函数。

<template>
    <div>
      <button v-on:click="btnClickEvent">
        子组件的按钮
      </button>
    </div>
</template>

<script>
export default {
  name: 'child-parent',

  methods: {
    // 在子组件内部通过emit定义btn-click事件,在父组件中去监听btn-click事件并实现对其的响应
    btnClickEvent: function () {
      this.$emit('btn-click')
    }
  }
}
</script>

<style scoped>
</style>
------------------- 分割线: 以下是调用上面子组件的父组件 ---------------------
<!-- 子组件通过emit注册的事件回调父组件的事件响应函数 -->
<template>
  <div>
    <!-- 监听子组件预定义的btn-click事件 -->
    <child-parent @btn-click="callback_fn"></child-parent>
  </div>
</template>

<script>
import childParent from '@/components/child-parent'
export default {
  name: 'emit',
  methods: {
    callback_fn () {
      alert('父组件预定义的供子组件回调的函数 ==> (由子组件触发)')
    }
  },
  components: {
    childParent
  }
}
</script>

<style scoped>
</style>

小结:Props 向下传递数据,事件向上传递数据。

在标准组件和自定义组件上分别使用v-model
1.在标准组件上使用v-model

<!-- 在标准组件input上使用v-model实现变量的双向绑定 -->
<div id="app">
    <input :value="name" @input="name = $event.target.value" />
    <input v-model="name" />
</div>

上面示例代码中的两行input标签效果是一样的,在标准组件上使用v-model 节约了不少代码,最重要的是可以少定义一个事件处理函数,所以 v-model 实际干的事包括:

  • 使用 v-bind(即 :)单向绑定一个属性(示例::value=“name”)
  • 绑定 input 事件(即 @input)到一个事件处理函数(示例:@input=“name = $event.target.value”

2.在自定义组件上使用v-model
如同在标准组件上使用v-model一样,如果在自定义的子组件上利用v-model绑定某个值,就相当于子组件内部实现上的props里面有个value属性,同时还注册一个input事件,如下所示:

<custom-input
  v-bind:value="searchText"
  v-on:input="searchText = $event"
></custom-input>
Vue.component('custom-input', {
  props: ['value'],
  template: 
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
})

再看下面代码所示为父组件的一个例子,在该父组件中引用了子组件model-input,其中
<model-input :value="msg" @input="(res) => {this.msg = res}"></model-input>
这一行代码就说明在model-input子组件中必须得有一个接收value值的props和利用$emit注册一个input事件。

<!-- 父组件上使用v-model,子组件上使用model -->
<template>
  <div>
    <!-- 在input标签上时 v-model == value + input -->
    <model-input :value="msg"></model-input>
    <model-input :value="msg" @input="(res) => {this.msg = res}"></model-input>
    <model-input v-model="msg"></model-input>
    <span>父组件:{{msg}}</span>
    
    <!-- model选项可以指定当前的事件类型和传入的props, 因此可以解决v-model默认只能是value + input -->
    <model-conponent value="type1" :checked="checked"></model-conponent>
    <model-conponent value="type2" :checked="checked" @change="change"></model-conponent>
    <model-conponent value="type3" v-model="checked"></model-conponent>
    <p>父组件中的当前选中状态: {{this.checked}}</p>
  </div>
</template>
<script>
import modelConponent from '@/components/v-model'
import modelInput from '@/components/model-input'
export default {
  name: 'vModel',
  data () {
    return {
      msg: 'byteDance',
      checked: false
    }
  },
  methods: {
    change (value) {
      console.log('父组件事件回调响应函数 ==>', value)
      this.checked = value
    }
  },
  components: {
    modelConponent,
    modelInput
  }
}
</script>
---------------------------分割线,以下是子组件的代码----------------------------
<template>
    <div>
      <input ref="input" type="text" :value="value" @input="input"/>
    </div>
</template>

<script>
export default {
  name: 'modelInput',

  // 利用model强制修改默认input事件为input-fn事件
  // model: {
  //   prop: 'value',
  //   event: 'input-fn'
  // },
  props: {
    value: String
  },
  methods: {
    input () {
      console.log('子组件 == ', event.target.value)
      this.$emit('input', event.target.value)
    }
  }
}
</script>

可以在子组件中用model对v-model默认的value属性和input事件进行修改,上面示例代码中,子组件<model-conponent value="type1" :checked="checked"></model-conponent>就是利用model改变默认的value和input为checked和change。
子组件上使用model的示例

4.3 子组件与子组件(兄弟组件)数据传递:vuex
个人理解,把各组件间用到的共享数据,抽离出到一个全局共享变量中,交由vuex进行集中管理。
1.将vuex引入到当前工程:

  • 安装:npm install vuex --save
  • 定义Vuex对象:在src/store/store.js文件(若无则新建)中定义一个new Vuex.Store对象
  • 在src/main.js中的Vue实例中引入vuex store

2.引入到工程中后,在工程组件中使用的步骤,详见store.js
除了以上内容外,下面在总结下组件的两个高级特性:slot和动态组件

5.slot

slot(插槽)类似于props,也是父组件到子组件传递数据的一种方式,区别于props的子组件标签内属性数据传递,而slot是子组件标签之间的数据传递,可以传递像dom之类的template内容,也包括html和一些其他组件。
在这里插入图片描述上述截图所示,如果子组件slot-child内部没有<slot></slot>则父组件的

<span>我是从父组件传递到子组件的数据</span>

是无法展示的。以下是子组件代码:

<template>
    <div>
      子组件Slot-Child:
      <br/>
      <button @click="update"> {{btnName}} </button>
      <br/>
      <!-- 如果注释掉下面的slot标签,则无法接受父组件内容 -->
      <slot></slot>
    </div>
</template>

<script>
export default {
  name: 'slot-child',
  props: {
    btnName: String,
    default: '子组件按钮'
  },
  methods: {
    update () {
      this.$emit('update', '子组件回调函数的入参')
    }
  }
}
</script>

6.动态组件

动态组件:通过使用 <component> 标签,让多个组件可以使用同一个挂载点,并动态切换,<component :is="currentTabComponent" class="tab"></component>根据 v-bind:is=“组件名” 中的组件名去自动匹配组件,显示相应的组件内容。

附录

  1. 文章对应的项目源码

  2. 后续todo:
    1.localstorage
    2.vuex-persistedstate
    3.vue-codemirror
    4.函数内部函数的局部this

  3. 摘录
    初学者可能不知道的vue技巧
    Vue大杂烩

  4. Vue学习资料
    Webpack原理剖析:https://wx.kaikeba.com/presaledata/5?channel=0ebwxz
    vue-router前端路由原理剖析:https://wx.kaikeba.com/presaledata/4?channel=pwvrgj
    Vue源码解析:https://wx.kaikeba.com/presaledata/21?channel=fiqp7b
    react组件化:https://wx.kaikeba.com/presaledata/22?channel=kw2iey
    react原理剖析:https://wx.kaikeba.com/presaledata/23?channel=lfdb15
    Koa2源码解读:https://wx.kaikeba.com/presaledata/3?channel=p1ina4
    如何通过数据劫持实现vue框架:https://wx.kaikeba.com/presaledata/6?channel=3a2mxj
    Web全栈Vue资料:https://pan.baidu.com/s/1e4rQqDf3Pn7ZRD276bsTnQ
    提取码:cmws

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值