【小程序】实现复用及造轮子入门

本文介绍小程序中template和component的使用方法,通过实例演示如何利用它们实现代码复用,提高开发效率。涵盖自定义弹窗模板及导航栏组件的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 小程序实现可以通过 template 和 component 两种方式实现代码的复用,以减少不必要的工作量。template 被官方称为模块,在 xml 和 css 中定义代码片段,然后可以在其他页面使用,事实上,template 像是复制粘贴的另一种形式,只是把复制粘贴的操作使用 <template> 标签来代替,减少了页面的简洁程度,方便维护(有点像 android 中的 <include> )。比起template, component实现的自定义组件,可以进行自己的逻辑处理,并像官方提供的组件一样去使用。

template 和 component 的不同

  • component 和普通的 page 一样有 xml、css、json 和 js 文件,template 只有 xml 和 css 文件
  • component 可以处理点击事件,tempalte 需要在使用者的 js 中定义
  • template 的动态数据均来自使用者的传递,component 不是
  • 对于 template,在使用者的 css 文件中定义的样式会覆盖模块中定义的样式,而对于 component,app 的样式和使用者的样式均不会影响到组件内部(除非使用externalClasses )
  • component 只能使用类选择器 ,template 没有限制
    ......

template 复用弹窗

 template 通常在复用的部分逻辑处理比较少的情况下使用,如在应用中有一些 UI 一样、但文字内容不一样的提示弹框,这时可以使用 template 来达到复用的目的。

  1. 定义

建立一个目录,在目录下建立 xml 和 css 文件,编辑弹框的 xml 和 css 文件和编辑普通的 page 基本没有什么差别,唯一不同的是在 xml 的最外层需要套上一个 <template> 标签,在该标签中定义 template 的 name 属性,这个 name 属性将成为该弹框的标识。另外 template 中动态数据通过引用者传入。

<!--tip-dialog.wxml-->
<template name="tip-dialog">
    <view class='container'>
        <view class='tip-content'>
            <image class='content-icon' src="{{icon}}"></image>
            <text class='content-text'>{{text}}</text>
        </view>
        <view class='tip-btn' bindtap='clickedBtn'>哦~</view>
    </view>
</template>
复制代码
  1. 使用
  • xml 文件中使用 标签引入模板
<import src="/pages/tip-dialog/tip-dialog"/>
复制代码
  • 使用 <template> 标签指明模板,并传入动态数据,data 属性中的 ... 是展开符号,将 js 中的对象属性展开传递到模板,使模板中可以直接通过属性名称使用,而不是对象.属性
<template is="tip-dialog" data="{{...tipData}}" wx:if="{{showTip}}"/>
复制代码
  • css 文件中使用 @import 引入模板的 css 文件,完成
@import "/pages/tip-dialog/tip-dialog";
复制代码

component 造简单的轮子

 微信从 1.6.3开始支持自定义组件,自定义组件拥有拥有和 page 一样的四个文件,其中 js 文件的结构有一些差异,不过写法基本没什么变化。创建自定义组件的步骤如下:

  • 新建目录,右键建立 component

  • component.json

{
  "component": true
}
复制代码
  • 和编辑普通的页面一样编辑组件,注意是 js 文件的一些差异
    • properties:是组件对外开放的属性,当在使用者 xml 文件中使用该组件时,可以为这些属性传值达到改变组件的目的
    • data:内部数据,和 page 的 data 一样,和 properties 不同的是它是对内的
    • mthods:组件的自定义方法都定义在其内部,亲测定义在外部无法识别
    • externalClasses:组件外部样式,组件内部的样式是不受 app 和 使用者的 css 影响的,如果有组件内部有一些样式希望在使用者使用时才决定,那么久可以通过 externalClasses 去实现
    • behaviors:用于组件间的引用(详情:文档-组件间的关系)
    • 生命周期 :created()、attached()、ready()、moved()、dettach()
  Component({
    //选项
    options: {
      multipleSlots: true // 启用多slot(插槽)支持
    },
    properties: {
      //外部属性
      text: {
        type: String, //类型
        value: 'default value', //默认值
        observer: '方法名' //当数据发生变化时调用
      }
    },
    //外部样式
    externalClasses: ['text-class'],
    data: {
      // 内部数据
      someData: {}
    },
    //生命周期
    attached: function(){},
    moved: function(){},
    detached: function(){},
    methods: {
      // 自定义方法
      customMethod: function(){}
    }
  })
复制代码
  • 使用者 json
{
  "usingComponents": {
      //组件名-路径
      "component-name": "component-path",
  }
}
复制代码
  • 使用者 xml
<component-name property="" />
复制代码

