第三章:豆瓣项目之登录、我的

创建项目

  1. 打开“微信开发者工具”->点击“+”新建项目,选择项目路径、项目名称(豆瓣评分)、设置AppID、选择不使用云服务、语言选择JavaScript,创建即可
  2. 打开VSCode
    1. 点击文件->打开…->找到“豆瓣评分”->打开
  3. VSCode写的代码怎么直接运行到“微信开发者工具”的模拟器上呢?
    1. “微信开发者工具”做的比较智能,一旦项目中任何文件改变,就会自动刷新模拟器
    2. 即写完代码一旦保存就会自动刷新模拟器
    3. 模拟器脱离出来:模拟器右上角有个图标“分离窗口”,点击之后模拟器就可以直接脱离出来
    4. 然后点击“钉”图标,让他永远显示在桌面最上层
  4. 本节要开发的页面如下

pic

开发登录页面

登录整体配置

  1. 在项目文件目录pages下面,新建一个目录文件夹“login”
  2. 在login文件夹下新增4个文件
    1. 打开“微信开发者工具”,右击login文件夹->“新建 Page”->输入名称为login,这样就会自动生成4个login的文件,后缀分别为:js、json、wxml、wxss
    2. 创建完继续回到VSCode继续开发
  3. 打开app.json文件,删除默认的index、logs路径

     "pages": [
     "pages/login/login"
     ],
    
    1. 然后右击index、logs文件目录,删除这两个文件移动到废纸篓
    2. 保存,此时打开模拟器显示的是

       pages/login/login.wxml
      
  4. 删除掉app.wxss文件中设置的全局样式代码
  5. 导入项目中使用的图片
    1. 在项目根目录文件夹新建一个“assets” 文件夹
    2. 然后在改文件夹下面建一个imgs文件夹,将图片全部放入
    3. 注意:上面两步都是在finder中手动建立,项目中会自动同步

登录页面搭建

