为女朋友写一个小程序(四)— —前端小程序的设计与实现

2023-11-19

为女朋友写一个小程序(一)— —目的与需求
为女朋友写一个小程序(二)— —数据库设计
为女朋友写一个小程序(三)— —基于springboot的服务器端接口设计与实现
为女朋友写一个小程序(四)— —前端小程序的设计与实现(本文)
为女朋友写一个小程序(五)— —如何用docker简化部署
为女朋友写一个小程序(六)— —结合docker实现devOps
为女朋友写一个小程序(七)— —优化引进redis(未编码,未写)
为女朋友写一个小程序(八)— —基于moongodb实现即时通讯(未编码,未写)

2018年后半年一直出差,几乎没时间书写博客,趁现在空档期,把
拖了许久的文章继续写完吧…还是要保持写文章的习惯呀,做过的项目很久没回顾回顾起来确实也需要一定时间…记忆力这东西

一、前端实现结果展示

(以首页,任务页,商城列表,兑换列表为例)
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

二、技术选型方案

1、为什么选择微信小程序?

因为2018年开发的时候想到小程序是那个时候的风口,把玩一下小程序是一个技术人的乐趣。
对于这样一个简单的程序适合于寄生于一个平台,以平台为入口进行开发,可以节省许多其他不必要的环节(如使用原生需要考虑如何被下载,应用上下架的问题)。
小程序其实也是基于B/S结构,其开发的使用的自身的框架,但是其实说白了跟使用HTML+JS+CSS开发区别其实不是很大,因为之前在工作中有过前端开发的基础,尚于对前端框架的使用,熟悉JS,入门起来可以比较快速。
所以考虑、了解了几天之后决定使用小程序作为该程序的前端交互。

2、使用的技术栈是什么?

技术栈使用的是:wxss+weUI
使用wxss这是没办法,开发小程序是腾讯限死一定要使用这样的框架(不像我司、支持我司开发的框架,同时支持普通的HTML+CSS,原生等),开发起来具有一定的局限性,且要开发一定要先过一次小程序开发文档,需要消耗一定的时间,但是因为之前玩过VUE这样MVVC前端框架,一通百通,所以接触起来也不困难。
使用weUI是因为之前用VUE开发的时候已经有很多开源的UI框架,最初的版本也是自己用原生的wxss的组件去画,但是因为前端基础还是比较薄弱,所以找到了小程序的UI框架,weUI,其界面简洁,语法简单,真是居家旅行,外包必备的一个好框架。

3、根据技术栈如何进行技术储备?

3.1、认识前端开发
如果你对于前段开发还是不熟悉的话,那做起来肯定会比较吃力,博主提过,之前是玩过VUE开发,参考文章,所以具备一定的前端开发能力是必要的,最好是在玩过VUE等这样的MVVC框架之后,接触小程序就相当简单了,因为其思想都是差不多的,开发“全家桶”也是差不多,只是语法不同罢了。

3.2、认识微信小程序
对小程序的开发首先肯定要对小程序进行了解,了解的时候主要还是以官方文档为主,无论如何一定要过一遍官方文档,里面会提及许许多多的细节,是你在设计方案的时候想不到的,如:接服务器端时,服务器端一定是要使用https协议,且服务器端地址展示出来一定要是一个域名,否则无法使用其原生接口发起请求…

3.3、认识weUI
weUI是一个UI框架官方文档,UI框架的入手过官方文档帮助其实不大,像我就直接下demo,了解一下如何接入该框架,然后根据我设计的界面找到响应的组件,然后demo代码直接copy上,然后再进行调整,这样对一个小项目来说是最快的。

3.4、IDE选择
小程序IDE是我见过的最烂的IDE没有之一,除了一个好处就是支持预览与远程调试。但是对于经常使用webStom的开发者来说非常不习惯,快捷键极少,习惯难以切换,最开始一段时间开发起来是比较慢和吃力。

