小程序开发常见的问题

596 阅读4分钟

APP研发总结和分享一些经常有人遇到的问题

Anthor:'林子'

1.使用的技术栈和讲述

使用的技术栈是安卓配合uniapp实现 独立开发 本身app研发并不难 有点体力活 就是对框架的再次运用与实现灵活封装 本次遇到的新知识就是map地图的 学习了map地图 发现可以做一个简单的美团外卖 不过应该有很多难关  不是我想的这么简单

2.app的页面快速封装(当然这些并不难)

onLoad(options) {
this.current=options.id
    //字典
const dict=['修改灯杆','控制器列表']
			let res=options.id
			this.current=res
			// 点击的那个页面的时候显示修改标题 就不要频繁为app修添加页面 增加内存消耗
		dict.forEach((v,index)=>{
			if(index==res){
				uni.setNavigationBarTitle({
					title:v
				})
			}
		})
},

image-20211208144619600

3重难点map地图的实现

//写入map便签
 <map style="width: 100%; height: 100%" id="map1" ref="map1" :show-location="true"
                     :latitude="map.latitude" :longitude="map.longitude" :scale="map.scale" :markers="map.covers"
                     @markertap="markertap"
                     @regionchange="regionchange" @updated="mapUpdated">
</map>

data(){
  return{
      map: {
        title: 'map',
        latitude: 22.862277018229168,
        longitude: 108.27395046657986,
        scale:10.5,
        covers: [],
        updated: false,
        oldMarker: undefined
      },
      QueryDeviceList: {
        input: {
          value: {
            "organizationId": undefined,      // id
            "searchKey": undefined,           // 关键字搜索
            "southwest": [],
            "northeast": []
          }
        },
        output: {
          value: [],
          currentDataShow: false,
          currentData: {},
          organizationName: undefined
        }
      }
  }  
}
created(){
    //uniapp获取经纬度
    uni.getLocation({
      type: 'gcj02', success: (res) => {
        console.log(res)
        this.setLocation(res)  //获取经纬度之后可以进行转换  然后据此搜索一波数据
        this.getRegion()  //获取视野
      }
    })
},
mounted(){
      //刚进页面设置一波显示的东西
      this.methods('setDeviceShow', false)
      this.methods('QueryDeviceListReset')
      //
      this.methods('setLocation', {latitude:this.map.longitude:this.map.longitude})
      await this.methods('getRegion')
      this.methods('setMoveToLocation')  //移动
      let data = await this.methods('queryFaultList',true)
      if (data) {
        this.methods('setCovers', data)
      }
    }
},
methods:{
    //地图加载完毕的事件
    async mapUpdated () {
        if (this.map.updated) return
        this.methods('setUpdated')
        this.methods('setMapContext')
        this.methods('setMoveToLocation')
        await this.methods('getRegion')
        console.log('queryFaultList------------------')
        let data = await this.methods('queryFaultList')
        console.log(data)
        if (data) {
          this.methods('setCovers', data)
        }
    },
    setUpdated(){
        this.map.updated = true
    },
    //算是绑定对象吧
    setMapContext () {
        this.mapContext = uni.createMapContext('map1')
        console.log(this.mapContext)
    },
    //设置中心点
    setLocation (data) {
        this.map.latitude = data.latitude
        this.map.longitude = data.longitude
    },
    //获取视野
    getRegion(){
        await new Promise(resolve => {
          this.mapContext.getRegion({
            success: (res) => {
              let southwest = [res.southwest.latitude, res.southwest.longitude]
              let northeast = [res.northeast.latitude, res.northeast.longitude]
              this.QueryDeviceList.input.value.southwest = southwest
              this.QueryDeviceList.input.value.northeast = northeast
              resolve()
            }
          })
        })
    },
    //设置视野
    setRegion (res) {
        let southwest = [res.southwest.latitude, res.southwest.longitude]
        let northeast = [res.northeast.latitude, res.northeast.longitude]
        this.QueryDeviceList.input.value.southwest = southwest
        this.QueryDeviceList.input.value.northeast = northeast
    },
    //移动
    setMoveToLocation () {
        this.mapContext.moveToLocation({
          latitude: this.map.latitude,
          longitude: this.map.longitude
        })
    },
    //根据请求的数据设置标记点的位置以及图标
    setCovers (data) {
        data.forEach((i, index) => {
          i.id = index
          i.width = 80
          i.height = 80
          i.deviceLabel = deviceLabel
          i.iconPath = '../../static/img/ddd.png'
          }
        })
        this.map.covers = data
    },
    //拖动视野
    async regionchange(data) {
        // if (data.detail.type === 'end' && data.detail.causedBy === "drag") {
        if (data.type === 'end' && data.causedBy === "drag") {
          console.log('地图视图改变')
          this.methods('setRegion', data.detail.region)
          //请求数据
          let list = await this.methods('queryFaultList')
          if (list) {
            this.methods('setDeviceShow', false)
            // 设置选中状态的markerId
            this.methods('setMarkerNoSelected')
            this.methods('setOldMarker', -1)
            this.methods('setCovers', list)
          }
        }
    },
    //点击标记点
    markertap(data) {
        console.log(data)
        let markerId = data.detail.markerId
        if (this.map.oldMarker === markerId) return
        // 显示标记详情
        this.methods('setDeviceShow', true)   //是否显示详情弹框
        this.methods('setDeviceData', markerId)  //显示的数据
        // 把上一次选中状态变成未选中
        this.methods('setMarkerNoSelected')

        // 图标改成选中状态
        this.methods('setMarkerSelected', markerId)
        // 设置选中状态的markerId
        this.methods('setOldMarker', markerId)
    },
    // 把图标上一次选中状态变成选中
    setMarkerSelected (markerId) {
        let markers = this.map.covers[markerId]
        if (markers && markers.iconPath) {
          let iconPath = markers.iconPath.split('.png')
          markers.iconPath = iconPath[0] + '_selected.png'
        }
    }
    // 把图标上一次选中状态变成未选中
    setMarkerNoSelected () {
        if (this.map.oldMarker || this.map.oldMarker === 0) {
          let oldMarker = this.map.covers[this.map.oldMarker]
          if (oldMarker && oldMarker.iconPath) {
            oldMarker.iconPath = oldMarker.iconPath.replace('_selected', '')
          }
        }
    }
}


