HaaS UI小程序解决方案基础教学之七:创建第一个自定义组件

简介: 前面已经介绍过通过HaaS UI内置的组件库来搭建页面,而组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素(在HaaS UI里就是扩展基础组件库),封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用。

名词解释

AliOS Things: 阿里云智能IoT团队自研的物联网操作系统

HaaS:全称是Hardware as a Service,阿里云智能IoT团队基于AliOS Things系统推出的硬件即服务

HaaS UI:全称是Hardware as a Service User Interface,是源自AliOS Things操作系统上的一套应用&图形解决方案,支持C/C++和 JS两种开发语言

1、前言

前面已经介绍过通过HaaS UI内置的组件库来搭建页面,而组件(Component)是 Vue.js 最强大的功能之一。 组件可以扩展 HTML 元素(在HaaS UI里就是扩展基础组件库),封装可重用的代码。 组件系统让我们可以用独立可复用的小组件来构建大型应用。

几乎任意类型的应用的界面都可以抽象为一个组件树:

image.png

2、自定义组件

Vue.js注册自定义组件支持全局组件和局部组件,全局组件是指在页面入口统一注册,所有组件都能使用,局部组件是在需要使用的地方进行注册。目前HaaS UI支持局部组件注册。

注册一个自定义组件的方法:

// 导入一个自定义vue组件
import Switch from "./switch.vue";
export default {
  // 注册自定义组件,只在当前实例中使用
  components: { Switch },
}
</script>

3、组件Prop

prop 是子组件用来接受父组件传递过来的数据的一个自定义属性。 父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 "prop":

export default {
  name: 'Child',
  props: {
    message: {                          // 属性名
      type: String,             // 属性类型
      default: '',              // 默认值
      validator(val) {      // 属性值合法验证
        return true;
      }
    },
    }
}
</script>

3.1、Prop类型

属性类型type可以是下面原生构造器:

String Number Boolean Array Object Date Function Symbol

也可以是一个自定义构造器,使用 instanceof 检测。

3.2、动态Prop

组件prop也可以使用动态绑定方式传递,类似于用 v-bind 绑定到一个表达式,也可以用 v-bind 动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件:

  <div @click="click">
    <!-- 动态prop -->
    <Child v-bind:message="message" />
  </div>
</template>
<script>
import Child from "./child.vue";
export default {
  // 注册自定义Child组件
  components: {
    Child,
  },
  data() {
    return {
      message: 'Hello world',
    };
  },
  methods: {
    click(r) {
      // 修改message,child自动响应式更新
      this.message = 'message changed';
    },
  },
};
</script>

3.3、第一个自定义组件

根据上面介绍的相关内容,搭建一个自定义组件child.vue:

    <text>{{message}}</text>
</template>
<script>
export default {
  name: 'Child',
  props: {
    message: {                          // 属性名
      type: String,             // 属性类型
      default: '',              // 默认值
      validator(val) {      // 属性值合法验证
        return true;
      }
    },
    }
}
</script>

父组件容器:

  <div @click="click">
    <!-- 动态prop -->
    <Child v-bind:message="message" />
    <!-- 静态prop -->
    <Child message="message static" />
  </div>
</template>
<script>
import Child from "./child.vue";
export default {
  // 注册自定义Child组件,当前实例内可复用
  components: {
    Child,
  },
  data() {
    return {
      message: 'Hello world',
    };
  },
  methods: {
    click(r) {
      // 修改message,child自动响应式更新
      this.message = 'message changed';
    },
  },
};
</script>

运行效果如下:

e06789acd6aa94916039e9af7a308b4a.gif

4、扩展一个Switch组件

了解了如何扩展一个自定义组件,我们开始尝试扩展一个更加实用的switch组件,这个组件一般用于做开关控制,是一个非常常用的组件。效果如下:

66933ab787245e4010a4941ab255cc7f.gif

4.1、Switch组件

直接上代码:

  <!-- box为组件外框 -->
  <div class='box' :style="{'width': width + 'px', 'height': height + 'px', 'background-color': internalChecked ? colorChecked : colorNormal}" @click="toggle">
    <!-- button为内部圆球 -->
    <div class='button' :style="{'width': (height-4) + 'px', 'height': (height-4) + 'px', 'transform': `translateX(${internalChecked ? (width - height) + 'px' : (0 + 'px')})`, 'background-color' : colorButton}"></div>
  </div>
