做完小程式專案、老闆給我加了6k薪資~

蘇南發表於2019-03-03

     大家好,我是@IT·平頭哥聯盟首席填坑官——蘇南(South·Su),今天要給大家分享的是最近公司做的一個小程式專案,過程中的一些好的總結和遇到的坑,希望能給其他攻城獅帶來些許便利,更希望能像標題所說,做完老闆給你加薪~

ç¸å…³å¾ç

  今天是中秋節的第一天,假日的清晨莫名的醒的特別早,不知道為什麼,也許是因為,昨晚公司上線的專案回來的路上,發現了個小bug,心裡有些忐忑吧~~

ç¸å…³å¾ç

以上純為扯淡,現在開始一本正經的裝逼,請繫好安全帶,中間過程有可能會開車,請注意安全!!!!!

  最近這個專案跟團隊小夥伴溝通在眾多框架中最後選擇了wepy,沒有直接用原生的,小程式原生就……,大家都懂的,用wepy框架,給自己帶來了便利,也帶來了不少坑,但縱是如此,我還是懷著:“縱你虐我千百遍,我仍待你如初戀”的心態去認真把專案做好。

toast元件

  • toast元件,大家都知道,官方的api wx.showToast 是滿足不了我們的需求的,因為它只支援 “success”, “loading“兩種狀態,同時“ title 文字最多顯示 7 個漢字長度”,這是官方原話,有圖有真相哦,樣式巨醜~

做完小程式專案、老闆給我加了6k薪資~

wx.showToast({
  title: `成功`,
  icon: `success`,
  duration: 2000
})
wx.showModal({
  title: `提示`,
  content: `這是一個模態彈窗`,
  success: function(res) {
    if (res.confirm) {
      console.log(`使用者點選確定`)
    } else if (res.cancel) {
      console.log(`使用者點選取消`)
    }
  }
})

複製程式碼

wx.showModal的content的文字是不會居中的(現在不確定有沒有擴充套件,可以設定),依稀記得有一次因為問題差點跟產品經理吵起來,讓文字居中,我說最少要兩小時,當時產品就炸了,什麼鬼???讓文字居中一下要兩小時??兩小時??兩小時??呵呵~走了,後來就下決定自己封裝了一個屬於自己的toast元件,以下為部分核心程式碼

âå´©æºæ´èµ° 表æ…å…âçå¾çæç´¢ç»æ

<template lang="wxml">
	
	<view class="ui-toast  {{ className }}" hidden="{{ !visible }}">
		<view class="ui-toast_bd">
			<icon wx:if="{{ options.icon}}" type="{{ options.icon }}" size="40" color="{{ options.color }}" class="ui-toast_icon" />
			<view class="ui-toast_text">{{ options.text }}</view>
		</view>
	</view>
</template>