后面我直接用webStom打开整个工程,在webStom进行编码,然后在小程序IDE进行调试,效率提升了不止一倍。我建议大家也可以这样玩。

三、前端代码的实现

1、整体开发架构规划,模块划分

小程序开发时,项目标准结构腾讯已经帮我们规划好了,这边开发是根据一些对象功能定义不同而简单划分出各个模块。小程序项目整体架构如下图所示:
在这里插入图片描述
1.1、小程序全局对象
整个“小程序”在项目中就是一个全局对象,所有的逻辑定义都在该全局对象中的,这个大家可以细看官方文档。这边主要使用到全局对象中(app.js)的东西是globalData用来装一些全局使用的变量,还有启动时一些操作、如获取高度、宽度,自动登录等操作。关于app.json就不解析,这个是关于布局亦可细看官方文档。
1.2、页面展示与交互逻辑模块
在这里插入图片描述
页面展示、交互逻辑这块曾经重构过一次、最开始的版本是所有页面都在/page目录下,到后面页面层次一多起来,维护起来看起来非常复杂,所以下了决心重构了一次,使用目录的层级体现页面的层级。
页面展示、交互逻辑模块这一块就是小程序说的MVVC结构,中规中举,下面给出登录页面的代码,简单展示一下MVVC结构。
展示页面login.wxml

<view class='login-wrapper' style='height:{{viewHeight}}px;width:{{viewWidth}}px'>
  <view class="login-icon">
    <image class="login-img" src="../../static/images/icon-logo.png"></image>
  </view>
  <view class="login-from">
    <!--账号-->
    <view class="inputView">
      <image class="nameImage" src="../../static/images/icon-account.png"></image>
      <label class="loginLab">账号</label>
      <input class="inputText" value="{{account}}" placeholder="请输入账号" maxlength="11" bindinput="handleInputAccount" />
    </view>
    <view class="line"></view>
    <!--密码-->
    <view class="inputView">
      <image class="keyImage" src="../../static/images/icon-password.png"></image>
      <label class="loginLab">密码</label>
      <input class="inputText" password="true" value="{{password}}" maxlength="20" placeholder="请输入密码" bindinput="handleInputPassword" />
    </view>
    <!--按钮-->
    <view class="loginBtnView">
      <button type="primary"   bindtap="handleTapLogin">登录</button>
    </view>
  </view>
    <view class="weui-footer weui-footer_fixed-bottom">
            <view class="weui-footer__text">粤ICP备18035307号</view>
        </view>
</view>

类CSS的wxss,为wxml穿衣服login.wxss

/*登录图片*/
.login-wrapper {
  background-color: white
}
.login-icon {
  text-align: center;
  background-color: #fff
}

.login-img {
  width: 250px;
  height: 250px;
}

/*表单内容*/

.login-from {
  flex: auto;
}

.inputView {
  background-color: #fff;
  line-height: 44px;
}

/*输入框*/

.nameImage, .keyImage {
  margin-left: 22px;
  width: 14px;
  height: 14px;
}

.loginLab {
  margin: 15px 15px 15px 10px;
  color: #545454;
  font-size: 14px;
}

.inputText {
  flex: block;
  float: right;
  text-align: right;
  margin-right: 22px;
  margin-top: 11px;
  color: #ccc;
  font-size: 14px;
}

.line {
  width: 100%;
  height: 1px;
  background-color: #ccc;
  margin-top: 1px;
}

/*按钮*/

.loginBtnView {
  width: 100%;
  height: auto;
  background-color: #f2f2f2;
  margin-top: 0px;
  margin-bottom: 0px;
  padding-bottom: 0px;
}

.loginBtn {
  width: 80%;
  margin-top: 35px;
}

主要的交互逻辑,控制层login.js

