深入理解 Vue 组件


组件使用中的细节点

使用 is 属性,解决组件使用中的bug问题

 <!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>组件使用中的细节点</title>
<script src="./vue.js"></script>
</head> <body>
<div id="root">
<table>
<tbody>
<!-- H5编码规范要求,tbody内必须是tr,因此row组件不能用,会产生bug,
因此 is 关键字起到了很好的作用,将此时的 tr 标签等于我们创建的 row 子组件。
完美解决了既要使用组件永不会影响H5编码规范的问题
不仅仅是table标签,ul ol select 标签都有相同的问题。-->
<tr is="row"></tr>
<tr is="row"></tr>
<tr is="row"></tr>

</tbody>
</table>
</div> <script>
// 创建全局子组件
Vue.component('row',{
template:"<tr><td>this is a row</td></tr>"
}) var vm = new Vue({
el:"#root", })
</script>
</body> </html>

  

子组件定义data数据,data必须是个函数

 <!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="./vue.js"></script>
</head> <body>
<div id="root">
<table>
<tbody>
<tr is="row"></tr>
<tr is="row"></tr>
<tr is="row"></tr>
</tbody>
</table>
</div>
<script>
// 子组件
Vue.component("row", {
// 子组件定义数据data的方法必须是一个函数返回,不能像根对象一样
data: function () {
return {
content: 'this is a row'
}
},
template: '<tr><td>{{content}}</td></tr>'
}) var vm = new Vue({
el: "#root",
})
</script>
</body> </html>

  

Vue中的 ref 引用的内容

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>ref</title>
<script src="./vue.js"></script>
</head> <body>
<div id="root">
<!-- 在vue当中,可以通过ref获取dom节点 -->
<div ref='hello' @click="handleClick">hello world</div>

</div>
<script> var vm = new Vue({
el: "#root",
methods: {
handleClick: function () {
// 获取dom中的内容
// this.$refs.hello 获取ref=hello的dom节点
alert(this
.$refs.hello.innerHTML)
}

}
})
</script>
</body> </html>

  

vue实现计数器功能

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>计数器功能</title>
<script src="./vue.js"></script>
</head> <body>
<div id="root">
<counter ref='one' @change="handleChange"></counter>
<counter ref='two' @change="handleChange"></counter>
<!-- 求和 -->
<div>{{total}}</div>
</div>
<script>
    // 子组件
Vue.component('counter', {
template: '<div @click="handleClick">{{number}}</div>',
data: function () {
return {
number: 0
}
},
methods: {
handleClick: function () {
this.number++
// 向外发送change事件
this.$emit('change')
}
}
}) var vm = new Vue({
el: "#root",
data: {
total: 0
},
methods: {
handleChange: function () {
this.total = this.$refs.one.number + this.$refs.two.number
// console.log(this.$refs.one.number)
// console.log(this.$refs.two.number)
}
}
})
</script>
</body> </html>

  

父子组件间传值

父组件向子组件传递数据

  1. 父组件通过属性的形式向子组件传递数据。
  2. 父组件可以随意的向子组件传递参数。
  3. 但是子组件绝对不能去修改父组件传进来的参数(单向数据流)。
 <!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>父子间组件传值</title>
<script src="./vue.js"></script>
</head> <body>
<div id="root">
<!-- 父组件都是通过属性的形式向子组件传递数据 -->
<counter :count="1"></counter>
<counter :count="2"></counter>

</div> <script> // 局部组件
var counter = {
// props 表示子组件接受父组件的内容
props: ['count'],
data: function () {
return {
// 子组件自己的data number值
number:this.count
}
},
template: "<div @click='handleClick'>{{number}}</div>",
methods: {
// 点击累加方法
handleClick: function () {
// 父组件可以随意的向子组件传递参数
// 但是子组件绝对不能去修改父组件传进来的参数 单向数据流
// 因此修改自己的Number值
this.number++
},
}
} var vm = new Vue({
el: "#root",
// 注册局部组件.
components: {
counter: counter,
}
})
</script> </body> </html>

  

