vue之组件

687 阅读5分钟

1. 组件化编程

1.1 组件

在 Vue 中,组件就是用来封装视图的,说白了就是封装 HTML;组件思想就是把一个很大的复杂的 Web 页面视图给拆分成一块一块的组件视图,然后利用某种特定的方式把它们组织到一起完成完整的 Web 应用构建

模块化是一种思想,一种构建方式,把一种很复杂的事务拆分成一个一个小模块,然后通过某种特定的方式把这些 小模块组织到一起相互协作完成这个复杂的功能

组件可以扩展HTML元素,封装可重用的代码。

在较高层面上,组件是自定义元素,Vue.js的编译器为它添加特殊功能。

在有些情况下,组件也可以变现为用 is 特性进行扩展原有的HTML元素

所有的Vue组件同时也都是Vue实例,所有可接受相同的选项的对象(除了一些根级特有的选项)并提供相同的生命周期钩子

1.2 组件的构成

组件主要包含三个部分:

  • template模板:html结构,只可以定义一个父元素
  • JS处理逻辑:主要作用是处理数据
  • style处理样式:如果不加 scoped,默认就是全局样式
<!-- template模板 -->
<template>
	<div class="title">
		<h1>{{ msg }}</h1>
	</div>
</template>

<!-- 逻辑处理 -->
<script>
export default {
    props: []/{},  // props参数:可以是数组或者对象
    // 自定义数据 
	data() {
		return {
			msg: 'hello vue.js'
		};
	},
    computed: {}, //计算属性
    methods: {},  //自定义方法              
    watch: {}, //监控
    filters: {}, // 过滤器
    directives: {}, // 自定义指令
    components: {}, //自定义组件
};
</script>

<!-- 样式处理 -->
<style lang="scss" scoped></style>

1.3 组件的定义和使用

1.3.1 全局组件

定义组件

<template>
  <div class="user">
    <h1>这是一个全局组件</h1>
  </div>
</template>

<script>
export default {}
</script>

<style lang="scss" scoped>
</style>

将组件注册为全局组件

一般是在main.js文件中 注册全局组件

// 1. 引入组件
import user from './components/user.vue'

// 2.  将组件注册为全局组件,名称为 my-user
Vue.component('my-user', user)

1.3.2 局部组件

定义组件

<template>
  <div class="helloWorld">
    <h1>这是一个局部组件</h1>
  </div>
</template>

<script>
export default {}
</script>

<style lang="scss" scoped>
</style>

使用组件

<template>
  <div class="test">
    <!-- 3. 使用组件 -->
    <user></user>
  </div>
</template>

<script>
// 1. 引入组件
import user from './user.vue'
export default {
  // 2.  注册声明组件
  components: {
    user,
  },
}
</script>

<style lang="scss" scoped>
</style>

2 组件插槽

插槽可以实现 父组件与子组件之间的通信

如果子组件中的插槽的name和父组件不一致,那么通过父组件传递过去的 标签数据 就不会显示

2.1 插槽的定义

<slot name="slot-name"></slot>

2.2 插槽的使用

<div slot='slot-name'></div>

案例:

子组件

<template>
  <div class="children">
    <slot name="userNameSlot"></slot>
    <div>子组件里面内容</div>
    <slot name="contSlot"></slot>
  </div>
</template>

父组件

<template>
  <div id="app">
    <children>
      <h1 slot="userNameSlot">插槽 userNameSlot 显示的内容</h1>
      <h1 slot="contSlot">插槽 contSlot 显示的内容</h1>
    </children>
  </div>
</template>

3 Prop

prop 是子组件用来接受父组件传递过来的数据的一个自定义属性

父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop"

prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来

组件可以为 props 指定验证要求:

Vue.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
      
    propA: Number,
      
    // 多个可能的类型
    propB: [String, Number],
      
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
      
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
      
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组默认值必须从一个工厂函数获取
      default: function () {
        return { message: 'hello' }
      }
    },
      
    // 自定义验证函数
    propF: {
      validator: function (value) {
        // 这个值必须匹配下列字符串中的一个
        return ['success', 'warning', 'danger'].indexOf(value) !== -1
      }
    }
  }
})

type 可以是下面原生构造器:

String Number Boolean Array Object Date Function Symbol

4 组件间的通信

组件间通信主要有5种方式:props、vue自定义事件、pubsub第三方库、slot插槽、vuex多组件共享状态

4.1 父组件向子组件通信

4.1.1 props

Prop是父组件用来传递数据的属性

父组件的数据需要通过props将数据传递给子组件,而子组件需要显式的用props声明prop

Prop是单向绑定的,当父组件的属性发生变化时,将传导给子组件,但是反过来不会

注意:不适合隔层组件和兄弟组件间的通信

1、 传递普通变量

eada7a4aacb74b6d93647cfd831e79dftplv-k3u1fbpfcp-zoom-1.png

image.png

2、 传递函数、方法

用法与传递普通变量一样

5f7cda31b3944020b9ad5da3b54d2499tplv-k3u1fbpfcp-zoom-1.png

4.2 子组件向父组件通信

