Vue组件
自定义组件的意思就是自定义tag标签,这个标签包含着一段html
代码
组件是可复用的 Vue
实例, 说白了就是一组可以重复使用的模板
和 JSTL
的自定义标签、Thymeleaf
的 th:fragment
有着异曲同工之妙,通常一个应用会以一棵嵌套的组件树的形式来组织:
例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
在Vue中,组件是最重要的组合部分,官方中定义组件为可复用的Vue实例,分为全局组件和局部组件,接下来通过实例来分别演示两种不同的组件。
封装Vue组件的原则及技巧,相关博客:https://blog.csdn.net/leilei__66/article/details/119348108
简单示例
<template>
<div id="app">
<button-counter></button-counter>
</div>
</template>
<script>
import buttonCounter from "./components/buttonCounter";
export default {
name: 'App',
components: {buttonCounter},
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<template>
<button v-on:click="count++">已经点击了 {{count}} 次按钮</button>
</template>
<script>
export default {
name: "buttonCounter",
data(){
return{
count: 0
}
}
}
</script>
<style scoped>
</style>
传递Object值
如果需要传递的值特别多,绑定很多元素就会显得很臃肿
那么就可以使用如下方式,传递对象
<template>
<div id="app">
<blog-info v-for="info in list" :key="info.id" :info="info"></blog-info>
</div>
</template>
<script>
import BlogInfo from "./components/blogInfo";
export default {
name: 'App',
components: {BlogInfo},
data() {
return{
list:[
{
id: '001',
content: 'HelloWorld1',
title: 'myBlog1'
},
{
id: '002',
content: 'HelloWorld2',
title: 'myBlog2'
}
]
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<template>
<div>
id:{{info.id}}, content:{{info.content}}, title:{{info.title}}
</div>
</template>
<script>
export default {
name: "blogInfo",
props:{
info:{
type: Object
}
}
}
</script>
<style scoped>
</style>
父组件监听子组件事件
在我们开发组件时,它的一些功能可能要求我们和父级组件进行沟通。
仅触发事件
<template>
<div id="app">
<event-component v-on:triggerEvent="str = 'triggerEvent'"></event-component>
<p>{{str}}</p>
</div>
</template>
<script>
import EventComponent from "./components/eventComponent";
export default {
name: 'App',
components: {EventComponent},
data() {
return{
str: "HelloWorld",
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<template>
<button v-on:click="$emit('triggerEvent')">点此触发事件</button>
</template>
<script>
export default {
name: "eventComponent"
}
</script>
<style scoped>
</style>
触发事件并传值
有的时候用一个事件来抛出一个特定的值是非常有用的。例如我们可能想让子组件决定父要做什么。这时可以使用 $emit 的第二个参数来提供这个值
然后当在父级组件监听这个事件的时候,我们可以通过 $event
访问到被抛出的这个值
<template>
<div id="app">
<event-component v-on:triggerEvent="str = $event"></event-component>
<p>{{str}}</p>
</div>
</template>
<script>
import EventComponent from "./components/eventComponent";
export default {
name: 'App',
components: {EventComponent},
data() {
return{
str: "HelloWorld",
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<template>
<button v-on:click="$emit('triggerEvent', 'triggerEvent')">点此触发事件</button>
</template>
<script>
export default {
name: "eventComponent"
}
</script>
<style scoped>
</style>
如果事件处理函数是方法
<template>
<div id="app">
<event-component v-on:triggerEvent="testEvent"></event-component>
<p>{{str}}</p>
</div>
</template>
<script>
import EventComponent from "./components/eventComponent";
export default {
name: 'App',
components: {EventComponent},
data() {
return{
str: "HelloWorld",
}
},
methods:{
testEvent(str){
this.$set(this, "str", str)
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<template>
<button v-on:click="$emit('triggerEvent', 'triggerEvent')">点此触发事件</button>
</template>
<script>
export default {
name: "eventComponent"
}
</script>
<style scoped>
</style>
在组件上使用v-model
自定义事件也可以用于创建支持 v-model 的自定义输入组件。
<input v-model="searchText">
等价于:
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
当用在组件上时,v-model 则会这样
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
为了让它正常工作,这个组件内的 input
必须将其 value attribute 绑定到一个名叫 value 的 prop 上
在其 input
事件被触发时,将新的值通过自定义的 input
事件抛出
父子组件获取值
父组件不能直接获取子组件的值
需要通过 this.$emit('input', val)
把值传回父组件
同时子组件也不能直接操作父组件传过来的值,需要进行变量的转换
例如 :this.count = this.value
然后去操作 this.count
<template>
<div id="app">
<button-counter v-model="count"></button-counter>
<p>已经点击了{{count}}次</p>
</div>
</template>
<script>
import buttonCounter from "./components/buttonCounter";
export default {
name: 'App',
components: {buttonCounter},
data() {
return{
count: 0
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<template>
<button v-on:click="clickMethod">已经点击了 {{count}} 次按钮</button>
</template>
<script>
export default {
name: "buttonCounter",
props:{
value:{
type: Number,
}
},
data(){
return{
count: this.value
}
},
watch:{
count(val){
this.$emit("input", val)
}
},
methods:{
clickMethod(){
this.count++
this.$emit("input", this.count)
}
},
}
</script>
<style scoped>
</style>
动态组件
<template>
<div id="dynamic-component-demo" class="demo">
<button
v-for="tab in tabs"
:key="tab.name"
:class="['tab-button', { active: currentTab.name === tab.name }]"
v-on:click="currentTab = tab"
>
{{ tab.name }}
</button>
<component v-bind:is="currentTab.component" class="tab"></component>
</div>
</template>
<script>
let tabs = [
{
name: "Home",
component: {
template: "<div>Home component</div>"
}
},
{
name: "Posts",
component: {
template: "<div>Posts component</div>"
}
},
{
name: "Archive",
component: {
template: "<div>Archive component</div>"
}
}
]
export default {
name: "tabs",
data() {
return {
tabs: tabs,
currentTab: tabs[0]
}
}
}
</script>
<style scoped>
.tab-button {
padding: 6px 10px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
border: 1px solid #ccc;
cursor: pointer;
background: #f0f0f0;
margin-bottom: -1px;
margin-right: -1px;
}
.tab-button:hover {
background: #e0e0e0;
}
.tab-button.active {
background: #e0e0e0;
}
.tab {
border: 1px solid #ccc;
padding: 10px;
}
</style>
解析DOM模板
有些 HTML 元素,诸如 <ul>
、<ol>
、<table>
和 <select>
,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>
、<tr>
和 <option>
,只能出现在其它某些特定的元素内部。
这会导致我们使用这些有约束条件的元素时遇到一些问题。例如在table标签中放入自定义的组件
这个自定义组件会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is attribute 给了我们一个变通的办法:
<table>
<tr is="自定义的组件"></tr>
</table>
注意:需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的
- 字符串 (例如:template: '...')
- 单文件组件 (.vue)
<script type="text/x-template">