2.总结一个一般初学者常见的遇到的问题

1对一些需求需要用到下载模板的api处理

// 下载
export function downloadExcel() {
  return request({
    url: 'api/projectCost/downloadExcel',//自己的下载api接口
    method: 'get',
    responseType: 'blob',
    headers: {
      'Content-Type': 'application/json'
    }
  }).then(res => {
    // new Blob([res])中不加data就会返回下图中[objece objece]内容(少取一层)
    const blob = new Blob([res], { type: 'application/vnd.ms-excel' })
    const fileName = '项目电费管理模板.xlsx'// 下载文件名称
    const elink = document.createElement('a')
    elink.download = fileName
    elink.style.display = 'none'
    elink.href = URL.createObjectURL(blob)
    document.body.appendChild(elink)
    elink.click()
    URL.revokeObjectURL(elink.href) // 释放URL 对象
    document.body.removeChild(elink)
  })
}
//写好了就在需要用的地方调用这个函数就行
data(){
    return{
        ..........
        methods:{
            click(){
                downloadExcel()//api
            }
        }
    }
}

2把文件上传到后台的代码做一个详情的讲解


<template>
  <el-form :model="form">
    <el-form-item label="上传文件" :label-width="formLabelWidth">
      <el-upload
        ref="uploadExcel"
        class="upload-demo"
        :limit="limitNum"//文件的限制  比如设置5就是只能最大限制5个
        :auto-upload="false"
        accept=".xlsx"
        :before-upload="beforeUploadFile"//文件上传之前的回调
        :on-change="fileChange"//文件改变触发的回调
        :on-exceed="exceedFile"//超出限制的回调
        :on-success="handleSuccess"//成功的回调
        :on-error="handleError"//失败的回调
        :file-list="fileList"
        :headers="headers"
        :action="CostApi"//您要上传的api接口
      >
        <i class="el-icon-upload" />
        <el-button size="small" plain>选择文件</el-button>
        <div slot="tip" class="el-upload__tip">只能选择excel文件</div>

      </el-upload>
    </el-form-item>
    <el-form-item>
      <el-button type="success" @click="download">下载模板</el-button>

    </el-form-item>
    <el-form-item>
      <div class="foot">
        <el-button size="small" @click="cancel">取消</el-button>
        <el-button size="small" type="primary" @click="uploadFile">立即上传</el-button>
      </div>
    </el-form-item>

  </el-form>