login.wxml文件添加控件

  1. 注释掉login.wxml文件的初始化代码
  2. 背景图片实现方案
    1. 用view视图,然后设置背景图片

       //用view做背景
       <view class="logo">
       </view>
              
       //css设置背景图片
       .logo {
           /* 在微信小程序中背景图片不能使用本地图片来写 ,url()只能放远程地址*/
           background-image: url(http://www.xxx/xxx.png);
       }
      
      1. 在小程序中,背景图片无法使用本地URL,代替方案有
        1. 用远程URL
        2. 将本地图片转成 Base64 编码:http://imgbase64.duoshitong.com/然后直接放入url()
    2. 直接用一个image视图来做背景图片

  3. 最终代码如下:

     <!--pages/login/login.wxml-->
     <!-- <text>pages/login/login.wxml</text> -->
     <!-- 
         注意:直接输入view,然后回车就好,不要输入<view...
         微信小程序中没有div,只有view
      -->
      <!-- 搞一个大容器来容纳所有的元素 -->
      <view class="container">
        
        <!-- icon 图片部分 -->
        <!-- 方法1: 用view然后设置背景图片 -->
        <!-- <view class="logo"></view> -->
        <!-- 方法二: 直接用image做背景图片 -->
        <!-- 相对路径来找img地址 -->
        <!-- <image class="logo" src="../../assets/imgs/ic_launcher.png"></image> -->
        <!-- 通过绝对路径来找 -->
        <image class="logo" src="/assets/imgs/ic_launcher.png"></image>
        
        <!-- 登录部分  -->
        <!-- bindtap绑定事件 -->
        <view class="wechat login-btn" bindtap="wechatLogin">微信登录</view>
        <view class="douban login-btn" bindtap="doubanLogin">已有豆瓣帐号登录</view>
        <!-- 底部协议 -->
        <view class="agreement">
           登录表示同意
           <view class="open" bind:tap="agreement">豆瓣使用协议/隐私协议</view>
        </view>
      </view>
    

login.wxss文件添加样式

/* pages/login/login.wxss */

.container {
    /* 使用flex布局 */
    display: flex;
    /* 设置主轴方向 */
    flex-direction: column;
    /* 设置交叉轴居中 */
    align-items: center;
    /* 设置内边距 */
    padding: 0 60rpx;
}

.logo {
    /* 在微信小程序中背景图片不能使用本地图片来写 ,url()只能放远程地址*/
    /* background-image: url(/assets/imgs/bg_mine_login.png); */
    /* 设置图片大小 */
    width: 144rpx;
    height: 144rpx;
    /* 设置边距 */
    margin: 60rpx 0;
}
/* 登录按钮的统一样式 */
.login-btn {
    height: 80rpx;
    width: 100%;
    /* 内容居中 */
    line-height: 80rpx;
    text-align: center;
    /* 圆角 */
    border-radius: 10rpx;
}
.wechat {
    background-color: rgb(27, 172, 35);
    color: white;
}
.douban {
    background-color: white;
    color: rgb(27, 172, 35);
    border: 2rpx solid rgb(27, 172, 35);
    margin-top: 30rpx;
}

/* 协议 */
.agreement {
    color: gray;
    font-size: 30rpx;
    display: flex;
    /* 绝对布局 */
    position: absolute;
    bottom: 50rpx;
}
.agreement .open {
    color: rgb(27, 172, 35);
    margin-left: 15rpx;
}

login.js文件添加事件

  1. 删除掉Page({ })中的所有默认代码
  2. 注意:js里面字符串用单引号,其他用双引号
// pages/login/login.js
Page({

  // 点击事件
  wechatLogin: function() {
    console.log('wechatLogin')
  },
  doubanLogin: function() {
    console.log('doubanLogin')
  },
  // 点击协议
  agreement: function() {
    console.log('agreement')
    // 页面跳转
    wx.navigateTo({
      url: '/pages/agreement/agreement',
      // 跳转成功
      success: (result) => {
        
      },
      // 失败
      fail: () => {},
      // 结束
      complete: () => {}
    });
      
  }
})

login.json文件添加

  1. 在该文件中设置导航栏的标题
{ 
  "navigationBarTitleText": "登录"
}

关于小程序内打开网页

  1. 目前来说,个人类型的小程序暂不支持使用
  2. 先在小程序官网后台【开发-开发设置-业务域名】添加需要打开的链接,再使用 web-view 组件显示网页
  3. 否则不能使用web-view 组件打开网页

我的页面开发

  1. 新建profile文件夹,以及相应模块
  2. 打开app.json文件修改,将pages中的profile加载设置为第一个,然后开发“我的页面”

     "pages": [
         "pages/profile/profile",
         "pages/login/login",
         "pages/agreement/agreement" 
     ],
    

技术知识点

数据绑定

  1. 目的:如何将数据动态的绑定的控件上去。
  2. 在当前模块的js文件中(比如profile.js)的data方法,就是绑定页面数据的方法
  3. 微信小程序渲染的数据必须放在data中
  4. 使用举例:
    1. js文件数据初始化

       // pages/profile/profile.js
       Page({
              
         /**
          * 页面的初始数据
          * 用来放动态绑定的数据
          */
         data: {
           name:'jack',
           age: 10,
           info:{
             address: '广州',
             salary: 2000
           },
           arr:[10,20,30],
           nums: [11,12,13]
         }
       })
      
    2. wxml 控件使用

       <view>
           <!-- *{ 直接取值 }} : 这种语法叫mustache语法 -->
           我的名字是:*{ name }},年龄是:*{ age }},城市: *{ info.address }},数组:*{ arr[2] }}
       </view>
      

for循环

  1. 查看官方文档“列表渲染”
  2. 举例:

     <!-- 查看官方文档“列表渲染” -->
     <!-- for循环数组nums,每个元素叫num,每个下标叫idx-->
     <view wx:for="*{ nums }}" wx:for-item="num" wx:for-index="idx">
         位置为*{ idx }} 的元素是 *{ num }}
     </view>
     <!-- 系统默认每个元素叫item,每个下标叫:index -->
     <view wx:for="*{ nums }}">
         位置为*{ index }} 的元素是 *{ item }}
     </view>
     <!-- 直接定义一个数组 -->
     <view wx:for="*{ [100,101,102] }}">
         位置为*{ index }} 的元素是 *{ item }}
     </view>
    
     <!-- block使用: 直接输入block回车即可 -->
     <block wx:for="*{nums}}">
         位置为*{ index }} 的元素是 *{ item }}
     </block>
    
  3. 效果: pic

    1. view与block的区别
      1. view循环: 会拷贝n个view控件
      2. block循环:只会拷贝n个blcok内容

for循环中点击控件,如何在点击事件中拿到相应的控件?

  1. wxml文件中for循环中的item控件,添加点击事件:

     <view wx:for="*{ items }}" class="items" wx:key="unique">
         <!-- bind:tap 添加点击事件 -->
         <view data-abc = "123" data-def ="234" data-index = "*{index}}" id="item-*{index}}" class="right" bind:tap="begin">     
         </view>
     </view>
    
    1. 2种方法:
      1. 方法1: 在控件中设置id属性,然后通过evt.currentTarget.id获取
      2. 方法2:自定义属性:data-*
        1. id、class等都是系统自带的属性,我们也可以自定义属性
        2. 上面自定义2个属性: abc、def,内容为123,234
  2. js中添加实现点击响应:

     begin:function (evt) {
         /*
         如何拿到点击控件的索引?
         1. 在控件中设置id属性,然后通过evt.currentTarget.id获取
         2. 通过 data-* 设置自定义属性,自定义一个index属性:data-index = "*{index}}"
          */
         // console.log(evt.currentTarget.id)
         console.log(evt.currentTarget.dataset.index)
     }
    

我的页面搭建

profile.json文件

{
  "navigationBarTitleText": "书影音档案"
}

profile.wxml文件

<!--pages/profile/profile.wxml-->
<!-- <text>pages/profile/profile.wxml</text> -->
<view class="container">
    <!-- 将版本与其他分割成2块 -->
    <view> 
        <view class="login-wrapper">
            <view class="login">登录</view>
            <!-- mode;图片展示的额样式,是否拉伸等 -->
            <image  src="/assets/imgs/bg_mine_login.png" mode="scaleToFill"/>
            
        </view>
        <view class="items-wrapper">
            <view class="title-wrapper">
                <view class="title">我的书影音</view>
                <view class="view">
                    登录查看
                    <view class="arrow"></view>
                </view>
            </view>
            <!--
            for循环
            wx:key="unique" :防止警告
            -->
            <view wx:for="*{ items }}" class="items" wx:key="unique">
                <view class="item">
                    <image class="icon" src="/assets/imgs/*{item.icon}}" />
                    <view class="info-wrapper">
                        <view class="info">
                            <view class="left">
                                <view class="top">*{item.title}}</view>
                                <view class="bottom">
                                    <view class="count">*{item.count}}</view>
                                    *{item.has}}
                                </view>
                            </view>
                            <!-- 
                                bind:tap 添加点击事件 
                                data-* :自定义属性
                                    id、class等都是系统自带的属性,我们也可以自定义属性
                                    <view data-abc = "123" data-def ="234">  </view>
                                    自定义2个属性: abc、def,内容为123,234
                            -->
                            <view data-abc = "123" data-def ="234" data-index = "*{index}}" id="item-*{index}}" class="right" bind:tap="begin">
                                <!-- text 可以识别换行符号\n -->
                                <text class="text">*{item.mark}}</text>
                                <view class="begin">立即开启</view>
                                <view class="arrow"></view>
                            </view>
                        </view>
                        <!-- 
                            下划线:
                            实现最后一行不显示下划线:
                            1. 通过css属性
                                /* 找到最后一个item,隐藏下划线 */
                                .items:last-child .line { 
                                /* 隐藏,但是仍有改下划线,只是透明的 */
                                /* visibility: hidden; */
                                /* 直接没有该下划线 */
                                display: none; 
                                }
                            2. 通过if条件句 
                            wx:if="*{ }}" 条件控制 ,最后一个item不显示下划线
                        -->
                        <view wx:if="*{ index < items.length-1 }}" class="line"></view>
                    </view>
                    
                </view>
            </view>
            
        </view>
    </view>

   <view class="verson">版本 1.0.39</view> 
</view>

profile.js文件

// pages/profile/profile.js
Page({

  /**
   * 页面的初始数据
   * 用来放动态绑定的数据
   */
  data: {
    items: [
      {
        icon: 'ic_cat_movie.png',
        title: '观影分析',
        count: 0,
        has: '看过',
        mark: '录10部影片\n开启观影分析'

      },
      {
        icon: 'ic_cat_book.png',
        title: '读书分析',
        count: 0,
        has: '读过',
        mark: '标记10本书\n开启读书分析'

      },
      {
        icon: 'ic_cat_music.png',
        title: '音乐分析',
        count: 0,
        has: '听过',
        mark: '记录10张唱片\n开启音乐分析'

      },
    ]
  },
  begin:function (evt) {
    /*
    如何拿到点击控件的索引?
    1. 在控件中设置id属性,然后通过evt.currentTarget.id获取
    2. 通过 data-* 设置自定义属性,自定义一个index属性:data-index = "*{index}}"
     */
    // console.log(evt.currentTarget.id)
    // console.log(evt.currentTarget.dataset.index)
   const idx = evt.currentTarget.dataset.index;
   if(idx == 0){
      console.log('观影分析')
   }else if (idx == 1){
      console.log('读书分析')
   }else if (idx == 2){
      console.log('音乐分析分析')
   }
  }
})