</template>
<script>
export default {
  name: 'FlSwitch',
  model:{           // v-model双向数据绑定
    prop: 'checked',
    event: 'change'
  },
  props: {
    colorChecked: { // 选中时的背景色
      type: String,
      default: '#108ee9'
    },
    colorNormal: {  // 默认未选中时的背景色
      type: String,
      default: '#fff'
    },
    colorButton: {  // 按钮颜色
      type: String,
      default: '#fff'
    },
    width: {        // 宽度(px),需大于高度,设置整体组件宽度
      type: Number,
      default: 50
    },
    height: {       // 高度(px),需小于宽度,设置组件高度
      type: Number,
      default: 25
    },
    checked: {      // 是否选中
      type: Boolean,
      default: false,
    }
  },
  data() {
    return {
      internalChecked : this.checked
    };
  },
  methods: {
    toggle() {
      this.internalChecked = !this.internalChecked;
    }
  },
  watch: {
    checked() {
      this.internalChecked = this.checked;
    },
    internalChecked() {
      this.$emit('change', this.internalChecked);
    }
  }
}
</script>
<style scoped>
.box {  /* switch背景样式 */
  border-style: solid;
  border-width: 1px;
  border-color: #888;
  border-radius: 1000px;
  box-sizing: border-box;
  transition-property: background-color;
  transition-duration: 100ms;
  padding: 1px;
}
.button { /* switch圆球样式 */
  border-radius: 1000px;
  box-shadow: 0px 0px 5px #888;
  transition-property: transform;
  transition-duration: 100ms;
}
</style>

以上,为switch组件定义了6个属性

  • colorChecked:组件选中态的背景颜色
  • colorNormal:组件未选中时的默认背景色
  • colorButton:switch中间圆球的颜色
  • width:组件整体宽度
  • height:组件整体高度
  • checked:默认的选中态true/false

以及通过v-model支持checked属性的双向数据绑定,可用于与父组件的变量绑定。

并通过transition样式为组件提供切换动效。

4.2、使用Switch组件

以上实现了一个Switch组件,接下来就可以在任意页面或者组件中引进来使用了。使用方法就是上面介绍的先import进来,然后注册到vue里面就行。

通过以下方法,就可以实现上面动图的效果:

  <div class="page">
    <div class="list-item">
      <FlSwitch v-model="switch1" /><text class="list-item-text">{{switch1Value}}</text>
    </div>
  </div>
</template>
<script>
import FlSwitch from "../packages/switch/index.vue";
export default {
  components: {
    FlSwitch,
  },
  data() {
    return {
      switch1: true,
    };
  },
  computed: {
    switch1Value() {
      return this.switch1 ? 'checked' : 'unchecked';
    },
  }
};
</script>
<style scoped>
.page {
  padding: 30px;
}
.list-item {
  flex-direction: row;
  align-items: center;
}
.list-item-text {
  font-size: 20px;
  margin-left: 30px;
}
</style>

4.3、更多用法

switch组件中定义了一些可定制的属性,在使用时就可以按照组件属性的方式来定制switch显示的样式和事件了:

  <div class="page">
    <div class="list-item">
      <text class="list-item-title">普通样式:</text>
      <FlSwitch v-model="switch1" /><text class="list-item-text">{{switch1Value}}</text>
    </div>
    <div class="list-item">
      <text class="list-item-title">双向绑定:</text>
      <FlSwitch v-model="switch1" /><text class="list-item-text">{{switch1Value}}</text>
    </div>
    <div class="list-item">
      <text class="list-item-title">修改样式:</text>
      <FlSwitch v-model="switch2" colorChecked="red" colorButton="green" colorNormal="#ccc"/><text class="list-item-text">{{switch2Value}}</text>
    </div>
    <div class="list-item">
      <text class="list-item-title">修改大小:</text>
      <FlSwitch v-model="switch3" :width="200" :height="100"/><text class="list-item-text">{{switch3Value}}</text>
    </div>
    <div class="list-item">
      <text class="list-item-title">事件监听:</text>
      <FlSwitch v-model="switch4" @change="switchChange"/><text class="list-item-text">{{switch4Value}}</text>
    </div>
  </div>
</template>
<script>
import FlSwitch from "../packages/switch/index.vue";
export default {
  components: {
    FlSwitch,
  },
  data() {
    return {
      switch1: true,
      switch2: false,
      switch3: false,
      switch4: false,
    };
  },
  computed: {
    switch1Value() {
      return this.switch1 ? 'checked' : 'unchecked';
    },
    switch2Value() {
      return this.switch2 ? 'checked' : 'unchecked';
    },
    switch3Value() {
      return this.switch3 ? 'checked' : 'unchecked';
    },
    switch4Value() {
      return this.switch4 ? 'checked' : 'unchecked';
    },
  },
  methods: {
    switchChange(c) {
      let modal = $falcon.jsapi.modal;
      modal.toast({
        content: 'switchChange ' + c,
        duration: 1000
      });
    }
  }
};
</script>
<style scoped>
.page {
  padding: 30px;
}
.list-item {
  flex-direction: row;
  margin-bottom: 30px;
  align-items: center;
}
.list-item-title {
  font-size: 20px;
  margin-right: 30px;
  width: 100px;
}
.list-item-text {
  font-size: 20px;
  color: red;
  margin-left: 30px;
}
</style>