// pages/login/login.js
let userLoginObj = require('../../request/user/login.js')
Page({

  /**
   * 页面的初始数据
   */
  data: {
    account:'',
    password:'',
    viewHeight: 0,
    viewWidth: 0,
    requestBuilder: {},
    userDao:{},
    router: {}
  },
  //登录控制
  handleTapLogin(){
    if (this.validate()) { //数据校验
      userLoginObj.data = { account: this.data.account,password:this.data.password}
      let that = this 
      wx.request(this.data.requestBuilder(userLoginObj,(res)=>{
        if(res.data.status){
          console.log('登录成功')
          //存储帐号与密码
          let security = { account: that.data.account, password: that.data.password}
          that.data.userDao.setSecurity(security)
          //存储用户信息
          that.data.userDao.setUser(res.data.data)
          console.log('页面跳转')
          that.data.router.toTapTargetTargetList()
          // that.data.router.toTapShopRewardList()
          // that.data.router.toTapShopExchangeDetailList()
          // that.data.router.toTapSupervisionRewardList()
          // that.data.router.toTapSupervisionRewardAdd()
          //that.data.router.toTapSupervisionTargetList()
        }else{//失败了
          wx.showToast({
            title: res.data.message,
            icon:'none'
          })
          return
        }
      }))
    }else{

    }
  },
  //form校验
  validate(){
    if(this.data.account==''){
      wx.showToast({
        title: '账户不能为空',
        icon: 'none'
      })
      return false
    }
     
    if(this.data.password==''){
      wx.showToast({
        title: '密码不能为空',
        icon: 'none'
      })
      return false
    }
     return true
  },
  handleInputAccount(even){
    this.setData({account:even.detail.value})
  },
  handleInputPassword(even){
    this.setData({password:even.detail.value})
  },
  onShow(){
    let account = this.data.userDao.getAccount()
    let password = this.data.userDao.getPassword()
    if (account != null && password != null) {
      this.setData({
        account:account,
        password:password
      })
      this.handleTapLogin()
    } 
  },
  onLoad(){
    let app = getApp()
    //定义高度与宽度
    this.setData({
      viewHeight: app.globalData.viewHeight,
      viewWidth: app.globalData.viewWidth,
      requestBuilder: app.globalData.requestBuilder,
      userDao: app.globalData.userDao,
      router: app.globalData.router
    })
  }
})

login.json没有对页面定义什么内容,故不做展示

1.3、请求、与服务器端交互模块
在上述的login.js中大家应该也看到与服务器端请求逻辑,这里不外乎也是使用wx.request(obj)进行请求,这里我用了类VUE axios的思想设计,把每个请求都定义成一个对象,称为请求对象。再由一个工厂类,对请求对象进行封装一层,成为wx.request(obj)要求的标准对象,这样设计的一个考虑,就是为了把每个不同请求进行解耦。
在这里插入图片描述

为了更好说明刚刚的设计理念,以登录接口为例进行代码展示,先来看看请求对象工厂类
requestObjBuilder.js

let config = require('../../config/config.js')
let userDao = require('../../store/user-dao.js')
let router = require('../../router/router.js')

module.exports=function(baseRequestObj,success,fail,complete){
  //复制一个传递进来的请求对象
  baseRequestObj = JSON.parse(JSON.stringify(baseRequestObj))
  //定义请求头
  baseRequestObj.header.KIKI_AUTH_TOKEN = userDao.getToken()
  //解耦域名基础路径
  baseRequestObj.url = config.BASE_SERVICE_PATH + baseRequestObj.url


//定义全局错误策略,与成功策略
  let baseSuccess = (res)=>{
    if (res.statusCode!=200){
      wx.showToast({
        title: '请求失败了:' + res.statusCode,
        icon: 'none',
        duration: 2000
      })
    }else{
      //res.data!=undefined 下载接口是没有data的
      if (res.data!=undefined && res.data.code == 401){//尚未登录
        router.toLogin()
      }else{
        if (typeof success === "function") {
          success(res)
        } 
      }
    }
  }

  baseRequestObj.success = baseSuccess
 


  if (typeof fail === "function"){
    baseRequestObj.fail = fail
  }else{
    let defaultfail = (err)=>{
      console.log(err)
      wx.showToast({
        title: '服务器挂了:' + err.errMsg,
        icon:'none',
        duration:2000
      })
    }
    baseRequestObj.fail = defaultfail
  }


  if (typeof complete === "function")
    baseRequestObj.complete = complete
  return baseRequestObj
}