</template>

<script>
import { getToken } from '@/utils/auth'
import { mapGetters } from 'vuex'
import { downloadExcel } from '@/api/operation/cost.js'
import { header, crud } from '@crud/crud'
export default {
  mixins: [header(), crud()],
  data() {
    return {
      headers: { 'Authorization': getToken() },
      limitNum: 5,
      formLabelWidth: '80px',
      form: {
        file: ''
      },
      fileList: []
    }
  },
  computed: {
    ...mapGetters([
      'baseApi',
      'CostApi'
    ])
  },
  methods: {
    // 下载模板
    download() {
      downloadExcel()
    },
    //   取消
    cancel() {
      this.$emit('cancel')
    },
    // 文件超出个数限制时的钩子
    exceedFile(files, fileList) {
      this.$notify.warning({
        title: '警告',
        message: `只能选择 ${this.limitNum} 个文件,当前共选择了 ${files.length + fileList.length} 个`
      })
    },
    // 文件状态改变时的钩子
    fileChange(file, fileList) {
      this.form.file = file.raw
      console.log(this.form.file)
    },
    // 上传文件之前的钩子, 参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传
    beforeUploadFile(file) {
      this.$emit('upload')
      // console.log('before upload')
      // console.log(file)
      const extension = file.name.substring(file.name.lastIndexOf('.') + 1)
      const size = file.size / 1024 / 1024
      if (extension !== 'xlsx') {
        this.$notify.warning({
          title: '警告',
          message: `只能上传Excel2017(即后缀是.xlsx)的文件`
        })
      }
      if (size > 10) {
        this.$notify.warning({
          title: '警告',
          message: `文件大小不得超过10M`
        })
      }
    },
    // 文件上传成功时的钩子
    handleSuccess(res, file, fileList) {
      this.$notify.success({
        title: '成功',
        message: `文件上传成功`
      })
      this.crud.refresh()
    },
    // 文件上传失败时的钩子
    handleError(file, fileList) {
      this.$notify.error({
        title: '错误',
        message: `文件上传失败`
      })
    },
    uploadFile() {
      this.$refs.uploadExcel.submit()
    }
  }
}
</script>

<style lang="scss" scoped>
.foot{
margin-left: 75%;
}
</style>

3自己简单的封装tabs

<template>
	<view class="facilty">
		<view class="map">
			<map style="width: 93%;" :latitude="latitude" :longitude="longitude"></map>
		</view>
		
		<view class="tab">
			<view class="tab-left" @click="change(0)"  :class="[current==0?'activeTab':'text']">//点击哪个的时候自己就加样式
				<view class="tab-title">
				tabs1
				</view>
			</view>
			<view @click="change(1)" class="tab-right"  :class="[current==1?'activeTab':'text']">
				<view class="tab-title" style="margin-left: 30rpx;">
					tabs2
				</view>
			</view>
		</view></view>
		
		</block>
	
	</view>
</template>

<style>
    .text{
		background-color: #FFFFFF;
	}
	.facilty {
		background-color: #f2f2f2;
	}
</style>



本地存储的使用

  let a=localStorage.setItem('lin',JSON.stringify([1,2,3,6]))
 
  console.log( JSON.parse(localStorage.getItem('lin')) );

小程序获得用户头像信息

login() {
				
				uni.getUserProfile({
					desc: '用于完善会员资料',//必须填
					success: (res) => {
						console.log(res)
					}
				})
			},

vue实现文件上传


