美文网首页
微信小程序:自定义组件-自定义导航栏,动态适配高度,数据传递

微信小程序:自定义组件-自定义导航栏,动态适配高度,数据传递

作者: YYFast | 来源:发表于2020-05-06 20:46 被阅读0次

    1. 自定义组件

    在微信小程序的开发中,经常需要在不同的地方使用一些相同的组件,这些组件的样式,数据,以及点击事件都是相同的,所以,可以微信提供了自定义组件的方式,可以将我们经常使用的组件封装起来,可以使得开发效率更高,让我们对于小程序的开发更加的深刻.
    自定义组件官方文档
    新建一个组件对应以下几个步骤:

    1. 新建一个专门用于存放组件的文件夹,可以命名为cmps(命名可以随意)
    2. 在cmps文件夹下,新建文件夹及组件Component(注意不是新建Page);�


      image.png
    1. 和新建page一样,组件也有4个对应的文件,分别是js,json,wxml,wxss.
      注意:微信官方的命名一般使用的中横线隔开,例如movie-item,所以命名的时候规则尽量与官方的一致.

    2. 自定义组件的封装和使用

    以我此次学习封装的movie-item为例,将整个的item的wxml,wxss,js等代码移动到对应的movie-item文件中,此处不再赘述,其中需要注意的是一些布局的代码,有些布局,例如item的宽度,这些在内部就可以写好,在外部的代码就可以直接删除:


    image.png

    2.1 组件的使用

    在封装以后可以预先编译一下看看封装是否能达到效果,组件的使用如下:

    • 在需要使用组件的page的.json文件中,加入以下代码:
    {
      "usingComponents": {
        /* key:value   key是组件的命名,一般和原有名称相同,value是组件的路径*/
        "movie-item":"/cmps/movie-item/movie-item"
      }
    }
    
    • 在wxml中直接使用movie-item标签:
    <movie-item 
        class="item"
        wx:key="unique" 
        wx:for="{{ row.movies }}" 
        wx:for-item="movie"
        movie="{{movie}}">
    </movie-item>
    
    

    在封装以后可以编译一下看到效果:

    image.png

    所以到这里封装成功了一小半,接下来需要将数据传给每个对应的item就行;

    2.1 数据的处理:属性

    当我们在封装好一个component后,这个组件需展示外部赋值的数据,在component.js文件中,有一个对应的properties可以用来传递参数赋值:
    属性的定义如下:
    命名:{ type:类型(String,Number,Object等),value:默认值(选填)}

    Component({
      properties: {
        // 这里定义了innerText属性,属性值可以在组件使用时指定
        innerText: {
          type: String,
          value: 'default value',
        },
        movie:{
            type:Object,
            value:null
          }
      },
      data: {
        // 这里是一些组件内部数据
        someData: {}
      },
      methods: {
        // 这里是一个自定义方法
        customMethod: function(){}
      }
    })
    
    

    传递过来的movie的赋值给图片等东西以后,自定义组件的逻辑就实现了一半了,接下来就是实现点击事件等的添加;

    2.2 点击事件的添加

    例如我封装的每个movie-item,在不同的页面响应的事件应该是相同的,跳转的都是电影详情;
    事件绑定

    1. wxml文件中先绑定事件:
    <view class="item" bindtap="enterDetail"></view>
    

    在自定义的组件中,以我自定义的movie-item为例,在.js文件中,有一个methods方法:

    /**
     * 组件的方法列表
     */
    methods: {
       enterDetail:function(){
         wx.navigateTo({
           url: `/pages/detail/detail?title=${this.data.movie.title}`,
         });
       }
    }
    

    3. 页面间的数据传递

    在由movie-item跳转到电影详情detail的时候,需要将电影信息传递到detail页面,数据的传递有以下几种方式:

    3.1 存储和读取

    使用setStorage和getStorage方法,在进入页面之前通过电影名将电影信息存储起来,进入到电影页面通过电影名读取电影信息;

    3.2 通过页面跳转url后拼接参数传递

    页面跳转的url后面可以拼接参数:
    注意:

    • url后面的参数拼接只能是字符串,例如:

      url: /pages/detail/detail?title=${this.data.movie.title},

    • 不能直接将movie对象直接拼接到url后面;

    另一种做法是将movie对象转化为json字符串,然后,在detail页面中将字符串转成对象:
    JSON和对象互转用法:JSON.stringify和JSON.parse

    methods: {
            enterDetail:function(){
             // 序列化:将JSON对象转换为JSONString
             // 反序列化:将JSONString转换为JSON对象
              wx.navigateTo({
                url: `/pages/detail/detail?movie=${JSON.stringify(this.data.movie)}`,
              });
            }
     }
    
    

    在detail页面的js文件onload方法中将参数转化为movie对象:

    /**
      * 生命周期函数--监听页面加载
      */
     onLoad: function (options) {
           console.log(options);
           let movie = JSON.parse(options.movie);
           console.log(movie);
       
           wx.setNavigationBarTitle({
             title: movie.title,
           }); 
     },
    
    

    打印url,options和movie对象如下:


    image.png

    3.3 使用eventChannel双向传递数据

    在微信官方文档中链接,传递数据和监听打开页面事件响应使用了eventChannel,这是一个双向的channel, 使用起来也比较方便,所以相比较前两种方法,这种更适合页面间较大数据,对象等的传递,简单的值传递使用url拼接参数就可以实现. 以下是实现代码示例:

    movie-item.js中的代码:

    methods: {
        enterDetail:function(){
          wx.navigateTo({
            url: '/pages/detail/detail',
            success: (result) => {
              //通过eventChannel向被打开的页面传递数据
              result.eventChannel.emit('sendDataToDetail',{data:this.data.movie});
            },
    
            events: {
              // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
              acceptDataFromOpenedPage: function(data) {
                console.log(data)
              },
              someEvent: function(data) {
                console.log(data)
              }
            },
            fail: () => {},
            complete: () => {}
          });
        }
      }
    
    

    跳转页面detail.js中的代码:

    /**
       * 生命周期函数--监听页面加载
       */
      onLoad: function (options) {
        const eventChannel = this.getOpenerEventChannel();
        // 监听acceptDataFromOpenerPage事件,获取上一页面通过eventChannel传送到当前页面的数据
        eventChannel.on('sendDataToDetail',function(data){
          console.log(data);
        });
        
        //向上一级页面返回数据
        eventChannel.emit('acceptDataFromOpenedPage',{data:'sentBackTest'});
        eventChannel.emit('someEvent', {data: 'test'});
          
      },
    
    

    打印如下:


    image.png

    还有很多传递数据的方式,比如可以在app.json中,给某个全局的对象如wx.db定义一个movie对象,每次在页面跳转前给这个对象赋值等.

    实际上只要能实现传递数据的效果的方法都可以,但是,如果后期要增加多个数据或者对象,使用url拼接的方式就会显得很复杂,使用eventchannel的方式后期增加参数没有压力,所以视开发需求情况而定;

    4. 自定义导航栏

    导航栏设置:在开发中有时候需要设置导航栏颜色,title,动画,字体颜色等,如果使用的是系统的导航栏,这些官方都提供了api可以直接设置.

    但是在实际开发过程中,有时候系统的导航栏很大可能不能满足我们开发的需求;


    image.png

    比如:在页面多次跳转以后,需要在导航栏上加上一个可以返回首页的按钮,这种情况下系统导航栏没有给我们提供api,也没有对应的组件,这时候就需要我们自定义导航栏来实现;

    4.1 自定义导航栏需要实现的功能

    • 可以展示系统导航栏没有的子控件,并且可以控制在不同页面展示和隐藏;
    • 适配不同机型问题:
      • 在有刘海的设备上:例如iPhone X,华为等,状态栏高度不一样,需要动态设定;
      • android设备navBar的高度是48,iOS设备navBar的高度是44,也需要动态设定;
    • 提供api给外界设置title,color,font等样式.

    自定义导航栏方式:

    1. 在app.json中设置navigationBarStyle为custom,这样每个界面的导航栏就消失了,然后需要在每个界面自己添加自定义的导航栏


      系统导航栏

    全局配置: 未配置默认样式是default, 配置样式custom(自定义)以后,如图所示,搜索框的起始位置是从0开始的,在未配置以前是从导航栏的底部开始的.

    "window": {
        "navigationStyle":"custom"
      },
    
    系统导航栏隐藏后

    4.2 获取状态栏高度

    获取系统信息

    可以在app.js中,通过wx.getSystemInfoSync()方法获取设备的信息


    image.png
    const info = wx.getSystemInfoSync();
        wx.db.statusBarHeight = info.statusBarHeight;
        if(info.system =='android'){
          wx.db.navBarHeight = 48;
        }else{
          wx.db.navBarHeight = 44;
        }
    

    4.3 导航栏的封装和实现

    和movie-item一样,创建一个nav-bar组件,然后对应子控件,属性等,以下是具体代码.

    wxml中的代码如下:

    • 通过设置style来动态设置statusBar和navBar的高度;
    • 通过wx:if判断属性值控制back和home是否展示
    <view class="container">
      <view class="status-bar" style="{{statusBarStyle}}">    
      </view>
      <view class="nav-bar" style="{{navBarStyle}}">
        {{title}}
        <view class="icons">
        <image bindtap="backClick" wx:if="{{ back == 'true' }}" class="back" src="/assets/imgs/nav_back.png"></image>
        <image bindtap="homeClick" wx:if="{{ home == 'true' }}" class="home" src="/assets/imgs/nav_home.png"></image>
        </view>
      </view>  
    </view>
    

    wxss中的代码如下:

    • back和home居左,使用了相对和绝对布局;
    • statusBar和navBar的高度通过wxml中的style设定;
    .nav-bar{
        display: flex;
        justify-content: center;
        align-items: center;
        position: relative;
    }
    
    .icons{
        position:absolute;
        left: 25rpx;
        display: flex;
        align-items: center;
    }
    
    .home{
        height: 36rpx;
        width: 36rpx;
    }
    
    .back{
        height: 36rpx;
        width: 36rpx;
        margin-right: 20rpx;
    }
    

    js中的代码如下:

    • 在属性列表中的属性也可以通过this.data.xxx来获取;
    • 返回上一级页面和home,可以设置wx.navgateBack()中的delta值来判断,(微信页面的层级最多10层,所以返回home,可以设置一个很大的数字);
    • 在具体的页面想要监听返回和返回首页,可以使用this.triggerEvent来实现;
    • 动态设置状态栏和导航栏的高度,在组件的声明周期lifetimes中,在组件即将被加载时设置,然后使用this.setData()方法刷新;
    Component({
      /**
       * 组件的属性列表
       */
      properties: {
        title:{
          type:String,
          value:"豆瓣评分"
        },
        back:{
          type:String,
          value:"true"
        },
        home:{
          type:String,
          value:"false"
        },
        statusBarColor:{
          type:String,
          value:'#fff'
        },
        navBarColor:{
          type:String,
          value:'#fff'
        }
      },
    
      /**
       * 组件的初始数据
       */
      data: {
        statusBarStyle:'',
        navBarStyle:''
    
      },
    
      /**
       * 组件的方法列表
       */
      methods: {
        backClick:function(){
          this.triggerEvent('backTap');
           wx.navigateBack({
             delta: 1
           }); 
        },
        homeClick:function(){
          this.triggerEvent('homeTap');
          wx.navigateBack({
            delta: 999
          });
        }
      },
    
      lifetimes: {
        attached: function() {
          const statusBarStyle=`height:${wx.db.statusBarHeight}px;background-color:${this.data.statusBarColor}`;
          const navBarStyle=`height:${wx.db.navBarHeight}px;background-color:${this.data.navBarColor}`;
          this.setData({statusBarStyle,navBarStyle});
        },
        detached: function() {
          // 在组件实例被从页面节点树移除时执行
        },
      },
    })
    
    

    不同页面样式的导航栏如下:

    首页-没有back没有home list-没有home detail-back和home都有

    前端的开发都是相通的,这一点从自定义组件可以看出来,对与系统提供的组件不能满足需求时,通过自己的封装,不仅能够实现需求,更能在开发的工程中收获满满.

    相关文章

      网友评论

          本文标题:微信小程序:自定义组件-自定义导航栏,动态适配高度,数据传递

          本文链接:https://www.haomeiwen.com/subject/uodyghtx.html