Vue学习笔记(5)——组件基础

Stars-one 2020年10月26日 295次浏览 本篇字数为4,260字

本文为作者原创,转载请注明出处,谢谢配合
作者:Stars-one
链接:https://stars-one.site/2020/10/26/vue-study-5


在网页开发过程中,页面中有许多地方都是使用的同样的布局与样式,html文件中会有多段重复性的代码,而且不便于维护,改一处,其他地方都得改,十分麻烦,而Vue提供了组件这一概念,我们可以将相同的布局抽取出来当作为一个组件,这样后期维护也会十分方便

简单使用

我们定义一个组件之后,页面就可以使用组件名作为标签来使用组件

<div id="app">
	<button-counter></button-counter>
</div>

// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
	//注意这里使用方法
  data: function () {
    return {
      count: 0
    }
  },
  //注意,这是js的模版语法,用的是 `(tab键上面那个键),而不是单引号
  template: `<button v-on:click="count++">You clicked me {{ count }} times.</button>`
});

//创建Vue实例
var app = new Vue({
	el: "#app",
	data: {
		
	},
});

下面对上面的代码进行解析

Vue.component()是组件注册**(全局注册)**需要调用的方法,其接收两个参数,第一个参数为组件名,第二个参数为一个Json对象

组件名,官方推荐使用-或者首字母大写,在使用的时候只能使用-,组件名大写,标签也得使用-,如下

Vue.component('ButtonCounter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: `<button v-on:click="count++">You clicked me {{ count }} times.</button>`
});

<!-- 会报错 -->
<ButtonCounter></ButtonCounter>

第二个参数与我们new一个Vue的实例传递的参数基本相同,不同的是,**组件注册传递的参数不包含el**

需要注意,第二个参数里的的data需要使用方法而不是使用对象,使用方法才能保证每个组件绑定的数据是相互独立,互不影响

传递数据

一般情形,我们使用组件肯定不止一个,可能是多个组件嵌套,这就涉及到了数据的传递

Vue中组件注册传递的json对象中,提供了prop参数(相当于给子控件的标签实现了自定义的属性),可以方便我们从父组件中传递数据到子组件中

<div id="app">
	<!-- title属性是在组件注册时候定义的 -->
	<nav-item title="导航1"></nav-item>
	<nav-item title="导航2"></nav-item>
	<nav-item title="导航3"></nav-item>
</div>

//定义组件
Vue.component('nav-item', {
	//自定义属性title
	props: ['title'],
	template: `<p>{{title}}</p>`
});

//创建实例
var app = new Vue({
	el: "#app",
});

可以注意到props传递的参数是一个数组,所以可以组件的自定义属性可以有任意多个

组件自定义属性效果图

自定义属性也可以使用v-bind命令,当然,也可以使用v-for创建多个重复组件,这个就比较灵活,可以根据需求使用即可

<div id="app">
	<nav-item v-for="item in navList" v-bind:title="item.title"></nav-item>
</div>

Vue.component('nav-item', {
	props: ['title'],
	template: '<p>{{title}}</p>'
});

var app = new Vue({
	el: "#app",
	data: {
		navList: [
			{
				id: 1,
				title: 'My journey with Vue'
			},
			{
				id: 2,
				title: 'Blogging with Vue'
			},
			{
				id: 3,
				title: 'Why Vue is so fun'
			}
		]
	}
});

上面只是传递一个属性,如果有多个属性,就得声明多个属性,我们可以定义属性接收Object对象,之后取值也是比较方便

属性接收为Object对象

内容传递(插槽)

上面都是通过自定义属性来传递数据,但有时候,我们需要将标签内容传递给组件,可以使用组件提供的插槽<slot></slot>进行传值

<alert-box>
  Something bad happened.
</alert-box>

Vue.component('alert-box', {
  template: `
    <div class="demo-alert-box">
      <strong>Error!</strong>
	  <!--接收组件标签的内容 -->
      <slot></slot>
    </div>
  `
})