<template>
  <el-form :model="form">
    <el-form-item label="上传文件" :label-width="formLabelWidth">
      <el-upload
        ref="uploadExcel"
        class="upload-demo"
        :limit="limitNum"
        :auto-upload="false"
        accept=".xlsx"
        :before-upload="beforeUploadFile"
        :on-change="fileChange"
        :on-exceed="exceedFile"
        :on-success="handleSuccess"
        :on-error="handleError"
        :file-list="fileList"
        :headers="headers"
        :action="CostApi"
      >
        <i class="el-icon-upload" />
        <el-button size="small" plain>选择文件</el-button>
        <div slot="tip" class="el-upload__tip">只能选择excel文件</div>

      </el-upload>
    </el-form-item>
  </el-form>
</template>

<script>
import { getToken } from '@/utils/auth'
import { mapGetters } from 'vuex'
import { downloadExcel } from '@/api/operation/cost.js'
import { header, crud } from '@crud/crud'
export default {
  mixins: [header(), crud()],
  data() {
    return {
      headers: { 'Authorization': getToken() },
      limitNum: 5,
      formLabelWidth: '80px',
      form: {
        file: ''
      },
      fileList: []
    }
  },
  computed: {
    ...mapGetters([
      'baseApi',
      'CostApi'
    ])
  },
  methods: {

    // 文件超出个数限制时的钩子
    exceedFile(files, fileList) {
      this.$notify.warning({
        title: '警告',
        message: `只能选择 ${this.limitNum} 个文件,当前共选择了 ${files.length + fileList.length} 个`
      })
    },
    // 文件状态改变时的钩子
    fileChange(file, fileList) {
      this.form.file = file.raw
      console.log(this.form.file)
    },
    // 上传文件之前的钩子, 参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传
    beforeUploadFile(file) {
      this.$emit('upload')
      // console.log('before upload')
      // console.log(file)
      const extension = file.name.substring(file.name.lastIndexOf('.') + 1)
      const size = file.size / 1024 / 1024
      if (extension !== 'xlsx') {
        this.$notify.warning({
          title: '警告',
          message: `只能上传Excel2017(即后缀是.xlsx)的文件`
        })
      }
      if (size > 10) {
        this.$notify.warning({
          title: '警告',
          message: `文件大小不得超过10M`
        })
      }
    },
    // 文件上传成功时的钩子
    handleSuccess(res, file, fileList) {
      this.$notify.success({
        title: '成功',
        message: `文件上传成功`
      })
      this.crud.refresh()
    },
    // 文件上传失败时的钩子
    handleError(file, fileList) {
      this.$notify.error({
        title: '错误',
        message: `文件上传失败`
      })
    },
    uploadFile() {
      this.$refs.uploadExcel.submit()
    }
  }
}
</script>

<style lang="scss" scoped>
.foot{
margin-left: 75%;
}
</style>

nodejs

1.获得请求报文 不写则获取不到值

// 定义内置中间件来获取请求报文
app.use(express.urlencoded())
app.use(express.json())
//get 拿到请求报文是req.query
//这种的get /delectHero/:id拿取是req.params
//post是req.boby

2.在全局注册mysql

let execSql=require("./util/sql")
// 注入全局
app.use((req,res,next)=>{
    res.execSql=execSql
    // 触发下一个函数的执行
    next()
})
// 导入并注册中间件
const heroRouter=require("./Router/heroRoter")
app.use("/hero",heroRouter) 需要拼接/hero

3生成token

下载第三方包
const josnwebtoken=require('jsonwebtoken')
function creattoken(username){
//   定义一个加密的密码
  // jsonwebtoken.sign(表示你要给token添加的数据对象,加密的密码,token的过期时间)
let tokenpwd=TOKENPW
let expiresIn={ expiresIn: 60*60 }
return "Bearer "+ josnwebtoken.sign({username},tokenpwd,expiresIn)
}

用法

Router.get("/login",(req,res)=>{
    let {username,password}=req.query
    if(!username||!password){
        res.send({code:201,mag:"请输入账号或者密码"})
        return
    }
let sql=`select * from user where username = '${username}' and password ='${password}'`
res.execSql(sql,(err,result)=>{
    if(err){
        res.send({ code: 500, msg: err.message })
        return
    }
    if(result.length<=0){
        res.send({code:201,mag:'该账号不存在'})
        return
    }
    res.send({code:200,msg:"登入成功",token:creattoken(username)})
})
})