再来看看设计的请求对象是怎样的
login.js

let requestObj = {//请求实体
  url: '/user/login',//请求地址
  data:null,//请求的参数
  header:{
    'content-type': 'application/json' // 默认值
  },//请求头
  method: "POST"//请求方法
}
module.exports = requestObj

把requestBuilder注入data中,当我需要对用户进行登录时,我可以使用以下方法进行登录,成功的解耦

 wx.request(this.data.requestBuilder(userLoginObj,(res)=>{
        if(res.data.status){
          console.log('登录成功')
          //存储帐号与密码
          let security = { account: that.data.account, password: that.data.password}
          that.data.userDao.setSecurity(security)
          //存储用户信息
          that.data.userDao.setUser(res.data.data)
          console.log('页面跳转')
          that.data.router.toTapTargetTargetList()
          // that.data.router.toTapShopRewardList()
          // that.data.router.toTapShopExchangeDetailList()
          // that.data.router.toTapSupervisionRewardList()
          // that.data.router.toTapSupervisionRewardAdd()
          //that.data.router.toTapSupervisionTargetList()
        }else{//失败了
          wx.showToast({
            title: res.data.message,
            icon:'none'
          })
          return
        }
      }))
    }else{

    }

1.4、页面之间的路由跳转模块
页面之间的路由跳转小程序是提供了标准的接口,参考导航,但是我感觉这个处理不是很优雅,因为这样需要在不同页面里面写入其他页面的地址,所以我干脆定义一个全局对象,使用方法进行跳转,见代码:
router.js