插槽

事件传递

子组件回调父类事件

如果父类想要监听子组件的事件,可以让字组件事件中使用$emit,进行回调父类事件,如下面有个简单的例子:

子组件是一个只有按钮的视图,点击按钮后,会回调父组件中的sayHi方法,$emit中传递父类组件定义的事件名即可

<div id="app">
	<!-- 这里的btn-click是自定义的一个事件名 -->
	<nav-item title="标题1" v-on:btn-click="sayHi"></nav-item>
</div>

Vue.component('nav-item', {
  props: ['title'],
  template: `<button v-on:click="$emit('btn-click')">{{title}}</button>`
});

var app = new Vue({
	el: "#app",
	data: {
	},
	methods:{
		sayHi:function(){
			console.log("hello");
		}
	}
});

事件传递数据

如果我们想要子组件传递在回调父类组件,并且需要传递数据,可以使用$emit的第二个参数

<button v-on:click="$emit('btn-click', 0.1)">
  Enlarge text
</button>

之后,在父类中,我们可以通过$event来接收这个数值(父类是使用内联的方式),如官方的例子:

<blog-post
  ...
  v-on:enlarge-text="postFontSize += $event"
></blog-post>

如果是像我们上面,是调用了方法的话,方法的第一个参数即为该数值

<div id="app"
	<nav-item title="标题1" v-on:btn-click="sayHi"></nav-item>
</div>

sayHi:function(value){
	...
}

组件使用v-model

如果组件中是包含相关的表单元素,需要稍微改造一下,我们可以看看官方给出的等价例子:

v-model的等价例子

参考上图,我们可以得到以下在组件中使用v-model的规则:

  • 将其 value attribute 绑定到一个名叫 value 的 prop 上
  • 在其 input 事件被触发时,将新的值通过自定义的 input 事件抛出
Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
})

使用:

<div id="app">
	<!-- 与下面的代码等价 -->
	<custom-input
	  v-bind:value="searchText"
	  v-on:input="searchText = $event"
	></custom-input>
	
	<!--使用v-model -->
	<custom-input
	v-model="searchText"
	></custom-input>
</div>

var app = new Vue({
	el: "#app",
	data: {
		searchText:""
	},
});

动态组件

动态组件,一般是有多标签切换的情况下,如官方给的示例中:

多标签切换

下方显示的内容就是动态组件,每个标签都有其对应的一个组件,当点击上方不同的选项,其会发生改变

<div id="app">
	<div>
		<!-- 绑定点击事件 -->
		<button v-on:click="showContent(1)">标签1</button>
		<button v-on:click="showContent(2)">标签2</button>
		<button v-on:click="showContent(3)">标签3</button>
	</div>
	<!-- 使用component标签和is属性 -->
	<component v-bind:is="currentContentDiv"></component>
</div>

//定义三个组件,名字各不相同
Vue.component('content1', {
  template: `
	<div>标签1的内容</div>`
});
Vue.component('content2', {
  template: `
	<div>标签2的内容</div>`
});
Vue.component('content3', {
  template: `
	<div>标签3的内容</div>`
});

var app = new Vue({
	el: "#app",
	data: {
		contentIndex : 1
	},
	computed:{
		currentContentDiv:function(){
			//当contentIndex数据发生变化(也就是点击按钮操作),返回不同的组件名
			//从而让页面显示不同的组件
			return 'content'+this.contentIndex;
		}
	},
	methods:{
		//点击按钮改变下标值,之后会自动计算,从而使currentContentDiv数据发生变化
		showContent:function(num){
			this.contentIndex =num;
		}
	}
});

切换标签效果图

currentContentDiv可接受已注册组件的名字一个组件的选项对象

这个 attribute 可以用于常规 HTML 元素,但这些元素将被视为组件,这意味着所有的 attribute 都会作为 DOM attribute 被绑定。对于像 value 这样的 property,若想让其如预期般工作,你需要使用 .prop修饰器。

相关标签