子组件向父组件传值

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>父子间组件传值</title>
<script src="./vue.js"></script>
</head> <body>
<div id="root">
<!-- 父组件都是通过属性的形式向子组件传递数据 -->
<counter :count="3" @change="handleChange"></counter>
<counter :count="2" @change="handleChange"></counter>
<div>{{total}}</div>

</div> <script> // 局部组件
var counter = {
// props 表示子组件接受父组件的内容
props: ['count'],
data: function () {
return {
// 子组件自己的data number值
number:this.count
}
},
template: "<div @click='handleClick'>{{number}}</div>",
methods: {
// 点击累加方法
handleClick: function () {
// 父组件可以随意的向子组件传递参数
// 但是子组件绝对不能去修改父组件传进来的参数 单向数据流
// 因此修改自己的Number值
this.number++
// 向外触发事件,后可以跟参数
this.$emit('change',1
)
},
}
} var vm = new Vue({
el: "#root",
data:{
total:5,
},
// 注册局部组件.
components: {
counter: counter,
},
methods:{
handleChange:
function(step){
// step = 1 步长为2
// 求和等于默认值+点击一下的步长
this.total +=
step
}
}

})
</script> </body> </html>

  

组件参数校验与非props特性

组件参数校验   

  组件参数校验是指:父组件向子组件传递参数的时候,子组件有权向父组件提出参数的形式和要求,并检验父组件传进的参数是否合乎要求。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>组件参数校验与非props特性</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="root">
<!-- <child :content="123"></child> -->
<child content="123"></child>
</div> <script> Vue.component('child',{
props:{
// content:String, // 子组件接收到的content数据,必须是一个字符串类型
// content:[Number,String] // 子组件接收到的content数据,要么是字符串,要么是数字
content:{ // 接收content
type:String, //类型type必须是string
// required:true, // 表示content必需传
// default:'default value', // 如果没有传进来,默认显示这个
validator:function(value){ // 校验器校验传入的内容长度必须大于5
return (value.length>5
)
},

}
},
template:'<div>{{content}}</div>',
}) var vm = new Vue({
el:"#root", })
</script> </body>
</html>

  

非 Props 特性

Props 特性是指:当你的父组件使用子组件的时候通过属性向子组件传值的时候,恰好子组件里面声明了对父组件传递过来的属性的接收。

  

非Props 特性是指:父组件向子组件传递了一个属性,但是子组件并没有props接收的内容,也就是说,子组件并没有声明要接受父组件传递进来的属性。

  

非Props 特性特点一:如果子组件没人接收父组件传进的属性,则子组件不能使用父组件传进的值。

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>非 Props 特性</title>
<script src="./vue.js"></script>
</head> <body> <div id="root">
<!-- <child :content="123"></child> -->
<child content="hell"></child>
</div> <script> Vue.component('child', {
// props: {
// content: { // 接收content
// type: String, //类型type必须是string
// }
// }, // content 找不到,就会报错
template: '<div>{{content}}</div>'
,
}) var vm = new Vue({
el: "#root", })
</script>
</body> </html>

  

非Props 特性特点二:DOM中会保留父组件传递给子组件的属性标识

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>非 Props 特性</title>
<script src="./vue.js"></script>
</head> <body> <div id="root">
<!-- <child :content="123"></child> -->
<child content="hell"></child>
</div> <script> Vue.component('child', {
// props: {
// content: { // 接收content
// type: String, //类型type必须是string
// }
// },

template: '<div>hello</div>',
// content 找不到,就会报错
// template: '<div>{{content}}</div>',
}) var vm = new Vue({
el: "#root", })
</script>
</body> </html>

  

给组件绑定原生事件

很简单,在绑定事件的click后面加一个修饰符就行。

