框架指令
了解框架提供的指令与组件:for,if,show,block,slot
通过本节,你将学会:
- 指令 for
- 指令 if 与指令 show
- 组件 block
- 组件 slot
指令 for
for 指令用于循环输出一个数组类型的数据
示例如下:
<template>
<div class="tutorial-page">
<!-- 方式1:默认$item代表数组中的元素, $idx代表数组中的索引 -->
<div class="tutorial-row" for="{{list}}">
<text>{{$idx}}.{{$item.name}}</text>
</div>
<!-- 方式2:自定义元素变量名称 -->
<div class="tutorial-row" for="value in list">
<text>{{$idx}}.{{value.name}}</text>
</div>
<!-- 方式3:自定义元素、索引的变量名称 -->
<div class="tutorial-row" for="(personIndex, personItem) in list">
<text>{{personIndex}}.{{personItem.name}}</text>
</div>
</div>
</template>
<style lang="less">
.tutorial-page {
flex-direction: column;
.tutorial-row {
width: 85%;
margin-top: 10px;
margin-bottom: 10px;
}
}
</style>
<script>
export default {
private: {
list: [
{name: 'aa'},
{ name: 'bb' }
]
},
onInit () {
this.$page.setTitleBar({ text: '指令for' })
}
}
</script>
在渲染页面时, div.tutorial-row
的结构,会根据 script 中的数据 list 的定义,被循环的生成多个
注意:
- 自定义变量表示 for 指令的数组索引和数组元素时,变量名不可以用
$
或_
开头;
指令 if 与指令 show
if 条件指令,是指 if/elif/else 这 3 个相关指令,用于控制是否增加或者删除组件;
show 指令,是指是否显示组件,用于控制组件的显示状态,并不会从 DOM 结构中删除
示例如下:
<template>
<div class="tutorial-page">
<text onclick="onClickShow">显示隐藏:</text>
<text show="{{showVar}}">show: 渲染但控制是否显示</text>
<text onclick="onClickCondition">条件指令:</text>
<text if="{{conditionVar === 1}}">if: if条件</text>
<text elif="{{conditionVar === 2}}">elif: elif条件</text>
<text else>else: 其余</text>
</div>
</template>
<style lang="less">
.tutorial-page {
flex-direction: column;
}
</style>
<script>
export default {
private: {
showVar: true,
conditionVar: 1
},
onInit () {
this.$page.setTitleBar({ text: '指令if与指令show' })
},
onClickShow () {
this.showVar = !this.showVar
},
onClickCondition () {
this.conditionVar = ++this.conditionVar % 3
}
}
</script>
当 if/elif 指令的值为 false 时,节点会从页面中移除,当 if/elif 指令值为 true,组件会动态插入节点中;
当 show 指令的值为 true 时,节点可见, 当其值为 false 时,组件不可见,但节点仍会保留在页面 DOM 结构中
注意:
- if/elif/else 节点必须是相邻的兄弟节点
组件 block
block 组件是表达逻辑区块的组件,没有对应的Native组件
。可以使用<block>
实现更为灵活的"列表/条件渲染"。如在<block>
上使用 for 指令和 if 指令
示例如下:
<template>
<div class="tutorial-page">
<text onclick="toggleCityList">点击:控制是否显示城市</text>
<div class="city" for="city in cities" if="{{showCityList === 1}}">
<text>城市:{{city.name}}</text>
<block if="{{city.showSpots}}" for="{{city.spots}}">
<text>景点:{{$item.name}}</text>
</block>
</div>
</div>
</template>
<style lang="less">
.tutorial-page {
flex-direction: column;
}
.city {
flex-direction: column;
}
</style>
<script>
import {dataDirective} from '../../Common/js/data'
export default {
private: {
showCityList: 1,
cities: dataDirective
},
onInit () {
this.$page.setTitleBar({ text: '组件block' })
},
toggleCityList () {
this.showCityList = this.showCityList === 1 ? 0 : 1
}
}
</script>
这个示例有点复杂,综合了前述的知识点。对示例中的变量解释如下:
- showCityList 用于控制是否在页面中生成列表元素即城市的列表
- cityList 数组代表需要列表渲染的城市列表数据
- cityList 数组的每个元素中的 showSpots,决定了是否显示当前 city 的 spots 数据读者可以看到,通过这些组合,可以表达复杂的业务逻辑
组件 slot
类似于其他框架的内容分发,在快应用中也实现了一套内容分发的 API,我们可以使用 slot
组件作为承载分发内容的出口。
插槽内容
在子组件 part1
中,我们使用了 slot
组件来承载父组件中定义的内容
<template>
<div>
<slot></slot>
</div>
</template>
在父组件 index
中,我们引入了子组件 part1
,并且在里面定义了分发内容。在渲染时,part1
中的 slot
组件将会被父组件中的分发内容替换。
<import name="part1" src="./part1.ux"></import>
<template>
<div>
<part1>
<text>dynamic content form parent</text>
</part1>
</div>
</template>
默认内容 1050+
slot
组件中可以设置默认内容
<template>
<div>
<slot>
<text>default content form part1</text>
</slot>
</div>
</template>
在父组件 index
中,如果没有内容需要分发到 part1
组件。此时子组件 part1
中的 slot
组件将会渲染该组件下的默认内容
<div>
<part1>
</part1>
</div>
同时,如果父组件中设置的分发内容但因为设置了 if
或其他原因没有实际的节点渲染,那么子组件 part1
中的 slot
组件也将渲染 slot
组件下的默认内容
<import name="part1" src="./part1.ux"></import>
<template>
<div>
<part1>
<text if="{{showContent}}">dynamic content form parent</text>
</part1>
</div>
</template>
<script>
export default {
data() {
return {
showContent: false
}
}
}
</script>
编译作用域 1050+
父级模板里的所有内容都是在父级作用域中编译;子模板里的所有内容都是在子作用域中编译。
父组件 index
<import name="part1" src="./part1.ux"></import>
<template>
<div>
<part1>
<!-- {{context}} 的编译作用域在父组件 -->
<text>dynamic content form {{context}}</text>
</part1>
</div>
</template>
<script>
export default {
data() {
return {
context: 'parentVm'
}
}
}
</script>
子组件 part1
<template>
<div>
<slot>
<!-- {{context}} 的编译作用域在子组件 -->
<text>default content form {{context}}</text>
</slot>
</div>
</template>
<script>
export default {
data() {
return {
context: 'childVm'
}
}
}
</script>
具名插槽 1050+
在子组件中,我们定义具有不同 name
属性的 slot
组件。如果没有设置,则默认的 name
属性为 default
。
<template>
<div>
<div class="header">
<!-- 我们希望把头部放这里 -->
<slot name="header"></slot>
</div>
<div class="main">
<!-- 我们希望把主要内容放这里 -->
<slot name="main"></slot>
</div>
<div class="footer">
<!-- 我们希望把尾部放这里 -->
<slot name="footer"></slot>
</div>
</div>
</template>
在父组件中,通过设置 slot
属性,如果没有设置,则默认的 slot
属性为 default
。然后根据 name
和 slot
的匹配,将内容分发到对应的 slot
组件。
<import name="part1" src="./part1.ux"></import>
<template>
<div>
<part1>
<text slot="header">header content</text>
<text slot="main">main content</text>
<text slot="footer">footer content</text>
</part1>
</div>
</template>
注意:目前
name
和slot
属性均不支持动态数据,如果使用可能导致实际渲染和预期不一致。
<template>
<div>
<!-- slotName 设置无效 -->
<slot name="{{slotName}}">
</slot>
</div>
</template>
<script>
export default {
data() {
return {
slotName: 'slot1'
}
}
}
</script>
总结
指令 for、if、show 与组件 block 是很常用的,掌握使用方法很有必要。同时,运用 slot 组件可以让我们的组件变得更加灵活,可定制。