const loginPath = '/pages/login/login'
const tapTargetTargetList = '/pages/tap-target/target-list/target-list'
const tapShopRewardList = '/pages/tap-shop/reward-list/reward-list'
const tapTargetTargetDetail = '/pages/tap-target/target-detail/target-detail'
const tapSupervisionTargetDetail = '/pages/tap-supervision/target-detail/target-detail'
const tapTargetTargetComplete = '/pages/tap-target/target-complete/target-complete'
const tapSupervisionReviewedList = '/pages/tap-supervision/reviewed-list/reviewed-list'
const tapSupervisionTargetList = '/pages/tap-supervision/target-list/target-list'
const tapSupervisionRewardList = '/pages/tap-supervision/reward-list/reward-list'
const tapSupervisionRewardAdd = '/pages/tap-supervision/reward-add/reward-add'
const persionPath = '/pages/tap-persion/persion/persion'
const tapPersionReviewedList = '/pages/tap-persion/reviewed-list/reviewed-list'
const toTapPersionExchangeList = '/pages/tap-persion/exchange-list/exchange-list'
const tapSupervisionExchangeList = '/pages/tap-supervision/exchange-list/exchange-list'
const rewardPath = '/pages/reward/reward'
const tapShopExchangeDetail = '/pages/tap-shop/exchange-detail/exchange-detail'
const tapPersionExchangeDetail = '/pages/tap-shop/exchange-detail/exchange-detail'
let router = {
    toLogin() {
        wx.reLaunch({
            url: loginPath,
        })
    },
    toTapTargetTargetList() {
        wx.switchTab({
            url: tapTargetTargetList
        })
    },
    toTapShopRewardList() {
        wx.switchTab({
            url: tapShopRewardList
        })
    },
    toTapTargetTargetComplete(params) {
        console.log(params)
        let url = tapTargetTargetComplete;
        if (params instanceof Array) {
            if (params.length > 0) {
                url = url + '?'
                let key = null;
                let value = null;
                for ({key, value} of params) {
                    url = url + key + '=' + value + '&'
                }
                url.substring(0, url.length - 1)
            }
        }
        wx.navigateTo({
            url: url,
        })
    },
    toTapSupervisionReviewedList() {
        wx.navigateTo({
            url: tapSupervisionReviewedList,
        })
    },
    toTapShopExchangeDetail(params) {
        let url = tapShopExchangeDetail;
        if (params instanceof Array) {
            if (params.length > 0) {
                url = url + '?'
                let key = null;
                let value = null;
                for ({key, value} of params) {
                    url = url + key + '=' + value + '&'
                }
                url.substring(0, url.length - 1)
            }
        }
        wx.navigateTo({
            url: url,
        })
    },
    toTapPersionExchangeDetail(params) {
        let url = tapPersionExchangeDetail;
        if (params instanceof Array) {
            if (params.length > 0) {
                url = url + '?'
                let key = null;
                let value = null;
                for ({key, value} of params) {
                    url = url + key + '=' + value + '&'
                }
                url.substring(0, url.length - 1)
            }
        }
        wx.navigateTo({
            url: url,
        })
    },
    toTapSupervisionTargetList() {
        wx.navigateTo({
            url: tapSupervisionTargetList,
        })
    },
    toTapSupervisionRewardAdd() {
        wx.navigateTo({
            url: tapSupervisionRewardAdd,
        })
    },
    toTapTargetTargetDetail(params) {
        console.log(params)
        let url = tapTargetTargetDetail;
        if (params instanceof Array) {
            if (params.length > 0) {
                url = url + '?'
                let key = null;
                let value = null;
                for ({key, value} of params) {
                    url = url + key + '=' + value + '&'
                }
                url.substring(0, url.length - 1)
            }
        }
        wx.navigateTo({
            url: url,
        })
    },
    toTapSupervisionTargetDetail(params) {
        console.log(params)
        let url = tapSupervisionTargetDetail;
        if (params instanceof Array) {
            if (params.length > 0) {
                url = url + '?'
                let key = null;
                let value = null;
                for ({key, value} of params) {
                    url = url + key + '=' + value + '&'
                }
                url.substring(0, url.length - 1)
            }
        }
        wx.navigateTo({
            url: url,
        })
    },
    toTapPersionReviewedList() {
        wx.navigateTo({
            url: tapPersionReviewedList,
        })
    },
    toTapPersionExchangeList() {
        wx.navigateTo({
            url: toTapPersionExchangeList,
        })
    },
    toTapSupervisionExchangeList() {
        wx.navigateTo({
            url: tapSupervisionExchangeList,
        })
    },
    toTapSupervisionRewardList() {
        wx.navigateTo({
            url: tapSupervisionRewardList,
        })
    },
}

module.exports = router

其他页面需要跳转时,使用以下的方式

console.log('页面跳转')
that.data.router.toTapTargetTargetList()

1.5、其他模块
1.5.1、全局配置
主要定义了服务器的基础路径,没有其他的东西
1.5.2、页面之间的交互
这里是一个比较有趣的问题,就是比如你在添加任务的页面完成一个任务添加时,需要通知任务列表去刷新,拉取刚刚任务。小程序在页面切换的时候是不会主动刷新的,切过去是你上一次点击看到的内容,所以需要一个通知机制来做主动刷新操作,所以就设计了这个模块。
其主要也是通过globalData的字段来体现,当页面被调到栈顶的时候,主动监测一下是否需要刷新,要的话就先刷新数据再展示,否则还是展示之前内容。下面看看代码
targetTargetListInteractive.js

module.exports={
  isReload(){
    return getApp().globalData.isTargetTargetListReload;
  },
  setReload(){
    getApp().globalData.isTargetTargetListReload=true;
  },
  resetReload(){
    getApp().globalData.isTargetTargetListReload = false;
  },
  isPartRefresh(){
    return getApp().globalData.targetTargetListPartRefresh.length>0
  },
  setPartRefresh(target){
    getApp().globalData.targetTargetListPartRefresh.push(target)
  },
  resetPartRefresh(){
    let array = getApp().globalData.targetTargetListPartRefresh
    getApp().globalData.targetTargetListPartRefresh=[]
    return array
  }
}

