热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Vue的组件化

文章目录Vue的组件化一、认识组件化1.什么是组件化2.组件化思想二、注册组件1.组件的使用步骤三、组件其他补充1.全局组件和局部组件2.父组件和子组件3.组件的语法糖写法4.组件


文章目录

  • Vue的组件化
    • 一、认识组件化
      • 1. 什么是组件化
      • 2. 组件化思想
    • 二、注册组件
      • 1. 组件的使用步骤
    • 三、组件其他补充
      • 1. 全局组件和局部组件
      • 2. 父组件和子组件
      • 3. 组件的语法糖写法
      • 4. 组件模板抽离的写法
    • 四、组件数据存放
      • 1. 组件能访问vue中的数据吗
      • 2. 组件中的data为什么必须是函数
    • 五、父子组件通信
      • 1. 父传子props
      • 2. props的驼峰命名
      • 3. 子传父(自定义事件)
      • 4. 数据双向绑定案例
      • 5. 父访子-\$children-\$refs
      • 6. 子访父-\$parent-\$root
    • 六、插槽slot
      • 1. 为什么要使用插槽
      • 2. 插槽的封装和基本使用
      • 3. 具名插槽
      • 4. 作用域插槽


Vue的组件化


一、认识组件化


1. 什么是组件化


  • 如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展。
  • 但如果,我们将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了。

组件化概念


  • 我们将一个完整的页面分成很多个组件。
  • 每个组件都用于实现页面的一个功能块。
  • 而每一个组件又可以进行细分。

2. 组件化思想


  • 它提供了一种抽象,让我们可以开发出一个个独立可复用的小组件来构造我们的应用。
  • 任何的应用都会被抽象成一颗组件树。
  • 组件化思想的应用:
    • 有了组件化的思想,我们在之后的开发中就要充分的利用它。
    • 尽可能的将页面拆分成一个个小的、可复用的组件。
    • 这样让我们的代码更加方便组织和管理,并且扩展性也更强。

组件化思想


二、注册组件


1. 组件的使用步骤


  • 创建组件构造器
    • Vue.extends()
      • 调用Vue.extend()创建的是一个组件构造器
      • 通常在创建组件构造器时,传入template代表我们自定义组件的模板
      • 该模板就是在使用到组件的地方,要显示的HTML代码
      • 事实上,这种写法在Vue2.x的文档中几乎已经看不到了,它会直接使用下面我们会讲到的语法糖,但是在很多资料还是会提到这种方式,而且这种方式是学习后面方式的基础
  • 注册组件
    • Vue.component()
      • 调用Vue.component()是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名称
      • p所以需要传递两个参数:1、注册组件的标签名 2、组件构造器
  • 使用组件
    • 组件必须挂载在某个Vue实例下,否则它不会生效

<div id&#61;"app"><hello-vue>hello-vue><hello-vue>hello-vue><hello-vue>hello-vue><hello-vue>hello-vue>div><script src&#61;"../js/vue.js">script><script>const cpnC &#61; Vue.extend({template:&#96;

hello vue

&#96;})Vue.component(&#39;hello-vue&#39;,cpnC)const app &#61; new Vue({el: &#39;#app&#39;,data: {msg: &#39;hello vue!&#39;}})script>

三、组件其他补充


1. 全局组件和局部组件

上述方式是全局组件&#xff0c;可以在多个vue实例中使用。&#xff08;实际开发一般从头到尾就一个vue实例&#xff09;

局部组件注册&#xff1a;

const app &#61; new Vue({el: &#39;#app&#39;,data: {msg: &#39;hello vue!&#39;},components:{//cpn使用组件时的标签名cpn:cpnC}
})

2. 父组件和子组件

<div id&#61;"app"><cpn1>cpn1>div><script src&#61;"../js/vue.js">script><script>//子组件const cpnC2 &#61; Vue.extend({template: &#96;

hello vue2

&#96;})//父组件const cpnC1 &#61; Vue.extend({template: &#96;

hello vue