自定义导航栏

 小程序官方提供的导航栏可以控制的部分太少,很多时候并不能满足项目的需求,从 1.9.1 开始,微信开始支持自定义导航栏,这里使用 component 实现一个导航栏。功能如下:

  • 导航栏有标题,返回键,分割线
  • 导航栏高度自适应,标题和返回键始终垂直居中
  • 导航栏可由使用者指定背景颜色或图片
  • 标题的内容和样式对使用者开放
  • 返回键可显示和不显示,按钮的 icon 可由使用者提供,且提供默认 icon,点击可返回上一个界面
  • 分割线可显示和不显示,使用者可决定颜色
    <!--nav-bar.wxml-->
    <view class='nav-container' style='height:{{customeHeight? navHeight:height}}px;background:{{bgColor}};'>
        <image class="nav-background-img" src='{{imageBg}}' style='height:{{height}}px;' mode='top' wx:if="{{useImageBg}}"></image>
        <image class='nav-back' src='{{backIcon}}' wx:if='{{showBack}}' bindtap='clickedNavBarBack'/>
        <view class='nav-title-view' style='margin-bottom: {{marginB}}rpx;'>
            <view class='nav-title-class'>{{title}}</view>
        </view>
        <view class='nav-line' style='background-color:{{lineColor}};' wx:if="{{showLine}}"></view>
    </view>
复制代码

tips:

  • 不使用 externalClasses 的情况下,组件使用者 css 不能覆盖组件中的 css
  • 在使用 externalClasses 的情况下,组件内部 xss 中对于该 class 样式失效,但是 wxml 中 style 属性指定的样式仍有效
    //nav-bar.js
    Component({
        externalClasses: ['nav-title-class'],
        properties: {
            //指定导航栏高度,不指定将使用默认的计算方式
            navHeight: {
                type: Number,
                value: -1,
                observer: 'navHeightChange'
            },
            //导航栏标题
            title: {
                type: String,
                value: "VUI"
            },
            //是否显示返回键
            showBack: {
                type: Boolean,
                value: true
            },
            //背景颜色,默认 #fff
            bgColor: {
                type: String,
                value: ''
            },
            //背景图片,默认不使用,使用后将覆盖掉背景颜色
            imageBg: {
                type: String,
                value: '',
                observer: 'imageBgChange'
            },
            //指定返回按钮的 Icon
            backIcon: {
                type: String,
                value: DEFAULT_BACKICON
            },
            //导航栏底部分割线颜色 
            lineColor: {
                type: String,
                value: "#ccc"
            }, 
            //是否显示底部分割线
            showLine: {
                type: Boolean,
                value: true
            }
        },
        data: {
            height: 64,
            useImageBg: false,
            customHeight: false,
            marginB: 10
        },
        created: function() {
            _this = this
        },
        /**
         * ready 开始可以获得控件信息
         */
        ready: function() {
            let height = _this.getNavBarHeight()
            _this.calculatePosition(height)
        },
        methods: {
            clickedNavBarBack: function() {
                console.log("navBar.clikedBack()")
                wx.navigateBack({})
                //使用者可以绑定这个方法来监听返回键点击事件(bindtapBack)
                this.triggerEvent("tapBack")
            },
            calculatePosition: function (height) {
                let sys = wx.getSystemInfoSync()
                let query = wx.createSelectorQuery().in(this)
                query.select(".nav-title-view").boundingClientRect()
                query.exec(function (rects) {
                    let titleH = rects[0].height
                    let realH = height - sys.statusBarHeight
                    let marginB = (realH - titleH) / 2  
                    _this.setData({
                        height: height,
                        marginB: marginB
                    })
                })
            },
            getNavBarHeight: function () {
                let height = 64
                let res = wx.getSystemInfoSync();
                let system = res.system
                if(system.search('android') != -1) {
                    height = 68
                } else {
                    let model = res.model
                    if (model.search('iPhone X') != -1) {
                        height = 88
                    } else if (model.search('iPad') != -1) {
                        height = 100
                    }
                }
                return height
            },
            navHeightChange: function (newVal, oldVal) {
                _this.setData({
                    customeHeight: true
                })
            },
            imageBgChange: function(newVal, oldVal) {
                if(newVal != '') {
                    _this.setData({
                        useImageBg: true
                    })
                }
            }
          
        }
    })
复制代码

对于标题栏高度,使用 px 作为单位,android 统一为 68,iPhone X 为 88,iPhone 其他为 64。对于居中,首先将标题和返回按钮固定在导航栏底部,然后计算 margin-bottom 的值(导航栏高度包括了状态栏的高度)。

    <!-- index.wxml -->
    <nav-bar show-back="{{true}}" title="VUI" nav-title-class="nav-title-class" line-color="#aaa" showLine="{{showNavLine}}"  bindtapBack="tapBack"></nav-bar>
复制代码

效果:

++:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值