修饰符为 .native

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>给组件绑定原生事件</title>
<script src="./vue.js"></script>
</head>
<body> <div id="root">
<!-- 原生点击事件 -->
<child @click.native="handleClick"></child>
</div> <script> Vue.component('child',{
template:'<div @click="handleChildClick">Child</div>',
}) var vm = new Vue({
el:"#root",
methods:{
handleClick:function(){
alert('click')
}
}
})
</script> </body>
</html>    

  

非父子组件间的传值

情景分析

我们可以把一个网页拆分成很多个部分,每个部分就是我们代码中是我一个组件,如下面的一张图:

  

如果 1  2 层需要进行传值,则为父子组件之间的传值,通信方式在之前的内容讲到过。

    

如果 1  3 层进行传值,则为非父子组件间的传值,应该怎么办呢?

  

第一中方式:和父子组件间传值一样,一层一层的传递,第一层传给第二层,第二层在传给第三层,反之亦然。但是这种传值方式显然不方便太繁琐。

加入 3  3 层进行的非父子组件传值,又会是怎样的处理方法呢?

  

这种情况显然更加不适合层层传值,即第三层传给第二层,第二层传给第一层,第一层传给第二层,第二层传给第三层,累死了!代码变得非常的复杂。

非父子组件传值解决方法

第一种方法,我们可以使用 VUE 官方提供的一个数据层的框架,名字叫做 VUEX 来解决,但是使用有难度。

第二种方法,使用 发布订阅模式 来解决非父子组件的传值问题,在vue中叫做 总线机制

使用总线机制解决非父子组件传值问题

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>非父子组件间的传值(Bus|总线|发布订阅模式|观察者模式)</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="root">
<child content="Jayvee"></child>
<child content="Wong"></child>

</div> <script> Vue.prototype.bus = new Vue() Vue.component('child',{
data:function(){
return{
selfContent:this.content
}
},
template:'<div @click="handleClick">{{selfContent}}</div>',
props:{
content:String,
},
methods:{
handleClick:function(){
this.bus.$emit('change',this.selfContent)
}
},
mounted:function(){
var this_ = this
this.bus.$on('change',function(msg){
this_.selfContent = msg
})
}
}) var vm =new Vue({
el:"#root",
})
</script> </body>
</html>

  

VUE 中的插槽 - slot

 父组件通过传值的方式向子组件添加标签

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue中的插槽(slot)</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="root">
<child content="<p>wjw</p>"></child>
</div> <script> Vue.component('child',{
props:['content'],
template:'<div><p>hello</p><div v-html="this.content"></div></div>'
}) var vm = new Vue({
el:"#root",
}) </script> </body>
</html>

  

使用插槽

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue中的插槽(slot)</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="root">
<child>
<p>wjw</p>
</child>
</div> <script> Vue.component('child',{
template:'<div><p>hello</p><slot>默认内容</slot></div>'
}) var vm = new Vue({
el:"#root",
}) </script> </body>
</html>

  

传入header和footer

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue中的插槽(slot)</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="root">
<body-content>
<div slot='header' class="header">header</div>
<div slot='footer' class="footer">footer</div>
</body-content>
</div> <script> Vue.component('body-content',{
template:`<div>
<slot name='header'></slot>
<div class="content">content</div>
<slot name='footer'></slot>
</div>`
}) var vm = new Vue({
el:"#root",
}) </script> </body>
</html>

  

Vue中的作用域插槽

<!DOCTYPE html>
<html lang="en"> <head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>vue中的作用域插槽(slot)</title>
<script src="./vue.js"></script>
</head> <body>
<div id="root">
<child>
<template slot-scope="props">
<li>{{props.item}} -- hello</li>
</template>
</child>
</div> <script>
Vue.component('child', {
data: function () {
return {
list: [1, 2, 3, 4]
}
},
template: `<div>
<ul>
<slot v-for="item of list" :item=item></slot>
</ul>
</div>`
}) var vm = new Vue({
el: "#root",
})
</script> </body> </html>

  

