热门标签 | 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从入门到精通


推荐阅读
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • 深入理解Vue.js:从入门到精通
    本文详细介绍了Vue.js的基础知识、安装方法、核心概念及实战案例,帮助开发者全面掌握这一流行的前端框架。 ... [详细]
  • 云函数与数据库API实现增删查改的对比
    本文将深入探讨使用云函数和数据库API实现数据操作(增删查改)的不同方法,通过详细的代码示例帮助读者更好地理解和掌握这些技术。文章不仅提供代码实现,还解释了每种方法的特点和适用场景。 ... [详细]
  • JavaScript 中创建对象的多种方法
    本文详细介绍了 JavaScript 中创建对象的几种常见方式,包括对象字面量、构造函数和 Object.create 方法,并提供了示例代码和属性描述符的解释。 ... [详细]
  • Redux入门指南
    本文介绍Redux的基本概念和工作原理,帮助初学者理解如何使用Redux管理应用程序的状态。Redux是一个用于JavaScript应用的状态管理库,特别适用于React项目。 ... [详细]
  • 在尝试使用C# Windows Forms客户端通过SignalR连接到ASP.NET服务器时,遇到了内部服务器错误(500)。本文将详细探讨问题的原因及解决方案。 ... [详细]
  • 本文介绍了如何在多线程环境中实现异步任务的事务控制,确保任务执行的一致性和可靠性。通过使用计数器和异常标记字段,系统能够准确判断所有异步线程的执行结果,并根据结果决定是否回滚或提交事务。 ... [详细]
  • 12月16日JavaScript变量、函数、流程、循环等***线上九期班
    12月16日JavaScript变量、函数、流程、循环等***线上九期班 ... [详细]
  • HTML5 表单新增属性详解
    本文深入探讨了HTML5中表单的新增属性,帮助读者全面掌握这些新特性。内容涵盖autocomplete、autofocus、list等常用属性,并详细解释了form、novalidate、enctype和accept-charset等高级属性的功能与应用场景。 ... [详细]
  • 本文介绍如何从字符串中移除大写、小写、特殊、数字和非数字字符,并提供了多种编程语言的实现示例。 ... [详细]
  • 本文详细介绍如何使用 HTML5 和 JavaScript 实现一个交互式的画板功能。通过具体代码示例,帮助读者理解 Canvas API 的基本用法及其在绘图应用中的实际应用。 ... [详细]
  • 使用PHP实现网站访客计数器的完整指南
    本文详细介绍了如何利用PHP构建一个简易的网站访客统计系统。通过具体的代码示例和详细的解释,帮助开发者理解和实现这一功能,适用于初学者和有一定经验的开发人员。 ... [详细]
  • 本文探讨了为何相同的HTTP请求在两台不同操作系统(Windows与Ubuntu)的机器上会分别返回200 OK和429 Too Many Requests的状态码。我们将分析代码、环境差异及可能的影响因素。 ... [详细]
  • 本文详细介绍了一种通过MySQL弱口令漏洞在Windows操作系统上获取SYSTEM权限的方法。该方法涉及使用自定义UDF DLL文件来执行任意命令,从而实现对远程服务器的完全控制。 ... [详细]
  • 本文回顾了2017年的转型和2018年的收获,分享了几家知名互联网公司提供的工作机会及面试体验。 ... [详细]
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社区 版权所有