看看任务列表页如果监听这个对象的机制
target-list.js

.....
onShow(){
        if (supervisionTargetListInteractive.isReload()) {//判断是否整个页面刷新
            //获取数据
            wx.pageScrollTo({
                scrollTop: 0,
                duration: 0
            })
            this.resetPage()
            this.loadTable()
            supervisionTargetListInteractive.resetReload()
        } else {//判断是否局部刷新
            if (supervisionTargetListInteractive.isPartRefresh()) {
                let newTargets = supervisionTargetListInteractive.resetPartRefresh()
                for (let target of newTargets) {
                    for (let i = 0; i < this.data.targets.length; i++) {
                        if (this.data.targets[i].id == target.id) {
                            this.setData({
                                ['targets[' + i + ']']: target
                            })
                        }
                    }
                }
            }
        }
    }
    ......

而在添加任务页面成功添加任务之后,需要调一下这个方法让任务列表刷新

 //让任务列表刷新
 targetListInteractive.setReload()

1.5.5、缓存模块
缓存模块主要是使用wx.setStorageSync()方法来进行本地缓存,主要是缓存用户数据。在开发的过程中,因为作者的手机网络比较慢,下载图片会很卡,每次读商城都要卡等一段时间,所以使用到了本地缓存,只要资源被下载过,就会缓存,不会二次下载。
store.js

let storeDownloadObj = require('../request/store/download-file')
let requestBuilder = require('../request/factory/requestObjBuilder')
let storeDao = {
    setStore(storeId,path){
        let stores = wx.getStorageSync('store')||{};
        stores[storeId]=path
        wx.setStorageSync('store', stores)
    },
    getStore(storeId){
        let stores = wx.getStorageSync('store')||{};
        return stores[storeId];
    },
    //下载图片资源并存储
    downloadPicture(storeId){
        let that = this
        let requetObj = JSON.parse(JSON.stringify(storeDownloadObj))
        requetObj.url = requetObj.url + "?storeId=" + storeId + ""
        wx.downloadFile(requestBuilder(requetObj, (res) => {
            console.log(res);
            console.log('下载资源:' + storeId + ' 成功,' + '临时目录:' + res.tempFilePath)
            //存储到本地
            wx.saveFile({
                tempFilePath: res.tempFilePath,
                success: function (res) {
                    console.log('存储到本地成功')
                    that.setStore(storeId, res.savedFilePath)
                }
            })

        }))
    }
}

module.exports = storeDao

1.5.6、工具
一些常用的工具对象,如时间转换等…