Vue的动态组件与 v-once 指令

点击按钮实现两个组件显隐切换

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>VUE的动态组件与v-once指令</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="root">
<child-one v-if="type === 'child-one'"></child-one>
<child-two v-if="type === 'child-two'"></child-two>
<button @click="handleBtnClick">change</button>
</div> <script> Vue.component('child-one',{
template:"<div>child-one</div>"
}) Vue.component('child-two',{
template:"<div>child-two</div>"
}) var vm = new Vue({
el:'#root',
data:{
type:'child-one'
},
methods:{
handleBtnClick:function(){
this.type = this.type === 'child-one'?'child-two':'child-one'
},
}
})
</script> </body>
</html>

    

动态组件

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>VUE的动态组件与v-once指令</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="root">
<!-- component是vue自带的,表示动态组件 -->
<component :is="type"></component>
<!-- <child-one v-if="type === 'child-one'"></child-one>
<child-two v-if="type === 'child-two'"></child-two> -->
<button @click="handleBtnClick">change</button>
</div> <script> Vue.component('child-one',{
template:"<div>child-one</div>"
}) Vue.component('child-two',{
template:"<div>child-two</div>"
}) var vm = new Vue({
el:'#root',
data:{
type:'child-one'
},
methods:{
handleBtnClick:function(){
this.type = this.type === 'child-one'?'child-two':'child-one'
},
}
})
</script> </body>
</html>

 

V-once 节约性能,提高静态文件的展示效率

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>VUE的动态组件与v-once指令</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="root">
<!-- component是vue自带的,表示动态组件 -->
<!-- <component :is="type"></component> -->
<child-one v-if="type === 'child-one'"></child-one>
<child-two v-if="type === 'child-two'"></child-two>
<button @click="handleBtnClick">change</button>
</div> <script> Vue.component('child-one',{
template:"<div v-once>child-one</div>"
}) Vue.component('child-two',{
template:"<div v-once>child-two</div>"
}) var vm = new Vue({
el:'#root',
data:{
type:'child-one'
},
methods:{
handleBtnClick:function(){
this.type = this.type === 'child-one'?'child-two':'child-one'
},
}
})
</script> </body>
</html>

  

 

深入理解 Vue 组件的更多相关文章

  1. 不一样的角度理解Vue组件

    什么是组件 以Java.C#等面向对象编程语言的角度去理解Vue组件,能够发现组件和面向对象编程的方式和风格很相似.一切事物皆为对象,通过面向对象的方式,将现实世界的事物抽象成对象,现实世界中的关系抽 ...

  2. 尝试用面向对象思维理解Vue组件

    什么是组件 用面向对象的思维去理解Vue组件,可以将所有的事物都抽象为对象,而类或者说是组件,都具有属性和操作. 如抽取人类为组件,其基本的属性有姓名.年龄.国籍:基本的方法有吃饭.睡觉.跑步等. & ...

  3. 深入理解Vue组件3大核心概念

    摘要: 搞懂Vue组件! 作者:浪里行舟 原文:详解vue组件三大核心概念 Fundebug经授权转载,版权归原作者所有. 前言 本文主要介绍属性.事件和插槽这三个vue基础概念.使用方法及其容易被忽 ...

  4. 深入理解--VUE组件中数据的存放以及为什么组件中的data必需是函数

    1.组件中数据的存放 ***(重点)组件是一个单独模块的封装:这个模块有自己的HTML模板,也有data属性. 只是这个data属性必需是一个函数,而这个函数返回一个对象,这个对象里面存放着组件的数据 ...

  5. 怎样理解 Vue 组件中 data 必须为函数 ?

    组件意在 复用 , 若为 对象, 则会相互干扰. 且 Vue 不允许此事发生, 规定必须为函数, 否则报错. 原理如下 对象 // 模拟创建组件 var Component= function() { ...

  6. 第四章、深入理解vue组件

    4-1.使用组件的细节 a.使用is解决html出现bug 如下 table下面应该为tr,所以页面渲染的时候没有找到tr是有问题的,所以是有小bug,所以table中必须是tr b.改上面bug,t ...

  7. 深刻理解Vue中的组件

    转载:https://segmentfault.com/a/1190000010527064 --20更新: Vue2.6已经更新了关于内容插槽和作用域插槽的API和用法,为了不误导大家,我把插槽的内 ...

  8. 深入理解Vue父子组件通讯的属性和事件

    在html中使用元素,会有一些属性,如class,id,还可以绑定事件,自定义组件也是可以的.当在一个组件中,使用了其他自定义组件时,就会利用子组件的属性和事件来和父组件进行数据交流. 父子组件之间的 ...

  9. vue组件最佳实践

    看了老外的一篇关于组件开发的建议(强烈建议阅读英文原版),感觉不错翻译一下加深理解. 这篇文章制定一个统一的规则来开发你的vue程序,以至于达到一下目的. 1.让开发者和开发团队更容易发现一些事情. ...