4.2.1 自定义事件--推荐

一般是 子组件 触发自定义事件,将参数传递给父组件

this.$emit('事件名',参数)

父组件绑定监听事件,接收子组件传递过来的参数

@事件名=回调函数

49c487beaf3242c2a4b1921ae17f1c28tplv-k3u1fbpfcp-zoom-1.png

子组件:todoHeader触发事件

<script>
export default {
  methods: {
    add() {
      const { title } = this
      if (title.length > 0) {
        var todoItem = { title, complete: false }
        
        // 1. 使用 $emit('事件名',参数) 触发事件
        this.$emit('addtodoItemSub', todoItem)
          
        this.title = ''
      } else {
        alert('输入不可以为空!')
      }
    },
  },
}
</script>

父组件:绑定监听事件

<template>
  <div class="comtodolist">
    <!-- 1. 给todoHeader绑定addtodoItemSub事件监听;   addtodoItem1是一个回调函数-->
    <todoHeader @addtodoItemSub="addtodoItem1"></todoHeader>
  </div>
</template><script>
import todoHeader from '../components/component-todolist/todoHeader.vue'
export default {
  methods: {
    // 2.  添加 todoItem 父组件定义的回调函数
    addtodoItem1(todoItem) {
      this.todos.unshift(todoItem)
    },
  },
}
</script>

4.2.2 ref 结合 $on

使用$on(事件名,回调函数) 绑定监听

9f236f3f146b4a8296eccf3ed9651ceetplv-k3u1fbpfcp-zoom-1.png

子组件todoHeader:触发事件

<script>
export default {
  methods: {
    add() {
      const { title } = this
      if (title.length > 0) {
        var todoItem = { title, complete: false }
        // 1. 使用 $emit('事件名',参数) 触发事件
        this.$emit('addtodoItemSub', todoItem)
        this.title = ''
      } else {
        alert('输入不可以为空!')
      }
    },
  },
}
</script>

父组件:绑定监听事件 $on

<template>
  <div class="comtodolist">
    <!--  1.  给子组件设置 ref     -->
    <todoHeader ref="todoheaderref"></todoHeader>
  </div>
</template><script>
import todoHeader from '../components/component-todolist/todoHeader.vue'
export default {
  name: 'todolist',
  data() {
    return {
      // 从slocalStorage中读取todos
      todos: JSON.parse(window.localStorage.getItem('todos_key') || '[]'),
    }
  },
  components: {
    todoHeader,
  },
  mounted() {
    // 2.  绑定监听事件  this.$on('addtodoItemSub', this.addtodoItem);
    this.$refs.todoheaderref.$on('addtodoItemSub', this.addtodoItem)
  },
  methods: {
    // 添加
    addtodoItem(todoItem) {
      this.todos.unshift(todoItem)
    },
  },
}
</script>

4.3 pubsub:消息订阅与发布

可以实现任意组件之间的通信:父子组件传值或同胞兄弟之间的传值

# 安装
npm i pubsub-js
​
# 判断是否安装成功 
npm info pubsub-js
​

4.3.1 订阅消息(绑定事件监听): 定义函数或方法

// 语法
PubSub.subscribe('方法名',(msg,data)=>{} )
或者是下面的这种
PubSub.subscribe('事件名',function(msg,data){})  data就是参数
​
​
// 案例展示:订阅消息 searchInfo
// 注意:此处必须使用 箭头函数,才可以获取 this.searchInfo方法
PubSub.subscribe('searchInfo', (msg, searchName) => {
  this.searchInfo(searchName);
});
​
methods:{
    searchInfo(searchName){
        console.log(searchName);
    }
}
​

4.3.2 发布消息(触发事件):调用函数或方法

// 语法  
PubSub.publish('方法名',data)  
​
// 案例展示:发布消息 searchInfo
import PubSub from 'pubsub-js';
​
//发布消息:触发事件 searchNameText参数名
PubSub.publish('searchInfo', searchNameText);
​

c31bd124e3f24d478876df320a5bafa1tplv-k3u1fbpfcp-zoom-1.png

48b388550cd441e1a8fbcf17930c696dtplv-k3u1fbpfcp-zoom-1.png

ed0d728464d34cf58a18cb1e23fb1ec3tplv-k3u1fbpfcp-zoom-1.png

4.5 slot插槽

主要是父组件向子组件传递带数据的标签数据

注意: 标签是在父组件中解析

// slot插槽定义
<slot name="slotName">不确定的标签结构 1</slot>
​
// slot插槽使用
<div slot="slotName">slotName 对应的标签结构</div>
​

案例展示:

子组件 Child.vue

<template>
    <div>
        <slot name="xxx">不确定的标签结构 1</slot>
        <div>组件确定的标签结构</div>
        <slot name="yyy">不确定的标签结构 2</slot>
    </div>
</template>

父组件

<child>
    <div slot="xxx">xxx 对应的标签结构</div>
    <div slot="yyy">yyyy 对应的标签结构</div>
</child>

4.6 vuex

多组件共享状态(数据的管理

组件间的关系也没有限制

功能比pubsub强大, 更适用于vue项目