做完小程序項目、老闆給我加了6k薪資~

本文由@IT·平頭哥聯盟-首席填坑官∙蘇南分享

  大家好,這裏是@IT·平頭哥聯盟,我是首席填坑官——蘇南(South·Su),今天要給大家分享的是最近公司做的一個小程序項目,過程中的一些好的總結和遇到的坑,希望能給其他攻城獅帶來些許便利,更希望能像標題所說,做完老闆給你加薪
自古深情留不住,唯有套路得人心

  今天是中秋節的第一天,假日的清晨莫名的醒的特別早,不知道爲什麼,也許是因爲,昨晚公司上線的項目回來的路上,發現了個小bug,心裏有些忐忑吧,一會偷偷先改了,讓領導發現這個月績效就沒了~~~~

蜜獾(huan),綽號

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

  最近這個項目跟團隊小夥伴溝通在衆多框架中最後選擇了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組件
         * @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'
    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>

@IT·平頭哥聯盟主要分享`前端、測試` 等領域的積累

Storage (數據存儲)

Storage (存儲)在前端我們存儲的方式,cookielocalStoragesessionStorage等這些,特性就不一一說明了,小程序裏大家都知道,數據存儲只能調用 wx.setStorage、wx.setStorageSync,相當於h5的localStorage,而 localStorage是不會過期的,這個大家都知道,而且在很多的面試中,面試官都會問到這個問題,怎麼讓localStorage像cookie一樣,只存兩小時、兩天、甚至只存兩分鐘呢?今天帶你解惑,讓你在職場面試中又減少一個難題,這也是我們項目中一直在用的方式,小程序中也同樣實用:
做完小程序項目、老闆給我加了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();

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

本文由@IT·平頭哥聯盟-首席填坑官∙蘇南分享

接口API維護

  • 接口API的維護,在沒有nodejs之前,前端好像一直都在爲處理不同環境(dev、test、uat、prd)下調用對應的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("大家好,我是蘇南",res)
    }
})

做完小程序項目、老闆給我加了6k薪資~

填坑時間了

填坑時間了wepy框架中每個組件內的生命週期回調 onload,只要是引入了組件,不管你視圖有沒有渲染,他都會執行,導致某些業務邏輯用不上它的時候也執行了產生異常(當然爲個鍋< 小程序 >肯定說我不背~^~ ),詳細看鏈接:https://github.com/Tencent/wepy/issues/975https://honeybadger8.github.io/blog/ ,不知道後面有沒有人解決。

rich-text組件

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

曾想仗劍天涯 後來BUG太多就沒去了


<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|\s\S)]*?)<\/a>/ig; //a標籤分割正則
        let cuttingArr = htmlStr.split(/[\n]/);
        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),\n職業:@IT·平頭哥聯盟-首席填坑官,\n身高:176cm,\n性別:男,\n性取向:女,\n公司:目前就職於由騰訊、阿里、平安三巨頭合資的一家互聯網金融公司深圳分公司某事業部、,\n簡介:寶劍鋒從磨礪出 梅花香自苦寒來,認真做自己,樂於分享,希望能盡綿薄之力 助其他同學少走一些彎路!,gitHub:https://github.com/meibin08/,\n興趣:跑步、羽毛球、爬山、音樂、看書、分享自己的微薄知識幫助他人……,\n其他:想了解更多嗎?可以加入<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 哦,感謝!

今天的分享就到這裏,寫了蠻久,最近纔在開始嘗試寫博客,新手上路中,如果文章中有不對之處,煩請各位大神斧正。如果你覺得這篇文章對你有所幫助,請記得點贊哦~,想了解更多?那就請關注下方的 公衆號,有驚喜哦。

寶劍鋒從磨礪出,梅花香自苦寒來,做有溫度的攻城獅,公衆號:honeyBadger8

更多文章:

immutability因React官方出鏡之使用總結分享!
小程序項目之填坑小記
面試踩過的坑,都在這裏了~
你應該做的前端性能優化之總結大全!
如何給localStorage設置一個過期時間?
動畫一點點 - 如何用CSS3畫出懂你的3D魔方?
動畫一點點 - 手把手教你如何繪製一輛會跑車
SVG Sprites Icon的使用技巧

作者:蘇南 - 首席填坑官
交流羣:912594095,公衆號:honeyBadger8
原文鏈接:https://blog.csdn.net/weixin_43254766/article/details/82811714
本文原創,著作權歸作者所有。商業轉載請聯繫@IT·平頭哥聯盟獲得授權,非商業轉載請註明原鏈接及出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章