&#96;
,components:{cpn2:cpnC2}})const app &#61; new Vue({el: &#39;#app&#39;,data: {msg: &#39;hello vue!&#39;},components: {//cpn使用组件时的标签名cpn1: cpnC1}})script>

3. 组件的语法糖写法

省去extend

//全局组件
Vue.component(&#39;hello-vue&#39;,{template:&#96;

hello vue

&#96;
})
//局部组件
const app &#61; new Vue({el: &#39;#app&#39;,data: {msg: &#39;hello vue!&#39;},components:{//cpn使用组件时的标签名cpn:{template:&#96;

hello vue

&#96;
}}
})

4. 组件模板抽离的写法

标签中写&#xff0c;两种方式&#xff1a;


  • 中写
  • 标签中写

然后使用id选择器放到模板后面


四、组件数据存放


1. 组件能访问vue中的数据吗


  • 组件无法访问vue实例中的数据
  • 组件的数据存放在组件中的data里&#xff0c;数据为函数格式&#xff0c;返回一个值

2. 组件中的data为什么必须是函数

当我们封装好一个组件之后&#xff0c;在html使用组件实例&#xff0c;例如封装计数器组件&#xff0c;我们创建三个组件实例&#xff0c;每个组件实例都有数值的改变&#xff0c;如果组件中的data是对象或者数组形式&#xff0c;其中一个组件实例的数字改变&#xff0c;其他组件的数值也会跟着改变&#xff0c;因为组件在使用data中的数据时&#xff0c;三个组件的内存地址都会指向同一个data中的内存地址。而使用函数进行返回值&#xff0c;函数每次返回数据都会开辟一个新的内存地址&#xff0c;这就使得每一个组件指向的data中的数据都是不同的内存地址&#xff0c;这样其中一个计数器数值增加&#xff0c;其他计数器数值才不会跟着增加


五、父子组件通信


  • 在上一个小节中&#xff0c;我们提到了子组件是不能引用父组件或者Vue实例的数据的。
  • 但是&#xff0c;在开发中&#xff0c;往往一些数据确实需要从上层传递到下层&#xff1a;
    • 比如在一个页面中&#xff0c;我们从服务器请求到了很多的数据。
    • 其中一部分数据&#xff0c;并非是我们整个页面的大组件来展示的&#xff0c;而是需要下面的子组件进行展示。
    • 这个时候&#xff0c;并不会让子组件再次发送一个网络请求&#xff0c;而是直接让大组件(父组件)将数据传递给小组件(子组件)。

1. 父传子props

