框架指令

了解框架提供的指令与组件:for,if,show,block,slot

通过本节,你将学会:

  • 指令 for
  • 指令 if 与指令 show
  • 组件 block
  • 组件 slot

指令 for

for 指令用于循环输出一个数组类型的数据

示例如下:

  1. <template>
  2. <div class="tutorial-page">
  3. <!-- 方式1:默认$item代表数组中的元素, $idx代表数组中的索引 -->
  4. <div class="tutorial-row" for="{{list}}">
  5. <text>{{$idx}}.{{$item.name}}</text>
  6. </div>
  7. <!-- 方式2:自定义元素变量名称 -->
  8. <div class="tutorial-row" for="value in list">
  9. <text>{{$idx}}.{{value.name}}</text>
  10. </div>
  11. <!-- 方式3:自定义元素、索引的变量名称 -->
  12. <div class="tutorial-row" for="(personIndex, personItem) in list">
  13. <text>{{personIndex}}.{{personItem.name}}</text>
  14. </div>
  15. </div>
  16. </template>
  17. <style lang="less">
  18. .tutorial-page {
  19. flex-direction: column;
  20. .tutorial-row {
  21. width: 85%;
  22. margin-top: 10px;
  23. margin-bottom: 10px;
  24. }
  25. }
  26. </style>
  27. <script>
  28. export default {
  29. private: {
  30. list: [
  31. {name: 'aa'},
  32. { name: 'bb' }
  33. ]
  34. },
  35. onInit () {
  36. this.$page.setTitleBar({ text: '指令for' })
  37. }
  38. }
  39. </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。然后根据 nameslot 的匹配,将内容分发到对应的 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>

注意:目前 nameslot 属性均不支持动态数据,如果使用可能导致实际渲染和预期不一致。

<template>
  <div>
    <!-- slotName 设置无效 -->
    <slot name="{{slotName}}">
    </slot>
  </div>
</template>

<script>
export default {
  data() {
    return {
      slotName: 'slot1'
    }
  }
}
</script>

总结

指令 for、if、show 与组件 block 是很常用的,掌握使用方法很有必要。同时,运用 slot 组件可以让我们的组件变得更加灵活,可定制。