随机推荐

  1. C# 指定http请求使用Tls1.2

    转载于 https://blog.csdn.net/yanghaitian/article/details/77498872 客户端语言 版本 类库 是否支持 兼容方案   Java 1.6.115之 ...

  2. 从零开始一起学习SLAM | 为什么要学SLAM?

    在<零基础小白,如何入门计算机视觉?>中我提到过,计算机视觉的研究目前主要分为两大方向:基于学习的方法和基于几何的方法.其中基于学习的方法最火的就是深度学习,而基于几何方法最火的就是视觉S ...

  3. cocos2dx 3.x 网络循环接收数据(RakNet::Packet* packet)单步网络接收

    void FriendFightLayer::update(float dt) { dealWithPacket(dt); if (m_isNeedSwitchToLobby) { PublicMet ...

  4. Selenium基础知识(四)表单切换

    在测试过程中,经常会碰到frame和iframe,嵌套等情况 这种情况下直接通过id,name等等是无法定位到的 好在selenium替我们想到了这个问题switch_to方法解决问题 switch_ ...

  5. IDEA2017及DataGrip2017注册码

    访问http://idea.lanyus.com/,网页中有相关说明,最简单的方式是将“0.0.0.0 account.jetbrains.com”添加到hosts文件中,然后点击页面底部的“获得注册 ...

  6. UML学习笔记(五)--顺序图

    顺序图是用来描述对象自身及对象间信息传递顺序的视图.它用来表示用例中的行为顺序.当执行一个用例行为时,顺序图中的每条消息对应了一个类操作或状态机中引起转换的触发事件.它着重显示了参与相互作用的对象和所 ...

  7. opencv-resize()放缩函数简介

    主要介绍函数resize(); 图像缩放的效果图如下: 主程序代码及函数解释如下所示: /******************************************************* ...

  8. PHP json_encode/json_decode与serialize/unserializ性能测

    PHP里面,有时候出于实际需求考虑,需要将某些信息以数组的方式进行存储,甚至有时候介于数组.字符串两者之间,很难确定是数组还是字符串,如果最终还需要将这些信息存储到文件系统中,而且要保证正确无误的存储 ...

  9. C# 语言 - 一个优雅的分页实现

    这篇文章介绍分页对象的封装,如何优雅的对数据进行分页. 先上调用代码: 我们希望能在一个Enumerable对象后面直接.ToPagedList(pageIndex,pageSize)这样优雅的调用分 ...

  10. 强化学习---A3C

    Asynchronous Advantage Actor-Critic (A3C) 在RL任务中,我们本质上最终要学习的是策略(Policy) value-based方法:间接方法,即通过学习值函数( ...