<script>
	import wepy from `wepy`;
	const __timer__ =1900;
	//方法以 : __XX__ 命名,因併入其他元件中後,可能引起方法名重複
	class Toast extends wepy.component {
			
		/**
		 * 預設資料
		 */
		data={
			 list:[
				{
					type: `success`,
					icon: `success`,
					className: `ui-toast-success`,
				},
				{
					type: `cancel`,
					icon: `cancel`,
					className: `ui-toast-cancel`,
				},
				{
					type: `forbidden`,
					icon: `warn`,
					className: `ui-toast-forbidden`,
				},
				{
					type: `text`,
					icon: ``,
					className: `ui-toast-text`,
				},
			],
			timer:null,
			scope: `$ui.toast`, 
			animateCss:`animateCss`,
			className:``,
			visible:!1,
			options:{
				type: ``, 
				timer: __timer__, 
				color: `#fff`, 
				text: `已完成`, 
			}
		}
		/**
		 * 預設引數
		 */
		__setDefaults__() {
			return {
				type: `success`, 
				timer: __timer__, 
				color: `#fff`, 
				text: `已完成`, 
				success() {}, 
			}
		}
		/**
     * 設定元素顯示
     */
    __setVisible__(className = `ui-animate-fade-in`) {
    	this.className = `${this.animateCss} ${className}`;
    	this.visible = !0;
    	this.$apply();
    }

    /**
     * 設定元素隱藏
     */
    __setHidden__(className = `ui-animate-fade-out`, timer = 300) {
    	this.className = `${this.animateCss} ${className}`;
    	this.$apply();
      setTimeout(() => {
  			this.visible = !1;
  			this.$apply();
      }, timer)
    }
		/**
		 * 顯示toast元件 @IT·平頭哥聯盟,首席填坑官∙蘇南的專欄,梅斌的專欄
		 * @param {Object} opts 配置項
		 * @param {String} opts.type 提示型別
		 * @param {Number} opts.timer 提示延遲時間
		 * @param {String} opts.color 圖示顏色
		 * @param {String} opts.text 提示文字
		 * @param {Function} opts.success 關閉後的回撥函式
		 */
		__show__(opts = {}) {
			let options = Object.assign({}, this.__setDefaults__(), opts)
			const TOAST_TYPES = this.list;
			TOAST_TYPES.forEach((value, key) => {
				if (value.type === opts.type) {
					options.icon = value.icon;
					options.className = value.className
				}
			})
			this.options = options;
			if(!this.options.text){
				return ;
			};
			clearTimeout(this.timer);
			this.__setVisible__();
			this.$apply();
			this.timer = setTimeout(() => {
				this.__setHidden__()
				options.success&&options.success();
			}, options.timer);

		}
		__info__(args=[]){
			let [ message, callback, duration ]  = args;
	   	this.__show__({
		    type: `text`,
		    timer: (duration||__timer__),
		    color: `#fff`,
		    text: message,
		    success: () => {callback&&callback()}
		  });
	  }
	  __success__(args=[]){
	  	let [ message, callback, duration ]  = args;
	  	this.__show__({
		    type: `success`,
		    timer: (duration||__timer__),
		    color: `#fff`,
		    text: message,
		    success: () => {callback&&callback()}
		  });
	  }
	  __warning__(args){
			let [ message, callback, duration ]  = args;
	  	this.__show__({
		    type: `forbidden`,
		    timer: (duration||__timer__),
		    color: `#fff`,
		    text: message,
		    success: () => {callback&&callback()}
		  });
	  }
	  __error__(args){
	  	let [ message, callback, duration ]  = args;
	  	this.__show__({
		    type: `cancel`,
		    timer: (duration||__timer__),
		    color: `#fff`,
		    text: message,
		    success: () => {callback&&callback()}
		  });
	  }
	  __showLoading__(options){
	  	wx.showLoading({
			  title: (options&&options.title||"載入中"),
			});
	  }
	  __hideLoading__(){
	  	wx.hideLoading();
	  }
	  onLoad(){
      this.$apply()
    }
	}

	export default Toast;
</script>複製程式碼

呼叫示例:

<template>
	<view class="demo-page">
		<Toast />
		<Modals />
	</view>
</template>

<script>
	import wepy from `wepy` //@IT·平頭哥聯盟
	import Toast from `../components/ui/Toast`
	import Modals from `../components/ui/Modals`
	import {fetchJson} from `../utils/fetch`;

	export default class Index extends wepy.page {
		config = {
			navigationBarBackgroundColor: "#0ECE8D",
      navigationBarTextStyle:"white",
			navigationBarTitleText: ``
		}
		components = {
			Toast: Toast,
			Modals: Modals
		}
		methods = {
			tapToast(){
				this.$invoke("Toast","__success__",[`您已提交成功,感謝您的支援與配合`]);
			}	
		}
	}
</script>複製程式碼

做完小程式專案、老闆給我加了6k薪資~

Storage (資料儲存)

  • Storage (儲存)在前端我們儲存的方式,cookielocalStoragesessionStorage等這些,特性就不一一說明了,小程式裡大家都知道,資料儲存只能呼叫 wx.setStorage、wx.setStorageSync,相當於h5的localStorage,而 localStorage是不會過期的,這個大家都知道,而且在很多的面試中,面試官都會問到這個問題,怎麼讓localStoragecookie一樣,只存兩小時、兩天、甚至只存兩分鐘呢?今天帶你解惑,讓你在職場面試中又減少一個難題,這也是我們專案中一直在用的方式,小程式中也同樣實用:

做完小程式專案、老闆給我加了6k薪資~

class storage {

  constructor(props) {
    this.props = props || {}
    this.source =  wx||this.props.source;

  }

  get(key) {
    const data = this.source,
          timeout = (data.getStorageSync(`${key}__expires__`)||0)

    // 過期失效
    if (Date.now() >= timeout) {
      this.remove(key)
      return;
    }
    const value = data.getStorageSync(key)
    return value
  }

  // 設定快取
  // timeout:過期時間(分鐘)
  set(key, value, timeout) {
    let data = this.source
    let _timeout = timeout||120;
    data.setStorageSync(key,(value));
    data.setStorageSync(`${key}__expires__`,(Date.now() + 1000*60*_timeout));
 
    return value;
  }

  remove(key) {
    let data = this.source
        data.removeStorageSync(key)
        data.removeStorageSync(`${key}__expires__`)
    return undefined;
  }
}
module.exports = new storage();
複製程式碼

其實很簡單,大家看了之後就都 “哦,原來還可以這樣”  懂了,只是一時沒想到而已,就是個小技巧,每次在儲存的時候同時也存入一個時效時間戳,而在獲取資料前,先與當前時間比較,如果小於當前時間則過期了,直接返回空的資料。

做完小程式專案、老闆給我加了6k薪資~

介面API的維護

  • 介面API的維護,在沒有nodejs之前,前端好像一直都在為處理不同環境下呼叫對應的API而煩惱,做的更多的就是用域名來進行判斷,當然也有些高階一點的做法,後端在頁面渲染的時候,存一個變數到cookie裡或者在頁面輸出一個全域性的api變數(建立在沒有前後端分離的基礎上),到了小程式同樣也是如此,每次都要手動改環境,那麼一個專案可能有不同的業務,要呼叫不同域名api,又有不同的環境區分,怎麼維護會比較好呢??
env/dev.js
//本地環境
module.exports = {
	wabApi:{
		host:"https://dev-ali.southsu.com/XX/api/**",
	},
	questionApi:{
		host:"https://dev-ali.bin.com/question/api/**/question",
	},
	mockApi:{
		host:"https://easy.com/mock/594635**c/miniPrograms"
	},
	inWelApi: {
		host: "https://dev.**.com/Wab/api/escene/v2"   
	}
};
複製程式碼
 
import dev from `./env/dev`; //本地或開發
import uat from `./env/pre`; //體驗環境
import prd from `./env/prd`; //線上


var ENV = "prd"; //`dev | uat | prd`;
let _base_ = {
  dev,
  uat,
  prd
}[ENV];
var config = {
  ENV,
  baseAPI:{..._base_, env : ENV },
  appID:"wx*****b625e", //公司賬號(指數)appid
  isAuthorization:true,
  `logId`: `gVDSMH****HAas4qSSOTb-gzGzoHsz`,
  `logKey`: `pxFOg****Jn3JyjOVr`,
  questionnaireNo:`z**Insu` // 問卷調查編號
};
export const __DEBUG__ = (ENV!="prd");
export default  config;
複製程式碼
請求呼叫api處理的示例

import wepy from `wepy`
import _login_ from `./login`;
import config,{__DEBUG__} from `./config`;
import `wepy-async-function`;
export const  fetchJson = (options)=>{
	/*
	 *  請求前的公共資料處理,首席填坑官∙蘇南的專欄,梅斌的專欄
	 * @ param {String} 	url 請求的地址
	 * @ param {String} 	Type 請求型別
	 * @ param {String} 	sessionId 使用者userToken
	 * @ param {Boolean} 	openLoad 開啟載入提示,預設開啟,true-開,false-關
	 * @ param {function} StaticToast 靜態提示方法 ,詳細說明請參考 components/ui/Toast
	 * @ param {Object} 	header 重置請求頭
	 * @ param {Boolean} 	isMandatory 是否強制使用者授權,獲取使用者資訊
	*/

	StaticToast = getCurrentPages()[getCurrentPages().length - 1];
	let { url,openLoad=true, type, data={},header={}, ...others } = options||{};
	let sessionId = (Storage.get(__login__.server+`_userToken`)||"");
	/*Start */
       
        var regExp = //(.*?)//,
        hostkey = url.match(regExp)[1];
	let baseUrl = config.baseAPI[hostkey].host;
	url = url.replace(regExp, `/`);

	/*End */

	__DEBUG__&&console.log(`#--baseUrl:`, baseUrl);
	__DEBUG__&&console.log(`#--請求地址:`, `${baseUrl}${url}`);
	__DEBUG__&&console.log(`----------分割線---------------`);
	openLoad&&StaticToast.__showLoading__();
	return new Promise((resolve, reject) => {
		return wepy.request({
			url:`${baseUrl}${url}`,
			method:(type || `POST`),
			data,
			header:{
				"t9oken":sessionId,
				`content-type`: `application/json`,
				// `Content-Type`: `application/x-www-form-urlencoded; charset=UTF-8`,
				...header
			},
			success:(res)=>{
				StaticToast.__hideLoading__();
				return resolve(resHandler(res,options));
			},
			error:(err,status)=>{
				StaticToast.__hideLoading__();
				return reject(errorHandler(err,options,err.statusCode));
			}
		});
	})
	

複製程式碼

業務呼叫示例

fetchJson({
	type:"post",
	// url:"/mockApi/service/XXX", 最後請求得到的地址是 https://easy.com/mock/594635**c/miniPrograms/service/XXX (域名不同環境不一樣,在config裡的 ENV baseAPI控制)
	data:{
		name:"蘇南"
	},
	success:res=>{
		console.log(`大家好,我是@IT·平頭哥聯盟-蘇南`,res)
		
	}
})
複製程式碼

做完小程式專案、老闆給我加了6k薪資~

填坑時間了

  • 填坑時間了wepy框架中每個元件內的生命週期回撥 onload,只要是引入了元件,不管你檢視有沒有渲染,他都會執行,導致某些業務邏輯用不上它的時候也執行了產生異常(當然為個鍋< 小程式 >肯定說我不背~^~ ),詳細看連結:github.com/Tencent/wep… , github.com/Tencent/wep…   ,不知道後面有沒有人解決。

rich-text元件

  • rich-text,小程式的一個元件,雖然有那麼一點點用處,但又不得不說到底要它何用啊?其它的我就忍了,a標籤,a標籤啊,屬性沒有,那還要它何用啊,你都不要我跳轉,我還要用你嗎?b、i、span、em……哪個我不能用?不知道設計這個元件的人是不是腦被驢踢了(願老天保佑,我在這罵他,可千萬別被看到了,哈哈~),又是業務需求後臺配置的內容有連結,沒辦法,來吧,搞吧,往死裡搞吧,一切的推脫都是你技術low的藉口(你看,你看,別人的怎麼可以跳轉啊,別人怎麼做到的?給我一刀,我能把產品砍成渣),所以有了後面的填坑:

做完小程式專案、老闆給我加了6k薪資~

做完小程式專案、老闆給我加了6k薪資~

做完小程式專案、老闆給我加了6k薪資~

<template>
	<view class="test-page">
			<button @tap="cutting">點選解析html</button>
			<view wx:if="{{result.length>0}}" class="parse-list">
					<view  class="parse-view" wx:for="{{result}}" wx:key="unique" wx:for-index="index" wx:for-item="items">
							<block wx:if="{{items.children&&items.children.length}}">
									<block wx:for="{{items.children}}" wx:for-item="child" >
											<text wx:if="{{child.type == `link`}}" class="parse-link" @tap="goToTap({{child.link}})">{{child.value}}</text>
											<text class="parse-text" wx:else>{{child.value}}</text>
									</block>
							</block>
							<text class="parse-text" wx:else>{{items.value}}</text>
					</view>
			</view>
			<Toast />
			<Modals />
	</view>
</template>

<script>
        //首席填坑官∙蘇南的專欄,梅斌的專欄
	import wepy from `wepy`
	import { connect } from `wepy-redux`
	import Toast from `../components/ui/Toast`
	import Modals from `../components/ui/Modals`
	import {fetchJson} from `../utils/fetch`;
	import Storage from "../utils/storage";

	function wxHtmlParse(htmlStr=``){
			if(!htmlStr){
					return []
			};
			const httpExp  =/(http://|https://)((w|=|?|.|/|&|-)+)/g;//提取網址正則
			const aExp=/<a.[^>]*?>([(^<a|sS)]*?)</a>/ig; //a標籤分割正則
			let cuttingArr = htmlStr.split(/[
]/);
			let result = [];
			//有a標籤的html處理
			let itemParse = (itemHtml=``)=>{
					let itemCutting = itemHtml.split(aExp)||[];
					let itemResult = [];
					for(var i = 0;i<itemCutting.length;i++){
							let _html = itemCutting[i];
							if(_html!==``){
									let itemData = {
											value:_html,
											type:`text`,
											class:"parse-text"
									};
									let matchTag = itemHtml.match(aExp)||[]; //再次匹配有 a 標籤的
									if(matchTag.length){
											let itemIndex = matchTag.findIndex((k,v)=>(k.indexOf(_html)!==-1));
											if(itemIndex>=0){
													let link = matchTag[itemIndex].match(httpExp)[0];
													itemData.type = `link`;
													itemData.link = link;
													itemData.class = "parse-link";
											};
									};
									itemResult.push(itemData)
							}
					};
					return itemResult;
			};
			cuttingArr.map((k,v)=>{
					let itemData = {type : "view",class:"parse-view"};
					let isATag = k.match(aExp);
					if(isATag){
							itemData.children = itemParse(k);
					}else{
							itemData.value = k;

					};
					result.push(itemData);
					return k;
			}) ;
			return result;
	};
	export default class Index extends wepy.page {
			config = {
					navigationBarBackgroundColor: "#0ECE8D",
					navigationBarTextStyle:"white",
					navigationBarTitleText: `小程式解析資料中的a標籤`
			}
			components = {
					Toast: Toast,
					Modals: Modals
			}
			data = {
					html:`大家好,我是蘇南(South·Su),
職業:@IT·平頭哥聯盟-首席填坑官,
身高:176cm,
性別:男,
性取向:女,
公司:目前就職於由騰訊、阿里、平安三巨頭合資的一家網際網路金融公司深圳分公司某事業部、,
簡介:寶劍鋒從磨礪出 梅花香自苦寒來,認真做自己,樂於分享,希望能盡綿薄之力 助其他同學少走一些彎路!,gitHub:https://github.com/meibin08/,
興趣:跑步、羽毛球、爬山、音樂、看書、分享自己的微薄知識幫助他人……,
其他:想了解更多嗎?可以加入<a href="https://honeybadger8.github.io/blog/#/">386485473交流群</a>,也可以給我電話<a href="https://github.com/meibin08/">134XX852xx5</a> ,開玩笑啦`,
					result:[]
			}
			methods = {
				cutting(e){
					this.result = wxHtmlParse(this.html);
					console.log(`result`,this.result);
					this.$apply();
				},
					
			}
			
	}
</script>複製程式碼


PS完整示例原始碼 來啦~,覺得不錯記得 Star、StarWatch 哦,感謝!

今天的分享就到這裡,寫了蠻久,最近才在開始嘗試寫部落格,新手上路中,如果文章中有不對之處,煩請各位大神斧正。如果你覺得這篇文章對你有所幫助,請記得點贊哦~,想了解我更多?歡迎關注下方公眾號

做完小程式專案、老闆給我加了6k薪資~

作者:蘇南 – 首席填坑官
交流群:912594095,公眾號:honeyBadger8
本文原創,著作權歸作者所有。商業轉載請聯絡@IT·平頭哥聯盟獲得授權,非商業轉載請註明原連結及出處。

本次徵文活動的連結:juejin.im/post/5b923a…

相關文章