Vue, App与我(十三)
前言:
- Big-man需要开发一个论坛模块, 论坛模块的话,简而言之, 就是一个发帖和回帖的模块。但是Big-man的这个论坛模块还是比较复杂的。在接下来的实现中Big-man会进一步地去进行分析。所以Big-man怀着好奇的心态进入了移动端的论坛模块。
首页:
- 从这个首页的设计图上就可以得出, 需求是多么地繁杂,特别是涉及到图片上传这一块,原来的头像更换代码, 也是相当于图片上传。代码如下:
<template>
<div>
<div class="navTop">
<i class="iconfont back" onclick="javascript:history.go(-1)"></i>
<span class="navCon">图片</span>
<span class="publish" v-on:click="updateUser()" style="display:none;">保存</span>
</div>
<div class="ask pt45">
<div class="tips">
<p class="tips_title">修改图片</p>
</div>
<div class="text">
<div id="app">
<img id="picture_sourceimg" :src="picture" width="600" height="800">
<input type="hidden" id="picture" name="picture" value="picture" ref="picture">
<div class="weui_uploader_input_wrp" v-on:click="changeUpload()"></div>
</div>
</div>
</div>
</div>
</template>
<input type="hidden" id="picture" name="picture" value="picture" ref="picture">
- input 标签代码中的
type=hidden
是定义隐藏的字段,这里这样写主要是想要通过样式实现如下的效果:
- 查看如下的样式修饰代码:
<style scoped>
.navTop .publish{ height:0.45rem; padding-right:0.15rem; color:#ffffff; font-size:0.15rem; line-height:0.45rem;}
.pt45{ padding-top:0.45rem; overflow:hidden;}
.ask{ overflow:hidden; }
.ask .text{ overflow:hidden; padding:0.15rem;}
.ask .text textarea{ width:90%; padding:5%; overflow:hidden; border:none; outline:none; background:#ffffff;}
.ask .tips{ padding:0 0.15rem; overflow:hidden; color:#a5a5a5; font-size:0.12rem;background-color: #E8E5E5;padding-bottom:0.15rem;}
.tips .tips_title{font-size:20px;font-weight:500;padding-top:0.15rem;color:#000000}
ul { list-style: none outside none; margin:0; padding: 0; }
li { margin: 0 10px; display: inline; }
#app{overflow: hidden;text-align: center;}
img {overflow: hidden; width: 150px;height:150px; border-radius: 150px; border: 1px solid #284baa; margin: auto;float: left;display: inline;margin-bottom: 10px;}
.weui_uploader_input_wrp {float: right;position: relative;margin-right: 9px;margin-bottom: 9px;width: 77px; height: 77px;border: 1px solid #d9d9d9;}
.weui_uploader_input_wrp:before {width: 2px;height: 39.5px;}
.weui_uploader_input_wrp:after {width: 39.5px;height: 2px;}
.weui_uploader_input_wrp:before {content: " ";position: absolute;top: 50%;left: 50%;-webkit-transform: translate(-50%,-50%);transform: translate(-50%,-50%);background-color: #d9d9d9;}
.weui_uploader_input_wrp:after, .weui_uploader_input_wrp:before {content: " ";position: absolute; top: 50%;left: 50%;-webkit-transform: translate(-50%,-50%);transform: translate(-50%,-50%);background-color: #d9d9d9;}
.weui_uploader_input {position: absolute;z-index: 1;top: 0;left: 0;width: 100%;height: 100%;opacity: 0;-webkit-tap-highlight-color: rgba(0,0,0,0);}
.weui_uploader_file {float: left; margin-right: 9px;margin-bottom: 9px;width: 79px;height: 79px;background: no-repeat 50%;background-size: cover;}
#picture_uploadimg{float: right;}
.photoclose {position: absolute;display: block;right: 0;top: 0;margin: 2px 2px 0 0;width: 23px;background: #fff;}
.photoshow {display: block;float: left;position: relative;margin-right: 8px;margin-top: 8px;overflow: hidden;zoom: 1;}
.contain {width:100%; height:300px;border:1px solid #ccc;}
</style>
- 其中最为主要的是实现图片上传的这部分代码:
<script>
import Error from '../components/Error.vue'
import Tab from '../components/Tab.vue'
import Config from '../config.js'
import {Toast} from 'mint-ui'
import Store from '../store.js'
export default {
components: {
Error,
Tab
},
data () {
return {
isError: false,
error: '',
picture:'',
whoami: 'user/whoami/',
govUrl:'user/update/'
}
},
beforeMount: function(){
if(Store.getAuthUid()){
this.$http.get(this.whoami,{}).
then((response) => {
const ret = JSON.parse(response.data);
if(ret && ret['code'] === 0){
if(!ret['picture']){
if(ret['wx_picture']){
this.picture = ret['wx_picture']
}else{
this.picture = Config.defaultPic
}
}else{
this.picture = Config.baseUrl + ret['picture']
}
}else{
this.$router.push('/login')
return
}
})
}else{
this.$router.push('/login')
return
}
},
methods: {
fullUrl: function(url) {
return Config.baseUrl + url
},
defaultPicUrl:function(){
return Config.defaultPic
},
changeUpload:function(e){
var share = {
action: 'uploadImage',
Authorization: 'Xyapp ' + Store.getAuthUid(),
api: '/user/upload/'
}
if(window.postMessage) window.postMessage(JSON.stringify(share),'*');
return true
},
updateUser: function(){
var picture = this.$refs.picture.value
this.getUpdate(picture)
},
getUpdate(picture) {
this.$http.post(this.govUrl,{picture:picture} ).then( (response) => {
const ret = JSON.parse(response.data || "[]")
if(ret && ret.code === 0){
Toast('操作成功!')
this.$router.push('/userset')
}else{
Toast(ret.msg)
this.error = (ret && ret.msg) || ""
this.isError = true
}
},(response) => {
this.isError = true
this.error = ""
if(callback) callback.call(this)
});
}
}
}
</script>
changeUpload()
函数事件也就是图片的加载事件, 具体代码如下:
changeUpload:function(e){
var share = {
action: 'uploadImage',
Authorization: 'Xyapp ' + Store.getAuthUid(),
api: '/user/upload/'
}
if(window.postMessage) window.postMessage(JSON.stringify(share),'*');
return true
},
- 在以上的代码中, Big-man在书写的时候还犯了一个致命的错误,且这个错误是因为Big-man的经验不足造成的,比如如下的代码:
Authorization: 'Xyapp ' + Store.getAuthUid(),
Authorization: 'Xyapp' + Store.getAuthUid(),
- 这两段代码大家可以仔细的推敲一下,在Big-man的书写过程当中就犯了这个错误,由此分享出来以供大家参考,引以为戒。
- 在图像上传的时候, Big-man的这个项目沿用的是以前的代码, 也就是每点击一下去执行一下
changeUpload()
函数,而action的函数是在打包代码里面,这里的Big-man的打包代码是react-native
。如下便是代码:
import config from "../config/config";
import ImagePicker from 'react-native-image-picker'; //第三方相机
import {Platform, Alert} from 'react-native'
import Log from "../utils/LogUtil";
var UpLoadImage = {
//上传图片
upload: function(message,callback,showTips,hidTips) {
Log.log("####进入方法内:"+message.api);
config.Authorization = message.Authorization;
let photoOptions = {
//底部弹出框选项
title:'请选择',
cancelButtonTitle:'取消',
takePhotoButtonTitle:'拍照',
chooseFromLibraryButtonTitle:'选择相册',
quality:0.3,
allowsEditing:true,
noData:false,
storageOptions: {
skipBackup: true,
path:'images'
}
};
// 选择图片
ImagePicker.showImagePicker(photoOptions,(response) => {
if (response.didCancel){
Log.log('User cancelled image picker');
return;
} else if (response.error) {
Log.log('ImagePicker Error: ', response.error);
return;
} else if (response.customButton) {
Log.log('User tapped custom button: ', response.customButton);
return;
}
if (Platform.OS === 'ios') {
const source = {uri: response.uri.replace('file://', ''), isStatic: true};
this.uploadImageNetWork(source.uri,callback,message,showTips,hidTips);
} else {
const source = {uri: response.uri, isStatic: true};
this.uploadImageNetWork(source.uri,callback,message,showTips,hidTips);
}
});
},
// 上传图片的网络请求
uploadImageNetWork : function(uri,callback,message,showTips,hidTips) {
let split = uri.split('/');
let p = split[split.length - 1];
// 这里还没有对 Uri 的非空判断
let formData = new FormData();
let file = {uri, type: 'multipart/form-data', name: p};
// name截取Uri的最后字段
formData.append("file",file); //这里的files就是后台需要的key
showTips();
fetch(config.api+message.api,{
method:'post',
// mode: "cors",// 允许跨域访问
headers:{
'Authorization':config.Authorization,
'Content-Type':'multipart/form-data',
},
body:formData,
}).then((response) => {
if (response.ok){
hidTips();
Alert.alert('提示','上传成功',[{text:'确定',onPress:()=>{}}]);
callback();
}else {
hidTips();
Alert.alert('提示','上传失败',[{text:'确定',onPress:()=>{}}]);
}
}).catch((e)=>{
hidTips();
Alert.alert('提示','系统错误',[{text:'确定',onPress:()=>{}}]);
});
}
}
export default UpLoadImage
- 更新图片的逻辑很是复杂,Big-man会在接下来分析一下图片的上传过程。
进入图片更新页面之前:
- 在进入图片更新之前, Big-man需要去插入一条空的数据, 类似于下面的代码:
common: function () {
let type = 3
this.$http.get(this.barAddUrl + type + '/').then((response) => {
const ret = JSON.parse(response.data || "[]")
if(ret && ret.code === 0) {
this.id = ret.id
this.$router.replace('/postcommon/' + this.id)
} else {
Toast(ret.msg)
}
})
},
- 因为Big-man书写的论坛里面还存在帖子的类型(活动帖和普通帖), 所以在这一步同时也需要上传一个类型(
type
值),接下来看数据分析:
barAddUrl
的代码分析:
$app->get('/bar/add/{type}/', function($request, $response, $args) {
global $g_tbwuserid,$timestamp,$g_city_id;
if ($g_tbwuserid > 0) {
$bar = [];
$bar['type'] = $args['type'];
$bar['istop'] = 1;
$bar['addtime'] = $timestamp;
$bar['cityid'] = $g_city_id;
$ret = template_add('cache_postbar', NO_CHECK_POWER, $bar, $request,$response);
}else{
$ret['code'] = 1;
$ret['msg'] = COMMENT_LOGIN;
return_result($request, $response, $ret);
}
return $response;
});
- 后台是采用
PHP
书写的代码, 这样的操作是为了方便图片的插入, Big-man这样去想过这个数据的走势,图片需要插入,但是图片处理需要与bar
的主键值(也就是上图中的id值)结合起来(不然怎么知道这张图片是是那个帖子的图片了),但是这个id
值是DataBase
自带的自增属性值(这里Big-man并没有对每一个帖子设计一个主键值,因为MySQL
中自带的数据库递增值,很明显可以处理完这类的需求),对于操作过的小伙伴们很明白这一点的,所以我在图片上传的页面需要知道这个id
值,如下图:
- 上图中的
linkid
也就是我这里的barid
,与这个barid
对应的也就是上述中的id
值。
插入一条空数据:
- 很多的小伙伴可能会存在像Big-man这样的疑问,为什么需要去插入一条空数据了?插入一条空数据有什么意义了?
- 占过座的伙伴们或者暗恋过别人的伙伴们就比较好理解这个内容,为什么了?因为这群伙伴很明白自己所占的东西虽然是空白的没人使用,但是却是实实在在属于自己的物品。
- 插入图片前插入一条空数据也是同样的道理的,虽然那是一条空的数据, 但是却是属于这部分上传图片的空数据,当图片上传进来的时候,就回归到这条空数据上的。当其他数据想要来强行插入的时候,不好意思,没有那个通行证的同志不准进入。
图片上传刷新页面:
react-native
中的机制,上传图片是app
触发的,所以需要查看app
的代码。代码在上一部分已经给出,react-native
老实说Big-man不是很熟悉, 曾经在一个大项目中接触过几个简单的功能,曾经的Big-man还被一位经验丰富的面试官打击了,曾经的历程就不再赘述。
react
基本语法:
- Big-man先来解释一下
react
的基本语法:
ReactDOM.render()
: 就这个问题曾经有一位伙伴问过Big-man这个问题,React
中的render()
如何理解, Big-man沉思了一下,就在这时这位伙伴又发过来说是不是渲染的含义,Big-man就回复了如果你在牛津英汉词典或者有道翻译上都是这个解释,而且还会出现是计算机专业名称解释,但是如果是渲染的话,Big-man想不通,浏览器加载任何一个静态的html
文件,也会称作浏览器渲染,但是为什么html
文件里面没有render
这个词汇,既然是说react
中的render
,Big-man就应该从react
这群开发者”怪咖”出发,
Jackdan9 Thinking