开始
博文组件
博文组件代码 (推荐组件名复合w3c规范: 字母全小写且必须包含一个连字符)
<!-- 博文 blog-test.vue -->
<!-- HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。
这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop名需要使用
其等价的 kebab-case (短横线分隔命名) 命名 -->
<!-- 如:在组件中我们prop的是postData,在使用组件是使用的是post-data -->
<template>
<div>
<h3>{{postData.title}}</h3>
<button @click="addSize">+size</button>
<div class="content">{{postData.content}}</div>
</div>
</template>
<script>
export default {
props: ['postData'],
methods: {
//不同于组件和 prop,事件名不存在任何自动化的大小写转换。
//而是触发的事件名需要完全匹配监听这个事件所用的名称
//所以在使用这个组件时还是enlarge-text事件
//推荐你始终使用 kebab-case(短横线分隔命名)的事件名
addSize(){
this.$emit('enlarge-text',0.5)
}
}
}
</script>
//prop验证
//类型错误控制台会报错
//没有动态绑定 :post-data="post" 会给个默认值即default里的内容
props: {
postData: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { title: '没有title', content: "没有内容"}
}
}
}
复制代码
<!-- 父组件的页面 -->
<template>
<div style="background: #eee;padding: 16px" :style="{ fontSize: postFontSize + 'em' }">
<blogTest :post-data="post" @enlarge-text="enlargeText1"></blogTest>
</div>
</template>
<script>
import blogTest from '@/components/blog-test'
export default {
components: {
blogTest
},
data(){
return {
post: {
title: '这是标题',
content: '这是博文的内容这是博文的内容这是博文的内容这是博文的内容这是博文的内容这是博文的内容这是博文的内容这是博文的内容这是博文的内容'
},
postFontSize: 1
}
},
methods: {
enlargeText1(num){
this.postFontSize += num;
}
}
}
</script>
复制代码
关于组件上使用v-model
关于组件上使用v-model(写的很详细)
查看 www.cnblogs.com/wind-lanyan…
<!-- 子组件custom-input.vue -->
<template>
<div>
<input v-bind:value="value" v-on:input="$emit('input', $event.target.value)" type="text">
</div>
</template>
<script>
export default {
props: ['value']
}
</script>
复制代码
<!-- 父组件的页面 -->
<template>
<div style="background: #eee;padding: 16px">
<!-- v-model实际是语法糖,用法如下 -->
<customInput v-bind:value="searchText" v-on:input="searchText1 = $event"></customInput>
<p>页面中的值:{{searchText}}</p>
<!-- v-model正常用法,和上面的是一样的 -->
<customInput v-model="searchText1"></customInput>
<p>页面中的值:{{searchText1}}</p>
</div>
</template>
<script>
import customInput from '@/components/custom-input'
export default {
components: {
customInput
},
data(){
return {
searchText: '1',
searchText1: '2'
}
}
}
</script>
复制代码
slot插槽
还是刚才的input组件
<!-- custom-input.vue在其中添加了一个slot -->
<div>
<input v-bind:value="value" v-on:input="$emit('input', $event.target.value)" type="text">
<slot></slot>
</div>
<!-- 使用组件的页面,在customInput标签中添加了一个p标签,这个p标签会替换掉slot标签 -->
<template>
<div style="background: #eee;padding: 16px">
<customInput v-model="searchText">
<p>slot内容</p>
</customInput>
<p>页面中的值:{{searchText}}</p>
</div>
</template>
复制代码
插槽后备内容
<!-- custom-input.vue在其中添加了一个slot -->
<div>
<input v-bind:value="value" v-on:input="$emit('input', $event.target.value)" type="text">
<slot>后备内容</slot>
</div>
<!-- 父组件的页面,在customInput标签中什么都没有时,slot标签中的内容就会显示 -->
<template>
<div style="background: #eee;padding: 16px">
<customInput v-model="searchText"></customInput>
<p>页面中的值:{{searchText}}</p>
</div>
</template>
复制代码
具名插槽(文档已经很清楚了)
<!--slot-input.vue-->
<template>
<div style="background: #fff;">
<h3>插槽是input的组件</h3>
<slot name="header"><h1>默认头部内容</h1></slot>
<!-- 把组件中的数据传到页面中 -->
<slot v-bind:data="comData"></slot>
<slot name="footer"><h1>默认底部内容</h1></slot>
</div>
</template>
<script>
export default {
data(){
return {
comData: {
name: 'lily',
age: 20
}
}
}
}
</script>
<!--父组件中使用-->
<template>
<div style="background: #eee;padding: 16px">
<slotInput>
<template v-slot:header>
<p>头部信息</p>
</template>
<!-- 任何没有被包裹在带有 v-slot 的 <template> 中的内容都会被视为默认插槽的内容 -->
<!-- <input type="text" style="width: 100px;height:30px;"> -->
<!-- 希望更明确一些,仍然可以在一个 <template> 中包裹默认插槽的内容 -->
<template v-slot:default="slotProps">
<!-- 使用组件中的数据 -->
<p>组件中的数据: {{slotProps.data.name}}</p>
</template>
<template v-slot:footer>
<p>底部信息</p>
</template>
</slotInput>
</div>
</template>
<script>
import slotInput from '@/components/slot-input'
export default {
components: {
slotInput
}
}
</script>
复制代码
效果图:
如果在父组件的组件标签中中不添加任何内容:
<!--父组件中代码-->
<template>
<div style="background: #eee;padding: 16px">
<slotInput></slotInput>
</div>
</template>
复制代码
则会显示子组件插槽slot中定义默认内容,效果如下:
组件自己套用自己
<!--子组件tree-test.vue-->
<!-- 树形组件 -->
<template>
<div class="content">
<ul>
<li v-for="item in treeData" :key="item.uname">
<span @click="toggle(item)">{{item.uname}}</span>
<treeTest1 :tree-data="item.children" v-show="item.xian"></treeTest1>
</li>
</ul>
</div>
</template>
<script>
export default {
//组件是可以在它们自己的模板中调用自身的,只能通过 name 选项来做这件事
name: 'treeTest1',
props: {
treeData: {
type: Array,
default: function () {
return [
{
uname:'默认',
xian: false,
children:[{
uname:'默认1',
xian: false,
children: []
}]
}
]
}
}
},
methods: {
toggle(item){
item.xian = !item.xian
}
}
}
</script>
复制代码
<!--父组件-->
<template>
<div class="about">
<treeTest :tree-data="treeList"></treeTest>
</div>
</template>
<script>
import treeTest from '@/components/tree-test'
export default {
components: {
treeTest
},
data(){
return {
treeList: [
{
uname:'目录',
xian: false,
children:[{
uname:'目录1',
xian: false,
children: [{
uname:'目录11',
xian: false,
children: []
},
{
uname: '目录12',
xian: false,
children: []
}]
}]
},
{
uname:'我的音乐',
xian: false,
children:[{
uname:'音乐1',
xian: false,
children: []
}]
},
{
uname:'我的照片',
xian: false,
children:[{
uname:'照片1',
xian: false,
children: []
}]
}
]
}
}
}
</script>
复制代码
默认效果是这样的:
点击第一个"目录"后: