微信小程序云开发

开通Cms可视化网页管理后台

我们上面源码导入成功,并把云开发环境初始化成功以后,接下来就来开通cms可视化网页后台,现在cms与云环境还是单向的,即cms同步到云上,但云同步不到cms中(导入数据除外),所以数据库我们还是要在cms中初始化好。
如下图两张所示,直接点击开通内容管理(CMS)即可,两个位置点开
image.png
image.png
添加账号与密码
image.png
登陆cms
image.png
image.png
创建项目,进入xiongshaowen651后
image.png
image.png
image.png
点击内容模型—新建模型,会在云数据库中看到xsw表了。
image.png
image.png
添加字段举例
image.png

注意:在云环境后台的云数据库中添加的记录或修改记录,不会同步到CMS中,但cms中添加记录或修改记录会同步到云环境后台中
image.png
##小程序与cms通信
------实际上我们用得最多还是数据库,也就是说,操作cms建立的数据,与直接访问数据库一样,首先到云环境后台设置操作权限。
image.png

// pages/testcms/testcms.js
Page({
  onLoad:function(options){
    wx.cloud.database().collection("news").get()
    .then(res=>{
      console.log("新闻列表",res)
     this.setData({
        list:res.data
      })
    })
  }
   
})

//xxx.wxml
<view wx:for="{{list}}">
   <view>{{item.title}}</view>
 <image src="{{item.img}}"></image>
</view>

image.png
image.png

使用cms问题

1.导入内容模型(数据表)

------新升级的小程序开发工具,同时也升级了cms,现在新的cms只可导入5张表,并具不可同步到云环境后台,当然了这是要交钱才可以的,但我不想交钱呀!
image.png
image.png

[{"fields":[{"dateFormatType":"timestamp-ms","description":"系统字段,请勿随意修改","displayName":"创建时间","id":"_createTime","isSystem":true,"name":"_createTime","type":"DateTime"},{"dateFormatType":"timestamp-ms","description":"系统字段,请勿随意修改","displayName":"修改时间","id":"_updateTime","isSystem":true,"name":"_updateTime","type":"DateTime"},{"displayName":"图片","id":"n1ywhthvr3pywyldiyzjonjzrigsueub","name":"picUrl","order":2,"resourceLinkType":"fileId","type":"Image"}],"collectionName":"lunbotu","displayName":"轮播图","description":"首页顶部轮播图,推荐热门菜品","_id":"b00064a7602371f8040333e766175a2e"},{"fields":[{"displayName":"菜品分类","enumElementType":"string","enumElements":[{"label":"店长推荐","value":"店长推荐"},{"label":"新品推荐","value":"新品推荐"},{"label":"活动推荐","value":"活动推荐"},{"label":"经典套餐","value":"经典套餐"},{"label":"粥品汤类","value":"粥品汤类"},{"label":"面食","value":"面食"},{"label":"酒水饮料","value":"酒水饮料"},{"label":"主食主菜","value":"主食主菜"}],"id":"zt5mivizg4tgdof0pp9q9d5roes6ke55","isRequired":true,"name":"fenlei","order":0,"type":"Enum"},{"displayName":"菜品名","id":"64e29ko0o0ycdduknshj6p5558g2kpa5","name":"name","order":1,"type":"String"},{"displayName":"菜品价格","id":"4iroi681tok4tr34ebwa9w0npnevu3ng","name":"price","order":2,"type":"Number"},{"displayName":"菜品上架状态","enumElementType":"string","enumElements":[{"label":"上架","value":"上架"},{"label":"下架","value":"下架"}],"id":"zr8p3hej61dtertt9d756fsdjt919fnq","name":"status","order":3,"type":"Enum"},{"defaultValue":0,"displayName":"销量","id":"kn2i058g3vsq8ygf8otj7h7u99ep119b","name":"sell","order":4,"type":"Number"},{"displayName":"菜品图片","id":"wmmq6qxra3bjsp2t9239l6zq6v6s0m34","name":"icon","order":5,"resourceLinkType":"fileId","type":"Image"},{"dateFormatType":"timestamp-ms","description":"系统字段,请勿随意修改","displayName":"创建时间","id":"_createTime","isSystem":true,"name":"_createTime","type":"DateTime"},{"dateFormatType":"timestamp-ms","description":"系统字段,请勿随意修改","displayName":"修改时间","id":"_updateTime","isSystem":true,"name":"_updateTime","type":"DateTime"}],"collectionName":"food","displayName":"菜品","description":"菜品数据","_id":"79550af26023746d03d8630759fc5694"},{"fields":[{"displayName":"用户微信昵称","id":"m8q1vjsz2c959nbgo88y5fyb7fsk6gsk","name":"name","order":0,"type":"String"},{"defaultValue":"0","description":"-1订单取消\n0新下单待上餐\n1待用户评价\n2订单已完成","displayName":"订单状态","enumElementType":"number","enumElements":[{"label":"订单取消","value":-1},{"label":"新下单待上餐","value":0},{"label":"已上餐待用户评价","value":1},{"label":"订单已完成","value":2}],"id":"f8sy1pq0eqkdx6umtvhhpj9s96k5h46z","name":"status","order":1,"type":"Enum"},{"displayName":"地址或桌号","id":"1cjixjfwmtd7eh00hm9hdks5r00o4v0o","name":"address","order":2,"type":"String"},{"displayName":"备注","id":"nf32xgjh2ah23vk9i10gevjme86p46fp","name":"beizhu","order":3,"type":"String"},{"defaultValue":1,"displayName":"就餐人数","id":"ubvhplplc1abw5vbtd81wf6nic15sce5","name":"renshu","order":4,"type":"Number"},{"displayName":"用户购买菜品","id":"0b31f3fqahpa28b0vmg0lqh939yg70e4","name":"orderList","order":5,"type":"Object"},{"dateFormatType":"timestamp-ms","description":"系统字段,请勿随意修改","displayName":"创建时间","id":"_createTime","isOrderField":false,"isSystem":true,"name":"_createTime","orderDirection":"desc","type":"DateTime"},{"dateFormatType":"timestamp-ms","description":"系统字段,请勿随意修改","displayName":"修改时间","id":"_updateTime","isSystem":true,"name":"_updateTime","type":"DateTime"},{"displayName":"订单总价格","id":"vm2elywssee8ukabunv55xmb40xfm69k","name":"totalPrice","order":8,"type":"String"}],"collectionName":"order","displayName":"订单表","_id":"28ee4e3e6023cca1044f88c54cc7ca97"},{"fields":[{"dateFormatType":"timestamp-ms","description":"系统字段,请勿随意修改","displayName":"创建时间","id":"_createTime","isSystem":true,"name":"_createTime","type":"DateTime"},{"dateFormatType":"timestamp-ms","description":"系统字段,请勿随意修改","displayName":"修改时间","id":"_updateTime","isSystem":true,"name":"_updateTime","type":"DateTime"},{"displayName":"用户名","id":"r224f33upej3jk98qti3rk18joh8lz4n","name":"name","order":2,"type":"String"},{"displayName":"订单号","id":"5sv5nbjy56xlqnlibg3lek2z694ic3sl","name":"orderId","order":3,"type":"String"},{"displayName":"用户头像","id":"uv9rsqgoexrraykjq3v4btbyooszyoco","name":"avatarUrl","order":4,"resourceLinkType":"https","type":"Image"},{"displayName":"评论内容","id":"5y71d4sptzgp0xsayj28lhv263bcvgf1","name":"content","order":5,"type":"MultiLineString"}],"collectionName":"pinglun","displayName":"评论","_id":"b00064a76023d836041d3bf4771dfc1f"},{"fields":[{"dateFormatType":"timestamp-ms","description":"系统字段,请勿随意修改","displayName":"创建时间","id":"_createTime","isSystem":true,"name":"_createTime","type":"DateTime"},{"dateFormatType":"timestamp-ms","description":"系统字段,请勿随意修改","displayName":"修改时间","id":"_updateTime","isSystem":true,"name":"_updateTime","type":"DateTime"},{"displayName":"账号名","id":"t1av0wc8jim7a8ea98p3jju81dh47yn8","name":"name","order":2,"type":"String"},{"displayName":"密码","id":"izpe4yji6md4i5ycwwcm85gzjxzw5bow","name":"password","order":3,"type":"String"}],"collectionName":"admin","displayName":"管理员","description":"小程序端后厨管理订单,管理排号。","_id":"79550af2602889fc04b23efa147abb02"},{"fields":[{"dateFormatType":"timestamp-ms","description":"系统字段,请勿随意修改","displayName":"创建时间","id":"_createTime","isSystem":true,"name":"_createTime","type":"DateTime"},{"dateFormatType":"timestamp-ms","description":"系统字段,请勿随意修改","displayName":"修改时间","id":"_updateTime","isSystem":true,"name":"_updateTime","type":"DateTime"},{"displayName":"小桌排号","id":"03pvviz7ihcx3jb401ynhgmqg5ciff79","name":"xiaozhuo","order":2,"type":"Object"},{"displayName":"大桌排号","id":"rl9pjp41nhg6tmkerzsck38aoiqt1pei","name":"dazhuo","order":3,"type":"Object"},{"defaultValue":0,"displayName":"小桌当前可就餐号码","id":"4hftsjo6ret4og53hw360k8vwd7g0my6","name":"xiaozhuonum","order":4,"type":"Number"},{"defaultValue":0,"displayName":"大桌当前可就餐号码","id":"ij0seo67dn6gbi64w33uds43ndzu8e9k","name":"dazhuonum","order":5,"type":"Number"}],"collectionName":"paihao","displayName":"排号","_id":"79550af260290e9604ccd27f5405ac2b"}]

上面的‘内容模型.json‘是事先建立了6个表后,导出的,我们也写不来。这里我们用一下,但导入6个表(内容模型)不成功。
解决办法:即安装扩展,返回到cms旧版本,具体步骤如下
image.png
image.png
按步就班,写一下账号和密码,完成后,把访问地址,账号,密码,都记一下,以便下次用。
image.png

访问地址:http://xiongshaowen65179334-2b8d7b7a64b-1253188164.tcloudbaseapp.com/wx-cms/
账号:xiongshaowen
密码:cexoit1983

project

效果图:
image.png
一, app.json中设置整个项目所有页的导航栏色,和标题,和页面

{
  "pages": [
    "pages/home/home","pages/food/food",
    "pages/food2/food2",
    "pages/address/address",
    "pages/pay/pay",
    "pages/mycomment/mycomment",
    "pages/myOrder/myOrder",
    "pages/me/me",
    "pages/paihao/paihao",
    "pages/admin/admin",
    "pages/adminHouchu/adminHouchu",
    "pages/adminPaihao/adminPaihao"
  ],
"window": {
    "backgroundColor": "#F6F6F6",
    "navigationBarTextStyle": "white",
    "navigationBarTitleText": "点餐小程序",
    "navigationBarBackgroundColor": "#f4c903"   
  },
  "tabBar": {
    "color": "#Fc0",
    "selectedColor": "#f4c903",
    "borderStyle": "white",
    "list": [{
        "selectedIconPath": "image/tab1-ok.png",
        "iconPath": "image/tab1.png",
        "pagePath": "pages/home/home",
        "text": "首页"
      },
      {
        "selectedIconPath": "image/tab2-ok.png",
        "iconPath": "image/tab2.png",
        "pagePath": "pages/me/me",
        "text": "我的"
      }
    ]
  },
  "permission": {
    "scope.userLocation": {
      "desc": "导航需要"
    }
  },
  "sitemapLocation": "sitemap.json"

}

二,app.js,绑定云开发环境

App({
  onLaunch() {
      wx.cloud.init({
        env:'xiongshaowen65179334-2b8d7b7a64b'
     })
      this.getOpenid();
    },
}

三,云函数目录设置,在’project.config.json’的顶部加了如下一行代码,就把云函数所在的目录云化了,文件夹图标上会显示云朵。

{
  "cloudfunctionRoot": "cloud/",
....
}

image.png

1–home

image.png

底部首页,也是我们一打开小程序就显示的页面。
home.json

{
  "navigationBarTitleText": "扫码点餐",
  "usingComponents": {}
}

image.png
这里只需要看一个重点知识点的文档即可,其余的知识点我在基础课里都有做讲解

轮播图片

home.wxml

<!-- 顶部轮播图 -->
<swiper indicator-color="#f4c903" indicator-dots="true" autoplay="true" circular="true">
  <block wx:for="{{banner}}" wx:key="banner">
    <swiper-item bindtap="goFood">
      <image src="{{item.picUrl}}" mode="widthFix" style="width:100%;height:100%;"></image>
    </swiper-item>
  </block>
</swiper>

home.js

let searchKey = ''
let db = wx.cloud.database()
Page({
  data: {     //网络不好时,初始化显示的图片
    banner: [{
      picUrl: '/image/1.jpg'
    }, {
      picUrl: '/image/2.jpg'
    }, {
      picUrl: '/image/3.jpg'
    }],
    foodlist: []
  },

  onLoad() {

  },
  /**
   * 周期函数,是系统自定义的
   */
  onShow() {
    this.getTopBanner() //显显轮播图,网络好时,调用数据库表中的图片
    this.getHotList() //显示热推荐
  },
//获取首页顶部轮播图(从表lunbotu)
  getTopBanner() {
    wx.cloud.database().collection('lunbotu')
      .get()
      .then(res => {
        if (res.data && res.data.length > 0) {
          this.setData({
            banner: res.data
          })
        }
      })
      .catch(res => {
        console.log("获取轮播图列表banner失败", res)
      })
  },

###搜索功能

  • 模糊搜索关键知识点文档:https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-sdk-api/database/Database.RegExp.html
    核心代码如下
// 数据库正则对象
db.collection('food').where({
  description: db.RegExp({     //description写数据表的字段名
    regexp: 'miniprogram',
    options: 'i',
  })
}).get()
.then(res=>{
   console.log("成功",res)
})
.catch(res=>{
   console.log("失败",res)
})

例:搜索含有’鱼‘的菜品,模糊查询,food表在上面已经由cms导入了完成了。

<!-- 搜索框 -->
<view class="searchRoot">
	<input class="searchInput" bindconfirm='goSearch' confirm-type='search' bindinput="getSearchKey" placeholder="搜索菜品" />
	<image class="searchImg" bindtap="goSearch" src="/image/sousuo.png"></image>
</view>
<!-- 在搜索框下面显示的,测试用,我们真正的开发中要跳转页面-->
   <block wx:for="{{foodlist}}" wx:key="foodlist">
     <view>
          <text>菜名:{{item.name}}</text>
          <image src="{{item.icon}}"></image>
       </view>
     </block> 
   
//xxx.wxss

/* 搜索框 */
.searchRoot {
  background: rgb(255, 255, 255);
  padding: 25rpx;
  display: flex;
  flex-direction: row;       /* 设置容器里的按行显示 */
  justify-content: space-between;  /*  */
}

.searchInput {
  flex: 2;          /* 输入框可以撑满行剩下的空间,值只要大于0即可 */
  height: 70rpx;
  padding-left: 30rpx;
  border: 1px solid #f4c903;
  border-radius: 30rpx;      /* 方框的四角以图形显示 */
}

.searchImg {
  width: 70rpx;
  height: 70rpx;
  margin: 0 15rpx;
}

//xxxx.js
let searchKey = ''
const db = wx.cloud.database()
Page(
//获取用户输入的搜索词
  getSearchKey(e) {
    searchKey = e.detail.value
    console.log(searchKey)
  },
//搜索点击事件触发方法
  goSearch() {
    console.log("触发了搜", searchKey)
    if (searchKey && searchKey.length > 0) {
      // 数据库正则对象
      db.collection("food").where({
          name: db.RegExp({
          regexp: searchKey,
          options: 'i'
        })
      }).get()
        .then(res=>{
          console.log("搜索成功",res)
         this.setData({
            foodlist:res.data
          })
        })
        .catch(res=>{
          console.log("搜索失败",res)
        })
    }
  },

image.png
image.png

image.png

九空格实现菜单选项

 <!-- 九宫格 -->
<view class="category_root">
  <view bindtap='diancan' class="category_item">
    <image class="category_item_image" src="/image/home1.png" />
    <text>{{'去点餐'}}</text>
  </view>
  <view bindtap='goToFood' class="category_item">
    <image class="category_item_image" src="/image/home2.png" />
    <text>菜单浏览</text>
  </view>
  <view bindtap='paihao' class="category_item">
    <image class="category_item_image" src="/image/home3.png" />
    <text>排号等位</text>
  </view>
  <view bindtap='goToAddress' class="category_item">
    <image class="category_item_image" src="/image/home4.png" />
    <text>饭店信息</text>
  </view>
</view>

/* 九空格区域,即显示四个菜单图标 */
.category_root {
  height:90px;
  width:100%;
  display:flex;
  color: #666;
  flex-direction: row;
  font-size:11px;
  justify-content: space-around;
}
.category_item {
  display: flex;
  flex-direction: column;
  text-align: center;
}
.category_item_image {
  width:50px;
  height: 50px;
  padding:15px 12px 0 6px;
}

image.png
###热门推荐
即在主页下面显示当前销量最多的5个商品,按降排序显示
image.png

<!-- 热销菜品依据销量,列出前5个菜品 -->
 <!-- <view wx:if="{{goodList&&goodList.length>0}}"> -->
	<view class="hot_tip"> 
		热门推荐
		<text class="more" bindtap="goToFood">更多></text>
	</view>
	<block wx:for="{{goodList}}" wx:key="index">
		<view class="good_item" bindtap="goToFood">
			<image class="good_img" src="{{item.icon}}" />
			<view class="good_right">
				<view class="good_title" data-index="{{index}}">{{item.name}}:少文游司边特色展</view>
				<view class="good_sell">销量:{{item.sell}} </view>
				<view class="good_price" data-index="{{index}}">{{item.price}}</view>
			</view>
		</view>
	</block> 
<!-- </view> -->

home.wxss

/* 热门推荐商品 */
.hot_tip {
  font-size: 45rpx;
  color: #f4c903;
  display: flex;
  justify-content: space-between;
  margin: 35rpx 5rpx 15rpx 30rpx;
}

.more {
  font-size: 36rpx;
  padding: 10rpx 30rpx;
}

.good_item {
  /*列表  */
  display: flex;
  margin: 5rpx 40rpx;
  border-bottom: 1px gainsboro solid;
}
.good_img {
  width: 120rpx;
  height: 120rpx;
  min-width: 120rpx;
  margin-left: 10rpx;
  margin-right: 30rpx;
}
.good_title {
  font-size: 38rpx;
  width: 500rpx;       /*这里必须设置文字宽度*/
  white-space:nowrap;   /*文本不换行*/
	text-overflow:ellipsis;  /*设置超出部分显示...*/
	overflow: hidden;
}
.good_sell {
  font-size: 30rpx;
  color: gray;
}
.good_price {
  /*价格*/
  font-weight: bold;
  font-size: 32rpx;
  color: #ff9600;
}

.good_price::before {
  /*人民币符号*/
  content: "¥";
  font-size: 14px;
}

home.js

Page({
  //热门推荐
  getHotList() {
  /*db.collection('food')
      .where({
        status: '上架' //只查上架的
      })
      .orderBy('sell', 'desc') //降序排列
      .limit(5)
      .get()
      .then(res => {
        console.log('菜品推荐查询成功', res)
      }) 
*/

  //云函数getFoodList来获取菜品信息,该函数有三个功能:全部,上架的,下架的
      wx.cloud.callFunction({
        name:'getFoodList',
        data:{
          action:'getHot',     //通过event.action传到云函数的参数中。
        }
      }).then(res=>{
        console.log('菜品推荐查询成功', res)
        this.setData({
          goodList:res.result.data
        })
      })
  }
})

注意点

  1. 列表中的文字过长时,不能换行显示,不然不好看
.good_title {
  font-size: 38rpx;
  width: 500rpx;       /*这里必须设置文字宽度*/
  white-space:nowrap;   /*文本不换行*/
	text-overflow:ellipsis;  /*设置超出部分显示...*/
	overflow: hidden;
 }

  1. 人民币符号,处理
.good_price::before {
  /*人民币符号*/
  content: "¥";
  font-size: 14px;
}
  1. 用云函数查询数据库,因为它可以突破20条查询权限,也可节省大量代码,如,查询条件(上架的,全部的,模糊的全可放一起)。
//getFoodList中的index.js代码,调用时,写如:name:'getFoodList'.
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()

// 云函数入口函数
exports.main = async (event, context) => {
  if (event.action == 'search' && event.searchKey) { //搜索菜品
    return await db.collection('food').where({
      name: db.RegExp({
        regexp: event.searchKey,
        options: 'i'
      }),
      status: '上架'
    }).get()
  } else if (event.action == 'getHot') { //获取首页推荐位热门商品
    return await db.collection('food').where({
        status: '上架'
      })
      .orderBy('sell', 'desc')
      .limit(5)
      .get()
  } else { //获取100条菜品
    return await db.collection('food')
      .where({
        status: '上架'
      }).get()
  }
}

2–me

底部’我的’页面。

3–address显示地图

<map style="width:100%; height:1000rpx;" longitude="{{longitude}}" latitude="{{latitude}}" scale="17"
  markers="{{markers}}"  bindmarkertap="navRoad" data-marker="{{markers[0]}}"
  show-location />
<view class="phone" bindtap="Call">
  地址:南昌市青山湖区江纺宅三区11</view>
<view class="phone" bindtap="Call">
  电话  13065156391(可点击拨打)
</view>
<view class="phone" bindtap="Copy">
  微信:x13065156391(可点击复制)
</view>
Page({
  data: {
    //店铺经纬度
    latitude: 28.719223,
    longitude: 115.945917,
    //标记点
    markers: [{
      id: 0,
      name: "编程小石头",
      address: "南昌市青山湖区江纺宅三区11号",
      latitude: 28.719223,
      longitude: 115.945917,
      width: 50,
      height: 50
    }]

  },
  //拨打电话
  Call() {
    wx.makePhoneCall({
      phoneNumber: '13065156391' //仅为示例,这个号码也是石头哥的微信号
    })
  },
  //复制微信
  Copy() {
    wx.setClipboardData({
      data: 'x13065156391',
    })
  },
  //导航
  navRoad(event) {
    console.log(event)
    wx.getLocation({ //获取当前经纬度
      type: 'wgs84', //返回可以用于wx.openLocation的经纬度,
      success: function (res) {
        wx.openLocation({ //使用微信内置地图查看位置。
          latitude: event.currentTarget.dataset.marker.latitude, //要去的纬度-地址
          longitude: event.currentTarget.dataset.marker.longitude, //要去的经度-地址
          name: event.currentTarget.dataset.marker.name,
          address: event.currentTarget.dataset.marker.address
        })
      },
      fail: res => {
        console.log('授权失败', res)
        wx.showModal({
          title: '需要授权位置信息',
          success: res => {
            if (res.confirm) {
              wx.openSetting()
            }
          }
        })
      }
    })
  }
})

image.png
发布上线小程序,地图遇到的问题
以下接口未正确配置在app.json文件中,勾选协议可继续提交,该版本发布后,用户将无法使用相关接口能力。接口未正确配置:wx.getLocation
处理:app.json中

{
  "pages": [
  .........
  ],
  "requiredPrivateInfos": [
    "getLocation",
    "choosePoi",
    "chooseAddress"
  ],

  "window": {
........

4—授权登陆与退出开发

4-1.认识wx.getUserProfile方法

对应的文档:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html
--------获取用户信息。页面产生点击事件(例如 button 上 bindtap 的回调中)后才可调用,每次请求都会弹出授权窗口,用户同意后返回 userInfo对象,该对象中有用户如:呢称(nickName),头像链接(avatarUrl----https://…),地址等。该接口用于替换 wx.getUserInfo(2020年就不用了),详见 用户信息接口调整说明。

//开放接口 /用户信息 /wx.getUserProfile
wx.getUserProfile(Object object)
//------用户头像昵称获取规则已调整,参考 小程序用户头像昵称获取规则调整公告 
//基础库 2.10.4 开始支持(本人2024年用2.16),低版本需做兼容处理。

-----2024年该方法又作了调整了,现在开发时可以获取用户信息,但是发布或测试版不可获用户信息了。后续会讲2024最新版授权登陆处理。
授权弹窗
-----一般我的使用上面的wx.getUserProfile方法获取用户信息时,需要用户授权的。一般授权弹窗如下。
image.png
只有用户点击允许以后才可以获取用户信息。
不弹起授权弹窗解决方案
-----有的用这个方法时,不会弹起上面的弹窗,有可能是因为基础库版本太低,这里建议升级到最新版的基础库。
image.png
例:最简单的授权登陆后,获取用户头像和昵称显示在页面上

<!--xxxx.wxml-->
<button wx:if="{{noLogin}}" bindtap = "login" >授权登陆</button>
<view wx:else class="root">
  <image class="touxiang" src="{{avatarUrl}}"></image>
   <text class="nicheng">{{nickName}}</text>   
</view>

<!--xxxx.wxss-->
.root{
  display: flex;   /* 弹性布局,默认会利用现有空间布置所有子元素 */
  flex-direction: column;
  align-items: center;
 
}
.touxiang{
  width: 250rpx;
  height: 250rpx;
  border-radius: 50%;
}
//xxxx.js
Page({
  data:{
    nickName:'',
    avatarUrl: '',
    noLogin: true     //没登陆时显示用户信息
  },
  login(){
    wx.getUserProfile({
      desc:'必须授权才可以继续用',
      success:res=>{
        console.log(res)
        this.setData({
          nickName: res.userInfo.nickName,
          avatarUrl: res.userInfo.avatarUrl,
          noLogin: false
        })
      },
      fail: res=>{
        console.log("授权失败",res)
      }
    })
  }
})

改进一下上面的代码,我们把userInfo封装成一个对象

Page({
  data:{
    userInfo:''
  },
  login(){
    wx.getUserProfile({
      desc:'必须授权才可以继续用',
      success:res=>{
        console.log(res)
        let user = res.userInfo
        this.setData({
          userInfo: user                //这里封装
        })
      },
      fail: res=>{
        console.log("授权失败",res)
      }
    })
  }
}),
//退出登陆,就是设置为空,但这登陆退出状态没有保存下来没做处理
  loginOut(){
    this.setData({
      userInfo:''
    })
  }


<button wx:if="{{!userInfo}}" bindtap = "login" >授权登陆</button>
<view wx:else class="root">
  <image class="touxiang" src="{{userInfo.avatarUrl}}"></image>
   <text class="nicheng">{{userInfo.nickName}}</text>   
   <button bindtap="loginOut">退出登陆</button>
</view>

image.png
image.png
###4-2登陆状态缓存到本地
这里缓存我们主要用到了wx.setStorageSync 对应的官方文档: https://developers.weixin.qq.com/miniprogram/dev/api/storage/wx.setStorageSync.html

-----
onLoad(){   //onLoad()方法,是系统自带的,页面初始化时加载执行之,这里我们是测试获取本地缓存变量
     let user =wx.getStorageSync('user')
     console.log("本地缓存中的user",user)
  },
  login(){
    wx.getUserProfile({
      desc:'必须授权才可以继续用',
      success:res=>{
        console.log("已授权",res)
        let user = res.userInfo
        wx.setStorageSync('user', user)   //缓存登陆用户信息到本地缓存,下次进入小程序可以读来不用再授权
-------

image.png

4-3利用1和2实现登陆退出

----大体思路:
一,初始化页时,从本地缓存中查询是否有用户登陆过的信息,如果有,则处于登陆授权状态
二,如果本地缓存中没有或为空,则显示授权登陆按钮,点击之,授权之,若授权成功,则把用户信息缓存到本地(user)
三,退出时,则清空或置null给本地用户缓存变量。

Page({
  data:{
    userInfo:''
  },
//onLoad()系统自带的初始化接口(api)
  onLoad(){
     let user =wx.getStorageSync('user')
     console.log("本地缓存中的user",user)
     this.setData({
       userInfo:user
     })
  },
//登陆授权
 login(){
    wx.getUserProfile({
      desc:'必须授权才可以继续用',
      success:res=>{
        console.log("已授权",res)
        let user = res.userInfo
        wx.setStorageSync('user', user)   //缓存登陆用户信息到本地缓存,下次进入小程序可以读来不用再授权
        this.setData({
          userInfo: user
        })
      },
      fail: res=>{
        console.log("授权失败",res)
      }
    })
  },
//退出登陆
  loginOut(){
    this.setData({
      userInfo:''
    })
    wx.setStorageSync('user', null/* '' */)
  }

##2024新版登陆获取昵称与头像
-----上面的例子,获取头像与呢称,只要wx.getUserProfile()即可弹出窗口点击获取之。但这种方式在2022年11月就被抛异了。
------最近好多人在学习小程序课程的时候,遇到了下面这样的问题,在小程序授权获取用户头像和昵称时,获取到的是下面这样的。
image.png
到底是什么原因导致的呢,去小程序官方文档一看,又是官方改规则了。
点进去一看,原来小程序官方又把获取用户头像的接口回收了。
对应学习链接如下
https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/userProfile.html
-----真是我的地盘我做主啊,我说怎么样就怎么样啊。有点店大欺客的嫌疑了。。。 但是呢,作为我们苦命的小程序开发者,官方虐我千百遍,我待官方如初恋。没办法啊,我们还是得用小程序不是吗。。。。
所以我们这里给大家提供几种解决方案。
一开始我们用的是wx.getUserInfo,
再后来官方给我们换成了wx.getUserProfile
而现在获取用户头像和昵称,只能用下面这个方法了。

<button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
  <image class="avatar" src="{{avatarUrl}}"></image>
</button> 
<input type="nickname" bindblur="getNickname" class="weui-input" placeholder="请输入昵称"/>
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
Page({
  data: {
    avatarUrl: defaultAvatarUrl,
  },
  onChooseAvatar(e) {
    const { avatarUrl } = e.detail 
    this.setData({
      avatarUrl,
    })
  },
//获取官方昵称
  getNickname(e){
    console.log("微信呢称:",e.detail.value)
    this.setData({
      nickName: e.detail.value
    })
  }
})

------但是官方给的方式有点不太方便使用,那就给大家改造下,供大家使用。学习之前你要去下载一下开发者工具。
使用方法
头像选择
-----需要将 button 组件 open-type 的值设置为 chooseAvatar,当用户选择需要使用的头像之后,可以通过 bindchooseavatar 事件回调获取到头像信息的临时路径。从基础库2.24.4版本起,若用户上传的图片未通过安全监测,不触发bindchooseavatar 事件。
昵称填写
-----需要将 input 组件 type 的值设置为 nickname,当用户在此input进行输入时,键盘上方会展示微信昵称。
----从基础库2.24.4版本起,在onBlur 事件触发时,微信将异步对用户输入的内容进行安全监测,若未通过安全监测,微信将清空用户输入的内容,建议开发者通过 form 中form-type 为submit 的button 组件收集用户输入的内容。
###前期准备
—新版登陆获取用户信息不仅可以获取登陆的版信对应的头像和呢称,还可以自已自定义呢称和头像,所以如果自定义的我们要把数据放到表中,以便随时用之。
1云开发环境
2.云环境表user2,权限设置‘仅创建者可读写,这样的好处是,获取数据时,获取第一个记录即可用,不用循环语句了,要不然读取多条记录,要用大量的语句来判断是某个用户的
image.png

Page({
  data:{
     userInfo:''
  },
  onLoad() {
    let user= wx.getStorageSync("user1")
    console.log("local user",user)
    if(user){
      this.setData({
        userInfo: user
      })
    }
 },
 //退出登录
 tuichu() {
     this.setData({
         userInfo: null,
     })
     let user = wx.getStorageSync('user1')
     if(user){
       wx.cloud.database().collection('user2').doc(user._id).remove()
       .then(res=>{
         console.log("删除记录成功",res)
       })
       .catch(res =>{
         console.log("删除记录失败",res)
       })
     }
     wx.setStorageSync('user1', null)
 },
 /**
  * 关闭/打开弹框
  */
 closeTank(e) {
     if (!this.data.userInfo_tank) {  //userInfo_tank
         wx.cloud.database().collection('user2')
             .get()
             .then(res => {
                 console.log("用户信息====", res);
                 if (res.data.length) {
                     this.setData({
                         userInfo: res.data[0],
                         userInfo_tank: false,
                     })
                     wx.setStorageSync('user1', res.data[0])
                 } else {
                     console.log("还未注册====", res)
                     this.setData({
                         userInfo_tank: true
                     })
                 }
             }).catch(res => {
                 console.log('编程小石头提醒你请添加user2表')
             })
     } else {
         this.setData({
             userInfo_tank: false
         })
     }

 },
 /**
  * 获取头像
  */
 onChooseAvatar(e) {
     console.log(e);
     this.setData({
         avatarUrl: e.detail.avatarUrl
     })
 },
 /**
  * 获取用户昵称
  */
 getNickName(e) {
     console.log(e);
     this.setData({
         nickName: e.detail.value
     })
 },

 /**
  * 提交
  */
 submit(e) {
     if (!this.data.avatarUrl) {
         return wx.showToast({
             title: '请选择头像',
             icon: 'error'
         })
     }
     if (!this.data.nickName) {
         return wx.showToast({
             title: '请输入昵称',
             icon: 'error'
         })
     }
     this.setData({
         userInfo_tank: false
     })
     wx.showLoading({
         title: '正在注册',
         mask: 'true'
     })
     let tempPath = this.data.avatarUrl

     let suffix = /\.[^\.]+$/.exec(tempPath)[0];
     console.log(suffix);

     //上传到云存储
     wx.cloud.uploadFile({
         cloudPath: 'userimg/' + new Date().getTime() + suffix, //在云端的文件名称
         filePath: tempPath, // 临时文件路径
         success: res => {
             console.log('上传成功', res)
             let fileID = res.fileID
             wx.hideLoading()
             wx.cloud.database().collection('user2')
                 .add({
                     data: {
                         avatarUrl: fileID,
                         nickName: this.data.nickName
                     }
                 }).then(res => {
                     let user = {
                         avatarUrl: fileID,
                         nickName: this.data.nickName
                     }
                     // 注册成功
                     console.log('注册成功')

                     this.setData({
                         userInfo: user,
                     })
                 }).catch(res => {
                     console.log('注册失败', res)
                     wx.showToast({
                         icon: 'error',
                         title: '注册失败',
                     })
                 })

         },
         fail: err => {
             wx.hideLoading()
             console.log('上传失败', res)
             wx.showToast({
                 icon: 'error',
                 title: '上传头像错误',
             })
         }
     })
 },

})
.header {
  width: 100%;
  display: flex;
  padding: 30rpx 55rpx;
  align-items: center;
  background: #1ED76D;
}

.userinfo_avatar {
  border-radius: 128rpx;
  width: 128rpx;
  height: 128rpx;
  margin-right: 30rpx;
}

.userinfo_nickname {
  font-size: 36rpx;
  margin-bottom: 5rpx;
}

.tuichu {
  font-size: 30rpx;
  color: gray;
}

/* 授权弹窗 */
.userInfo_tank_bg {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  opacity: 0.3;
  background: #000;
  z-index: 666;
}

.userInfo_tank {
  position: fixed;
  bottom: 0;
  background-color: white;
  width: 100%;
  border-radius: 30rpx 30rpx 0 0;
  padding: 30rpx;
  box-sizing: border-box;
  z-index: 999999;
}

.transfromjoin {
  transition: all 0.3s;
  margin-bottom: 0;
}

.transfromout {
  transition: all 0.3s;
  margin-bottom: -700rpx;
}

.avatar_url {
  width: 80rpx;
  height: 80rpx;
  border-radius: 50%;
}

.tank_content {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid #eee;
  height: 100rpx;
}

.tank_content text {
  color: #787376;
}

.tank_content input {
  width: 80%;
  text-align: right;
}

.tank_title {
  border-bottom: 1px solid #eee;
  padding-bottom: 30rpx;
  font-weight: 700;
}

.confirm_button {
  display: flex;
  margin: 50rpx 0;
  box-sizing: border-box;
  align-items: center;
  justify-content: center;
}

.confirm_button view {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 50%;
}

.pos_photo {
  position: absolute;
  bottom: 0;
  right: -10rpx;
  background-color: rgba(0, 0, 0, 0.3);
  border-radius: 50%;
  width: 40rpx;
  height: 40rpx;
  display: flex;
  justify-content: center;
  align-items: center;
}

.pos_photo text {
  font-size: 25rpx !important;
  color: #fff;
}

.avatar {
  position: relative;
}

.confirm_button view button {
  width: 90%;
}

.default_button {
  width: none !important;
  margin: 0 !important;
  padding: 10rpx 20rpx !important;
  width: 260rpx !important;
  font-weight: 600 !important;
  font-size: 32rpx !important;
}

.avatar_button {
  padding: 0 !important;
  margin: 0 !important;
  width: 80rpx !important;
  height: 80rpx !important;
  border-radius: 50% !important;
  font-size: 32rpx !important;
  overflow: visible !important;
}
<view class="header">
    <!-- 未登陆 -->
    <image wx:if="{{!userInfo.avatarUrl}}" bindtap="closeTank" class="userinfo_avatar" src="/image/no_login.png"></image>
    <view wx:if="{{!userInfo.avatarUrl}}" bindtap="closeTank" class="userinfo_nickname">点击登陆</view>
    <!-- 已登陆 -->
    <image wx:if="{{userInfo.avatarUrl}}" class="userinfo_avatar" src="{{userInfo.avatarUrl}}"></image>
    <view wx:if="{{userInfo.avatarUrl}}" class="header_right">
        <view class="userinfo_nickname">{{userInfo.nickName}}</view>
        <text class="tuichu" bindtap="tuichu">退出登录</text>
    </view>
</view>

<!-- 头像昵称基本信息弹框 -->
<view>
   <view class="userInfo_tank_bg" bindtap="closeTank" wx:if="{{userInfo_tank}}"></view>
    <view class="userInfo_tank {{userInfo_tank?'transfromjoin':'transfromout'}}">
        <view class="tank_title">
            <text>申请获取您的头像、昵称</text>
        </view>
        <view class="tank_content">
            <text>头像:</text>
            <button class="avatar_button" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
                <image class="avatar_url" src="{{avatarUrl}}"></image>
                <view class="pos_photo">
                    <text class="iconfont icon-paizhao"></text>
                </view>
            </button>
        </view>
        <view class="tank_content">
            <text>昵称:</text>
            <input form-type='submit' bindblur="getNickName" placeholder="请输入昵称" type="nickname" />
        </view>
        <view class="confirm_button">
            <view>
                <button bindtap="closeTank">拒绝</button>
            </view>
            <view>
                <button bindtap="submit" type="primary">允许</button>
            </view>
        </view>
    </view>
</view>

image.png

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qq_33406021

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值