<body><div id&#61;"app"><cpn :cmovies&#61;"movies">cpn>div><script type&#61;"text/x-template" id&#61;"cpn"><ul><li v-for&#61;"item in cmovies">{{item}}</li></ul>script><script src&#61;"../js/vue.js">script><script>const cpn &#61; {template: &#39;#cpn&#39;,data() {return {}},props: [&#39;cmovies&#39;]}const app &#61; new Vue({el: &#39;#app&#39;,data: {msg: &#39;hello vue!&#39;,movies: [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]},components: {cpn}})script>

  • 在子组件中使用props属性给要传的数据命名
  • 在子组件模板中直接使用命名后的数据命
  • 在html中引用组件时使用v-bind绑定父组件的数据
  • props有两种写法&#xff1a;
    • 上面的数组写法&#xff0c;一般不用

    • 对象写法

      • 可以设置默认值
      • 可以进行数据类型验证
    • 对象写法可验证的数据类型

      • String
      • Number
      • Boolean
      • Array
      • Object
      • Date
      • Function
      • Symbol
      • 自定义类型
    • props: {//基础的类型检查&#xff08;null匹配任何类型&#xff09;propA: Number,//多个可能的类型propB: [String, Number],//必填的字符串propC: {type: String,required: true},// 带有默认值的数字prorD: {type: Number,default: 100},// 带有默认值的对象propE: {type: Object,// 对象或数组默认值必须从一个工厂函数获取default() {return {msg: &#39;hello&#39;}},},// 自定义验证函数propF: {validator(value) {// 这个值必须匹配下列字符串中的一个return [&#39;success&#39;, &#39;warning&#39;, &#39;danger&#39;].indexOf(value) !&#61;&#61; -1}}}


2. props的驼峰命名

在子组件中我们习惯使用驼峰命名&#xff0c;但是在html中绑定时&#xff0c;html无法识别驼峰命名&#xff0c;因此会报错&#xff0c;此时我们要么不使用驼峰命名&#xff0c;要么在html使用该名字时将驼峰命名改为用-连接&#xff0c;即cMovies---->c-movies


3. 子传父(自定义事件)

<div id&#61;"app"><cpn &#64;itemclick&#61;"nameclick">cpn>
div>
<template id&#61;"cpn"><div><button &#64;click&#61;"cnameClick(name)" v-for&#61;"name in names">{{name.name}}button>div>
template>
<script src&#61;"../js/vue.js">script>
<script>const cpn &#61; {template: &#39;#cpn&#39;,data() {return {names: [{id: 1, name: &#39;老子&#39;},{id: 2, name: &#39;孟子&#39;},{id: 3, name: &#39;孔子&#39;},{id: 4, name: &#39;荀子&#39;},]}},methods: {cnameClick(name){console.log(name,&#39;c&#39;)this.$emit(&#39;itemclick&#39;,name)},}}const app &#61; new Vue({el: &#39;#app&#39;,data: {msg: &#39;hello vue!&#39;},components: {cpn},methods: {nameclick(name){console.log(name)}}})
script>

  • 监听子组件中发生的事件

  • <template id&#61;"cpn"><div><button &#64;click&#61;"cnameClick(name)" v-for&#61;"name in names">{{name.name}}button>div>
    template>

  • 在子组件中写调用的方法

    • methods: {cnameClick(name){console.log(name,&#39;c&#39;)this.$emit(&#39;itemclick&#39;,name)},}

    • 并将该方法事件发送给父组件&#xff0c;参数为&#xff1a;自定义事件名&#xff0c;要传的参数

      • this.$emit(&#39;itemclick&#39;,name)
  • 在html中使用该组件&#xff0c;并使用自定义事件监听

    • <div id&#61;"app"><cpn &#64;itemclick&#61;"nameclick">cpn>
      div>

    • 调用的方法未写参数默认传发射过来的第一个参数

  • 在父组件中写自定义事件的回调方法

    • methods: {nameclick(name){console.log(name)}}

    • 方法带的参数与$emit发射的参数相同


4. 数据双向绑定案例

<body><div id&#61;"app"><cpn :number1&#61;"num1" :number2&#61;"num2" &#64;num1change&#61;"num1change" &#64;num2change&#61;"num2change">cpn>div><template id&#61;"cpn"><div>props:{{number1}}data:{{dnumber1}}<input type&#61;"text" :value&#61;"dnumber1" &#64;input&#61;"num1input">props:{{number2}}data:{{dnumber2}}<input type&#61;"text" :value&#61;"dnumber2" &#64;input&#61;"num2input">div>template><script src&#61;"../js/vue.js">script><script>const app &#61; new Vue({el: &#39;#app&#39;,data: {num1: 1,num2: 0},components: {cpn: {template: &#39;#cpn&#39;,props: {number1: Number,number2: Number,},data(){return {dnumber1 : this.number1,dnumber2 : this.number2,}},methods:{num1input(event){this.dnumber1 &#61; event.target.valuethis.$emit(&#39;num1change&#39;,this.dnumber1)this.dnumber2 &#61; this.dnumber1 * 100this.$emit(&#39;num2change&#39;,this.dnumber2)},num2input(event){this.dnumber2 &#61; event.target.valuethis.$emit(&#39;num2change&#39;,this.dnumber2)this.dnumber1 &#61; this.dnumber2 / 100this.$emit(&#39;num1change&#39;,this.dnumber1)}}}},methods: {num1change(num){this.num1 &#61; parseInt(num)},num2change(num){this.num2 &#61; parseInt(num)}}})script>
body>

需求&#xff1a; 子组件的输入框中显示父组件中定义的num1&#xff0c;num2&#xff0c;更改子组件输入框中的内容&#xff0c;父组件的num1&#xff0c;num2跟着改变

思路&#xff1a;


  1. 用父传子props把数据传给子组件&#xff0c;然后在输入框中使用v-model双向绑定父传过来的数据
    1. 不可行
    2. 因为官方规定&#xff0c;父组件传过来的数据只能有父组件更改&#xff0c;否则造成混乱&#xff0c;因此报错
  2. 用父传子props把数据传给子组件&#xff0c;子组件在data中将传过来的数据用另一个变量number1&#xff0c;number2保存&#xff0c;在子组件输入框中更改时&#xff0c;将数据保存到number1&#xff0c;number2中&#xff0c;然后使用自定义事件&#xff0c;将更改后的数据传入给父组件&#xff0c;父组件在自己内部将子组件传过来的数据给原来的num1,num2
    1. 可行
    2. 这种双向绑定的方法就是v-model的原理
    3. 完整代码在上方

5. 父访子-$children-$refs

当父组件要访问子组件中的方法或者属性时&#xff0c;可以使用以下两种方法


  • $children
    • 写法&#xff1a;this.$children
    • 作用&#xff1a;拿到所有子组件实例&#xff0c;返回一个数组
    • 由于不能固定拿到某个组件&#xff0c;使用很少
  • $refs
    • 写法&#xff1a;this.$refs.xxxx,在子组件实例中要加上ref&#61;"xxxx"属性
    • 作用&#xff1a;拿到对应名字的组件实例&#xff0c;返回一个对象
    • 使用多

6. 子访父-$parent-$root

使用很少&#xff0c;且不建议使用&#xff0c;耦合度高

写法与父访子类似&#xff0c;两个的区别&#xff0c;字面意思可看出


六、插槽slot


1. 为什么要使用插槽

生活中插槽目的是让我们原来的设备进行扩展性

vue中组件的插槽也是为了让封装的组件更加有扩展性&#xff0c;让使用者可以决定组件内部一些内容到底展示什么


2. 插槽的封装和基本使用

封装&#xff1a;


  • 在组件中定义一个标签即可
  • 标签中可以写上默认要放的东西

使用&#xff1a;


  • 在组件实例标签中写的所有内容会替换标签
  • 如果不写则显示默认内容

3. 具名插槽

上述方法只能将组件实例标签中的所有内容替换给所有的标签

假设我们定义了3个插槽&#xff0c;而我们只想替换中间那个插槽那我们就要给中间那个插槽命名

写法&#xff1a;


  • 插槽&#xff1a;
  • 组件实例标签&#xff1a;

4. 作用域插槽

一句话总结&#xff1a;父组件替换插槽的标签&#xff0c;但是内容由子组件来提供。

个人理解&#xff1a;子组件定义数据&#xff0c;父组件决定表现形式

需求&#xff1a;


  • 子组件中包括一组数据&#xff0c;比如&#xff1a;pLanguages: [‘Javascript’, ‘Python’, ‘Swift’, ‘Go’, ‘C&#43;&#43;’]
  • 需要在多个界面进行展示&#xff1a;
    • 某些界面是以水平方向一一展示的
    • 某些界面是以列表形式展示的
    • 某些界面直接展示一个数组
  • 内容在子组件&#xff0c;希望父组件告诉我们如何展示&#xff0c;怎么办呢&#xff1f;
    • 使用作用域插槽

写法&#xff1a;


  • 子组件插槽中定义一个名字并绑定一个数据&#xff0c;这里定义data绑定pLanguages

  • 在父组件中使用该插槽时&#xff0c;使用包裹需要使用的子组件的数据即可引用

    • <cpn><template slot-scope&#61;"slot">{{slot.data}}template>
      cpn>

表现形式

需求&#xff1a;


  • 子组件中包括一组数据&#xff0c;比如&#xff1a;pLanguages: [‘Javascript’, ‘Python’, ‘Swift’, ‘Go’, ‘C&#43;&#43;’]
  • 需要在多个界面进行展示&#xff1a;
    • 某些界面是以水平方向一一展示的
    • 某些界面是以列表形式展示的
    • 某些界面直接展示一个数组
  • 内容在子组件&#xff0c;希望父组件告诉我们如何展示&#xff0c;怎么办呢&#xff1f;
    • 使用作用域插槽

写法&#xff1a;


  • 子组件插槽中定义一个名字并绑定一个数据&#xff0c;这里定义data绑定pLanguages

  • 在父组件中使用该插槽时&#xff0c;使用包裹需要使用的子组件的数据即可引用

    • <cpn><template slot-scope&#61;"slot">{{slot.data}}template>
      cpn>

参考&#xff1a;vue从入门到精通


推荐阅读
  • 本文详细介绍了如何在 Node.js 环境中利用 Nodemailer 库实现邮件发送功能,包括环境配置、代码实现及常见问题解决方法。 ... [详细]
  • 使用Vue指令实现下拉菜单效果
    使用Vue指令实现下拉菜单效果模仿重庆红岩历史革命博物馆官网的导航栏内容和效果,使用Vue实现。官网地址如下:https:www.hongyan.info官网效果效果图片展示代码展 ... [详细]
  • 本文介绍了如何通过C#语言调用动态链接库(DLL)中的函数来实现IC卡的基本操作,包括初始化设备、设置密码模式、获取设备状态等,并详细展示了将TextBox中的数据写入IC卡的具体实现方法。 ... [详细]
  • 本文详细介绍了C++中的构造函数,包括其定义、特点以及如何通过构造函数进行对象的初始化。此外,还探讨了转换构造函数的概念及其在不同情境下的应用,以及如何避免不必要的隐式类型转换。 ... [详细]
  • 深入探讨:React中的方法绑定技巧与性能考量
    本文详细介绍了在React应用中绑定方法的三种常见方式及其对性能的影响,包括在JSX中使用箭头函数、在构造函数中绑定this以及将类方法定义为箭头函数的方法。 ... [详细]
  • 小编给大家分享一下Vue3中如何提高开发效率,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获, ... [详细]
  • 本文详细介绍了如何在 Vue CLI 3.0 和 2.0 中配置 proxy 来解决开发环境下的跨域问题,包括具体的配置项和使用场景。 ... [详细]
  • HTML:  将文件拖拽到此区域 ... [详细]
  • 嵌套列表的扁平化处理
    本文介绍了一种方法,用于遍历嵌套列表中的每个元素。如果元素是整数,则将其添加到结果数组中;如果元素是一个列表,则递归地遍历这个列表。此方法特别适用于处理复杂数据结构中的嵌套列表。 ... [详细]
  • 在使用 Nginx 作为服务器时,发现 Chrome 能正确从缓存中读取 CSS 和 JS 文件,而 Firefox 却无法有效利用缓存,导致加载速度显著变慢。 ... [详细]
  • 本文介绍了如何利用jQuery实现对网页上多个div元素的显示与隐藏控制,包括基本的toggle方法及更复杂的显示隐藏逻辑。 ... [详细]
  • 本文介绍了.hbs文件作为Ember.js项目中的视图层,类似于HTML文件的功能,并详细讲解了如何在Ember.js应用中集成Bootstrap框架及其相关组件的方法。 ... [详细]
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • 理解浏览器历史记录(2)hashchange、pushState
    阅读目录1.hashchange2.pushState本文也是一篇基础文章。继上文之后,本打算去研究pushState,偶然在一些信息中发现了锚点变 ... [详细]
  • 本文将从基础概念入手,详细探讨SpringMVC框架中DispatcherServlet如何通过HandlerMapping进行请求分发,以及其背后的源码实现细节。 ... [详细]
author-avatar
新洋之家140
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有