以上代码就是使用了switch组件不同属性,运行效果如下:

0805c7d9f040327ce1221ec8cda983a5.gif

5、开发者技术支持

如需更多技术支持,可加入钉钉开发者群,或者关注微信公众号

image.png

更多技术与解决方案介绍,请访问阿里云AIoT首页https://iot.aliyun.com/

相关文章
|
4月前
|
小程序 前端开发
2025商业版拓展校园圈子论坛网络的创新解决方案:校园跑腿小程序系统架构
校园跑腿小程序系统是一款创新解决方案,旨在满足校园配送需求并拓展校友网络。跑腿员可接单配送,用户能实时跟踪订单并评价服务。系统包含用户、客服、物流、跑腿员及订单模块,功能完善。此外,小程序增设信息咨询发布、校园社区建设和活动组织等功能,助力校友互动、经验分享及感情联络,构建紧密的校友网络。
135 1
2025商业版拓展校园圈子论坛网络的创新解决方案:校园跑腿小程序系统架构
|
3月前
|
开发者 容器
44.[HarmonyOS NEXT RelativeContainer案例一] 掌握组件锚点布局:打造灵活精准的UI定位系统
在HarmonyOS NEXT的UI开发中,精确控制组件位置是构建复杂界面的关键。RelativeContainer作为一种强大的布局容器,通过锚点系统提供了精确定位能力,使开发者能够创建出灵活且精准的UI布局。本教程将详细讲解如何使用RelativeContainer的锚点布局功能,帮助你掌握这一核心技术。
113 4
|
3月前
|
设计模式 缓存 容器
06.HarmonyOS Next UI进阶:Text组件与视觉样式完全指南
在HarmonyOS Next应用开发中,Text组件是最基础也是最常用的UI元素之一。它不仅用于显示文本内容,还可以通过丰富的样式属性实现各种视觉效果。掌握Text组件的样式设置,是构建精美UI界面的基础技能。
159 1
|
7月前
|
前端开发 安全 开发工具
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
380 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
4月前
|
JSON 监控 小程序
微信百度字节小程序包过大解决方案(实战经验总结)-优雅草卓伊凡|果果|小无
微信百度字节小程序包过大解决方案(实战经验总结)-优雅草卓伊凡|果果|小无
275 14
微信百度字节小程序包过大解决方案(实战经验总结)-优雅草卓伊凡|果果|小无
|
5月前
|
小程序 UED
拓展校友网络的创新解决方案:校园论坛圈子小程序+跑腿+二手市场系统
这是一款基于小程序的校园跑腿服务平台,支持多种注册登录方式、下单支付、跑腿接单配送、订单跟踪评价及物流查询功能,并配备客服模块提升用户体验。系统包含用户、客服、物流、跑腿员和订单五大核心模块,功能完善。此外,平台还拓展了校友网络功能,如信息咨询发布、校园社区建设和活动组织等,旨在增强校友互动与联系,形成紧密的校友生态。
159 4
|
7月前
|
JavaScript 数据安全/隐私保护
Vue Amazing UI 组件库(Vue3+TypeScript+Vite 等最新技术栈开发)
Vue Amazing UI 是一个基于 Vue 3、TypeScript、Vite 等最新技术栈开发构建的现代化组件库,包含丰富的 UI 组件和常用工具函数,并且持续不断维护更新中。另外,组件库全量使用 TypeScript,支持自动按需引入和 Tree Shaking 等,能够显著提升开发效率,降低开发成本。
462 5
Vue Amazing UI 组件库(Vue3+TypeScript+Vite 等最新技术栈开发)
|
9月前
「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件
本篇将带你实现一个自定义天气预报组件。用户可以通过选择不同城市来获取相应的天气信息,页面会显示当前城市的天气图标、温度及天气描述。这一功能适合用于动态展示天气信息的小型应用。
384 38
「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件
|
7月前
|
人工智能 自然语言处理 前端开发
Flame:开源AI设计图转代码模型!生成React组件,精准还原UI+动态交互效果
Flame 是一款开源的多模态 AI 模型,能够将 UI 设计图转换为高质量的现代前端代码,支持 React 等主流框架,具备动态交互、组件化开发等功能,显著提升前端开发效率。
843 1
|
6月前
|
安全 API 开发者
深入探索ArkUI中的@LocalBuilder装饰器:构建高效可维护的UI组件
在ArkUI框架中,组件化开发至关重要。@LocalBuilder作为自API version 12引入的装饰器,专注于组件内部私有构建,确保封装性与安全性。本文解析其工作原理、参数传递机制及与@Builder的区别,结合典型场景代码示例,助开发者掌握这一工具。通过状态驱动UI更新、复杂组件组合等实践,优化性能并提升代码可维护性,推动高效UI架构构建。
163 0