profile.wxss文件

/* pages/profile/profile.wxss */
/* 为了是page大小正好充满屏幕,否则默认包裹子控件大小 */
page {
    height: 100%;
}
/*
将版本号与其他分成2块 ,然后设置space-between
 */
.container {
    /* 给页面设置一个统一的字体大小 */
    font-size: 28rpx;
    display: flex;
    flex-direction: column;
    /* 这一步必须将父控件page设置尺寸为手机屏幕尺寸才有效 */
    justify-content: space-between;
    height: 100%;
}
/*
版本适配:
1. 如果使用 absolute,那么版本就是悬浮在页面底部,当数据过多时,就不行了
2. 所以版本必须是跟随底部的,因此使用上面的方法
 */
.verson {
    /* position: absolute;
    bottom: 30rpx; */
    color: gray;
    font-size: 24rpx;
    width: 100%;
    text-align: center;
    margin-bottom: 30rpx;
}
.login-wrapper {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 500rpx;
    /* 父相: 注意!!!! */
    position: relative;
}

.login-wrapper .login {
    color: #1e4826;
    background-color: white;
    border-radius: 50rpx;
    font-size: 50rpx;
    height: 100rpx;
    line-height: 100rpx;
    width: 500rpx;
    text-align: center;
    /* 设置阴影 */
    box-shadow: 2rpx 2rpx 2rpx 0 rgba(0, 0, 0, 1);
}

/* 注意:1. 让图片脱离布局 2. 让图片位于“登录”下一层 */
.login-wrapper image {
    /* 脱离布局,并设置称为背景 */
    /* 子绝 */
    position: absolute;
    left: 0;
    top: 0;
    /* 设置层次:z轴最底层*/
    z-index: -1;
    width: 100%;
    /* 注意:一定要在父控件设置相对定位:position: relative;,否则默认的相对控件为整个屏幕 */
    height: 100%;
}

.items-wrapper {
    margin-top: 30rpx;
}

.title-wrapper {
    padding-left: 30rpx;
    padding-right: 40rpx;
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 20rpx;
}
.title-wrapper .title {
    font-weight: bold;
    font-size: 36rpx;
}
.title-wrapper .view {
    color: gray;
    display: flex;
    align-items: center;
}

/* 模拟一个箭头 */
.items-wrapper .arrow {
    width: 20rpx;
    height: 20rpx;
    border: 4rpx solid gray;
    border-left: none;
    border-top: none;
    transform: rotate(-45deg);
    margin-left: 10rpx;
}
.item {
    display: flex;
    align-items: center;
    padding-left: 30rpx;
    padding-right: 20rpx;
    margin-top: 20rpx;
    /* 设置item里面所有文字的默认大小 */
    font-size: 28rpx;
}
.item .icon {
    width: 108rpx;
    height: 108rpx;
    margin-right: 30rpx;
}
/* 找到最后一个item,隐藏下划线 */
/* .items:last-child .line { */
    /* 隐藏,但是仍有改下划线,只是透明的 */
    /* visibility: hidden; */
    /* 直接没有该下划线 */
    /* display: none; */
/* } */

/* 让当前控件填充父元素 */
.info-wrapper {
    /* 方法1 */
    /* width: 100%; */
    /* 方法2: */
    /* flex布局中的最后一个布局属性:flex */
    /* flex: 1; */
    /* 等价于:flex-grow: 1 */
    flex-grow: 1;
    padding-right: 20rpx;
}
.info-wrapper .info {
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.info .left .bottom {
    display: flex;
    color: #818181;
    align-items: center;
}
.info .left .top {
    margin-bottom: 10rpx;
    font-size: 32rpx;
}

.info .count {
    font-size: 60rpx;
    font-weight: bold;
    margin-right: 10rpx;
}
.info .right {
    display: flex;
    align-items: center;
}

.info .right .text {
    color: gray;
    margin-right: 10rpx;
}

.info .right .begin {
    color:  #4a4a4a;
    background-color: #f5f5f5;
    padding: 10rpx 15rpx;
}
.item .line {
    width: 100%;
    height: 2rpx;
    background-color: rgba(0, 0, 0, 0.2);
    margin-top: 15rpx;
}
Table of Contents