果然,唯有代码可以让我找回初心,那一个热爱编程的初生牛犊不怕虎的想进BAT男孩,hhhhh可是现在不是很想了,三个小时的回顾,1w+字,如果对您有帮助,希望给我一分鼓励~愿你我皆不忘初心!
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为女朋友写一个小程序(四)— —前端小程序的设计与实现 的相关文章

  • 非常厉害的全文检索技术Elasticsearch

    目录 一 Elasticsearch是什么 二 关于安装 三 kibana的安装和使用 最后 今天是刘小爱自学Java的第157天 感谢你的观看 谢谢你 全文检索技术Elasticsearch的学习 牵扯到的知识点太多太多了 首先要创建一个
  • Cadence Allegro PCB设计88问解析(九) 之 Allegro中封装(footprint)3D模型添加

    一个学习信号完整性的layout工程师 今天整理下PCB封装的3D 模型添加 此步骤并不是所有的公司使用 因为我们平常给器件添加一个实际的高度 就已经OK了 只不过我们在看整版的3D模型是 每个器件都是方方正正的 不太美观 所以有的人要求完
  • JavaScript基础

    编程之修 重在积累 而非资质 资质虽然重要 可是后天的努力更不可缺少 直接量 编程世界中的直接量 就是表面上可以见到的数据值 常见的直接量有数字 小数 字符串 字符串的出现必然带着双引号 单引号也可以 被很好地包裹住 而数字则是光秃秃的 如
  • 解决Opencv高低版本不兼容问题

    分享一下我老师大神的人工智能教程 零基础 通俗易懂 http blog csdn net jiangjunshow 也欢迎大家转载本篇文章 分享知识 造福人民 实现我们中华民族伟大复兴 目前OpenCV版本已更新到2 4 由此出现了一系列问
  • Qt之QSS中替代background-position的方法。

    学过css的朋友 应该都多少了解一些雪碧图相关的知识 雪碧图 用的就是background position来确定选取的素材位置 比如 素材中每张扑克的宽高分别为49px 66px 如果我要选用红桃8 我就会在css中写 backgroun
  • Gradle sync failed: A problem occurred configuring project ‘:app‘解决方法

    在terminal 中输入 gradlew i 查看详细信息 输出信息 NDK is missing a platforms directory If you are using NDK verify the ndk dir is set
  • vue项目中使用iconfont阿里图标库

    1 进入icon 官网 iconfont 阿里巴巴矢量图标库 2 根据搜索选择自己想要的图片 添加到项目中或者新建项目 如下图 3 添加之后如下图 点击下载至本地 4 下载本地解压后的文件如下图 5 在vue项目中 css新建一个文件夹 把
  • JS时间格式和时间戳的相互转换

    时间戳转化为日期的方式 var timestamp 1527521052 var newDate new Date newDate setTime timestamp 1000 Mon May 28 2018 console log new

随机推荐

  • 计算机视觉知识点-图像增强

    图像增强技术通过对训练图像进行一系列随机更改以生成相似但不同的训练示例来扩展训练数据集的规模 随机更改训练示例可以减少模型对某些属性的依赖 从而提高模型的泛化能力 我们可以以不同的方式裁剪图像 以使感兴趣的对象出现在不同的位置 从而减少了模
  • YoungTalk STM32入门第12步——CRC校验和芯片ID

    1 CRC 循环冗余校验 计算单元 2 96位芯片唯一序列号 1 CRC 循环冗余校验 计算单元 CRC计算单元使用一个固定的多项式发生器 从一个32位的数据字产生一个CRC码 在众多应用中 基于CRC的技术被用于验证数据传输或者存储的一致
  • Qt -信号槽实现原理

    一 简介 QT信号槽的实现实质是什么 回调函数 简要说一下信号与槽的底层原理 信号与槽的实现是借助了Qt 的元对象系统 元对象系统有一个元对象编译器 程序编译之前会有一个预处理过程 预处理将一个类 对象中的信号 槽的字符串值分别保存在一个容
  • 小白学股票基金_1

    债券要集资 利息比银行同等期限的高 但是不能随意提取现金 如果未到期就提取就不能按约定的利息给于 不可买卖 可以抵压 股票为单向交易 只能在低时进入买涨 T 1交易当天不能卖出 固定的开收盘时间 易受庄家控制 全资动作 多少钱买多少股 必须
  • lmg_Model Links and Torrents

    lmg Model Links and Torrents Changelog MDY 4 bit GPU Model Requirements 4 bit CPU llama cpp RAM Requirements LLaMA 16 bi
  • GraphicsLayer知识点

    require esri layers GraphicsLayer function GraphicsLayer code goes here 包含一个或多个图形特征的图层 每个地图都包含默认的GraphicsLayer 可以使用map g
  • 如何访问虚拟机中的Web服务

    需求 1 在虚拟机Vmware中安装了CentOS6 5 虚拟机使用NAT的方式 2 在CentOS中安装了APACHE 并且使用 http 192 168 237 128可以正常访问 3 想在其他windows机器上访问该虚拟机的web服
  • linux系统的系统性学习 (持续更新)

    分类 系统启动过程 第一步 内核的引导 第二步 运行 init 第三步 系统初始化 第四步 建立终端 第五步 用户登录系统 关机 查看系统基本信息 CPU相关 内存相关 查看网络信息 用户 服务 进程相关 磁盘管理 df 命令 du 命令
  • Thrift、Dubbo、Spring Cloud 和 gRPC

    何为RPC RPC Remote Procedure Call 远程过程调用 是一种进程间通信方式 是一种技术的思想 而不是规范 它允许程序调用另一个地址空间 通常是共享网络的另一台机器上 的过程或函数 而不用程序员显式编码这个远程调用的细
  • 计算机常用函数及写法,计算机常用的函数公式有哪些?

    01 计算机常用的函数公式包括RANK函数 COUNTIF函数 IF函数 ABS函数 AND函数 AVERAGE函数 COLUMN 函数等 RANK函数是Excel计算序数的主要工具 它的语法为 RANK number ref order
  • 现代OpenGL教程 01 - 入门指南

    文章转载自 http huangwei pro 2015 05 modern opengl1 以下是我学习opengl得到的启示最多的一篇文章 我强烈地建议大家去读一下这位大神的相关系列的文章 还有https github com tomd
  • Allegro约束管理器的设置

    1 打开约束管理器 2 设置管理器 黄色表示未打开 右击 选择analysis mode打开 3 添加物理规则 修改的数据 4 建立组 同时选中几个网络 右击选择Create New Group新建一个组 修改组的规则里面的网络也都跟着修改
  • Orangepi Zero2 全志H616 的初识

    Q 为什么要学习香橙派 A 在之前对于Linux系统的学习 其内容主要是对于系统API的掌握 而很难进行外设的交互 Linux系统很强大 如果能够结合外设 可以做出STM32 C52等单片机无法实现的复杂项目 而我们可以通过将Linux系统
  • Python 中导入csv数据的三种方法

    这篇文章主要介绍了Python 中导入csv数据的三种方法 内容比较简单 非常不错 具有一定的参考借鉴价值 需要的朋友可以参考下微点阅读小编收集的文章介绍 Python 中导入csv数据的三种方法 具体内容如下所示 1 通过标准的Pytho
  • lnmp集群的搭建及优化

    文章目录 lnmp 名词解释 搭建 mysql nginx php 一键安装 优化及应用 Discuz论坛搭建 php增加memcache模块 nginx添加memcache模块 tomcat lnmp 名词解释 LNMP是指一组通常一起使
  • 服务器上配置jupyter并使用浏览器远程连接

    一 服务器上配置jupyter 1 安装jupyter 执行两条安装命令 conda install ipykernel conda install jupyter 2 添加配置文件 jupyter notebook generate co
  • vi vim快捷键

    快捷键 行为 x 删除光标所在后面的字符 X 删除光标所在前面的字符 d e 删除光标所在位置到本单词末尾 d E 删除光标所在位置到本单词末尾包括标点符号 d b 删除光标所在位置到前面单词 d B 删除光标所在位置到前面单词包括标点符号
  • 机器学习——Boosting、提升树、随机森林(Random Forest)学习笔记

    大数据工作室学习打卡 第 N 次 一 Boosting 提升 1 什么是集成学习 首先 我们得先了解什么是集成学习 集成学习是一种通过组合弱学习器来产生强学习器的通用且有效的方法 简单来说 就是通过训练多个分类器 然后将其组合起来 从而达到
  • 定时开机电路设计

    在一些情况下 比如电池供电 需要定时采集数据并传输 并且对功耗要求比较高时 就需要电路实现采集完成后关机 且能够定时自动启动的功能 一种方法是 采集完成后 通过单片机关闭外围电路的电源 且单片机本身处于低功耗模式 只保留RTC工作 设置定时
  • 为女朋友写一个小程序(四)— —前端小程序的设计与实现

    为女朋友写一个小程序 一 目的与需求 为女朋友写一个小程序 二 数据库设计 为女朋友写一个小程序 三 基于springboot的服务器端接口设计与实现 为女朋友写一个小程序 四 前端小程序的设计与实现 本文 为女朋友写一个小程序 五 如何用