h5 錄音 自動生成proto Js語句 UglifyJS-- 對你的js作了什麼 【原碼筆記】-- protobuf.js 與 Long.js 【微信開發】-- 發送模板消息 能編程與會編程 vue

得益於前輩的分享,作了一個h5錄音的demo。效果圖以下:html

點擊開始錄音會先彈出確認框:前端

首次確認容許後,再次錄音不須要再確認,但若是用戶點擊禁止,則沒法錄音:vue

點擊發送 將錄音內容發送到對話框中。點擊便可播放。點擊獲取錄音便可下載最後一次的音頻:html5

播放下載都是圍繞blob文件。播放就是讓隱藏的audio標籤的地址指向內存中的blob:node

        this.play = function (audio,blob) {
            blob=blob||this.getBlob().blob;
            audio.src = URL.createObjectURL(blob);  
        };  
createObjectURL 咱們在用base64顯示圖片的時候也能夠用到。
 img.src = URL.createObjectURL(blob);

這樣比一長串的字符串好看不少。同理若是你想銷燬該地址對應的數據而節省內存能夠這樣:webpack

 URL.revokeObjectURL(img.src);

扯遠了點。下載就是模擬a標籤的點擊。ios

複製代碼
   function downloadRecord(record){
              var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a')
                save_link.href = URL.createObjectURL(record);
                var now=new Date;
                save_link.download = now.Format("yyyyMMddhhmmss");
                fake_click(save_link);
            }

       
            function fake_click(obj) {
            var ev = document.createEvent('MouseEvents');
            ev.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
            obj.dispatchEvent(ev);
            }
複製代碼

每次發送 ,實際上是講音頻數據緩存下來,標記下id。下次點擊的時候根據id獲取緩存的數據,而後叫給audio元素播放:git

複製代碼
var msg={};
            //發送音頻片斷
            var msgId=1;
            function send(){
                if(!recorder){
                    showError("請先錄音");
                    return;
                }

               var data=recorder.getBlob();
               if(data.duration==0){
                     showError("請先錄音");
                    return;
               }
                msg[msgId]=data;
                recorder.clear();
                console.log(data);
                var dur=data.duration/10;
                 var str="<div class='warper'><div id="+msgId+" class='voiceItem'>"+dur+"s</div></div>"
                $(".messages").append(str);
                msgId++;
            }
            
            $(document).on("click",".voiceItem",function(){
                var id=$(this)[0].id;
                var data=msg[id];
                playRecord(data.blob);
            })
複製代碼

內部是基於AudioContext實現:兼容性以下,基本上只能在谷歌和火狐瀏覽器裏面玩。很惋惜微信和ios目前不支持的。若是電腦沒有音頻驅動或者沒有麥都會報錯提示。程序員

 

 有興趣的朋友能夠玩玩。將來移動端支持就更好了。github

源碼:http://files.cnblogs.com/files/stoneniqiu/Voice.zip

參考博客:

 

自動生成proto Js語句

2017-07-28 20:02 by stoneniqiu, 789 閱讀, 0 評論, 收藏編輯

在與後端的WebSocket通訊時,前端要帶一個proto文件是一個累贅的事情。首先是明顯的曝光了協議實體對象,再一個瀏覽器客戶端很容易會緩存該文件,新的協議更新可能致使客戶端不能使用,另外在cdn服務器上還須要配置.proto類型客戶端才能下載過去。真是遺毒不淺,本身使用的時候會注意這些,但給別人使用的時候就很不樂觀了,因此此次所有將proto文件轉成JavaScript對象,省去協議文件和加載的步驟。

先看代碼:

複製代碼
 function createProto(name) {
        var args = [].slice.call(arguments, 1);
        var obj = new protobuf.Type(name);
        for (var i = 0; i < args.length; i++) {
            var p = args[i];
            var key = i + 1;
            obj.add(new protobuf.Field(p[0], key, p[1] || "string"));
        }
        return obj;
    }

    function createEnum(name,list) {
        var obj = new protobuf.Enum(name);
        for (var i = 0; i < list.length; i++) {
            obj.add(list[i],i);
        }
        return obj;
    }

    function loadProto(callback) {
         if (typeof protobuf == "undefined") return;//說明瀏覽器加載失敗            root = new protobuf.Root().define("IMEntity");
            root.add(createProto("Token", ["UserID"], ["Token"], ["Device"], ["Version", "int32"], ["Appkey"]));
            root.add(createProto("Feedback", ["ResultCode", "int32"], ["ResultData"], ["Seq", "int32"], ["MsgID"]));
            root.add(createEnum("ReceiptType", ["Receive", "Read"]));
       //...
util.triggerCallback(callback); };
複製代碼

proto 主要有兩種類型,Type和Enum。Type對應協議中的message,至關因而類。Enum就是枚舉類型

複製代碼
var Root  = protobuf.Root,
    Type  = protobuf.Type,
    Field = protobuf.Field;

var AwesomeMessage = new Type("AwesomeMessage").add(new Field("awesomeField", 1, "string"));

var root = new Root().define("awesomepackage").add(AwesomeMessage);
複製代碼

枚舉的建立不要須要Field。只須要add 字段名便可。那麼接下來的問題是,手寫root.add 也很煩,由於要一個一個對照屬性,不斷的複製粘貼,很容易出錯。因此又作了個自動生成代碼的頁面:

複製代碼
 <textarea id="content">
        //登錄Token
        message Token{
        string UserID = 1;    //登錄接口返回的IMUserID
        string Token = 2;    //登錄接口返回的Token
        string Device = 3;    //客戶端設備號
        int32  Version = 4;    //版本號,發佈前與服務端約定值
        string Appkey = 5;    //客戶端Appkey
        }
       
        //收到私信
        message ReceivePrivateMessage{
        string MsgID = 1;        //消息id
        string SenderID = 2;    //發送者id
        string ReceiverID = 3;    //接收者id
        string Content  = 4;    //消息內容。客戶端轉換成業務相關的實體後,再作後續處理(客戶端使用,服務器不作任何處理,原樣下發)
        bool Ack = 5;              //是否須要已讀回執
        int32 SendDateTime = 6;    //消息發送時間
        int32 ContentType = 7;    //內容類型(客戶端使用,服務器不作任何處理,原樣下發)
        }
        //回執類型
        enum ReceiptType{
        Receive = 0;                      //已收回執(收到消息後當即發送給服務器的回執)
        Read = 1;                        //已讀回執(用戶進入消息閱讀界面後發送給服務器的回執)
        }
    </textarea>
    <div id="result"></div>
    <script>
        function start() {
            $("#result").html("");
            $("#result").append('root = new protobuf.Root().define("IMProtoEntity")<br>');


            var reg = /("([^\\\"]*(\\.)?)*")|('([^\\\']*(\\.)?)*')|(\/{2,}.*?(\r|\n))|(\/\*(\n|.)*?\*\/)/g,// 過濾註釋
          str = $('#content').val(); // 欲處理的文本
            // console.log(str.match(reg));// 打印出:匹配子串
            var news = str.replace(reg, "");
            // console.log(news); // 打印出:原文本
            var reg1 = /[message|enum].*?{/mg;
            var regobj = /{[^}{]*?}/g;//新地址
            var names = news.match(reg1);
            var protos = news.match(regobj);
            // console.log(names, protos);
            var root = {};
            for (var i = 0; i < names.length; i++) {
                var rawname = names[i];
                var rawObj = protos[i];
                //if (~rawname.indexOf("message"))
                if (!rawObj) continue;

                var name = rawname.replace("{", '').replace("message ", '').replace("enum ", '');
                var obj = { name: name };
                if (~rawname.indexOf("enum")) {
                    obj["type"] = "enum";
                }

                rawObj = rawObj.replace("{", '').replace("}", '');
                var protolist = rawObj.split(';');
                //  console.log("protolist", protolist);
                var plist = [];
                for (var j = 0; j < protolist.length; j++) {
                    var p = $.trim(protolist[j]);
                    if (p) {
                        var args = [];
                        var list = p.split(' ');
                        //  console.log("list", list);
                        list.forEach(function (n) {
                            n && args.push(n);
                        }),
                        //  console.log("args", args);
                        plist.push(args);
                    }
                }
                obj.list = plist;
                console.log(obj);
                toProto(obj);
            }

        }

        start();

        function toProto(obj) {
            var root = "root";
            var fun = "createProto";
            var enumfun = "createEnum";

            var str = root + '.add(';
            var args;
            if (!obj.type) {//message
                args = '';
                for (var i = 0; i < obj.list.length; i++) {
                    var item = obj.list[i];

                    //老協議2.0
                    if (item[0] == "required" || item[0] == "optional") {
                        item.shift();
                    }
                    //新協議3.0
                    if (item[0] != "string") {
                        args += '["' + item[1] + '","' + item[0] + '"]';
                    } else {
                        args += '["' + item[1] + '"]';
                    }
                    if (i < obj.list.length - 1) args += ",";
                }
            } else {//enum
                args = '[';
                for (var i = 0; i < obj.list.length; i++) {
                    var item = obj.list[i];
                    args += '"' + item[0] + '"';
                    if (i < obj.list.length - 1) args += ",";
                }
                args += ']';
            }

            var all = str + (obj.type ? enumfun : fun) + '("' + obj.name + '",' + args + '));';
            //  console.log(all);
            $("#result").append(all + "<br>");
        }
    </script>
複製代碼

而後頁面上會獲得:

紅色部分複製到工程裏面就能夠用了。固然要帶上createProto和createEnum兩個方法。proto的格式要規範,畢竟start裏面是以空格split的。相對於protobuf.load("xx.proto",callback)的方式要好不少。load對位置要求比較死板,必定要在根目錄。並且有類型不存在就會報錯,終止程序。add方法不存在找不到類型的錯誤。另外速度也快了不少。 

 

 

UglifyJS-- 對你的js作了什麼

2017-07-27 08:38 by stoneniqiu, 1118 閱讀, 4 評論, 收藏編輯

也不是閒着沒事去看壓縮代碼,但今天調試本身代碼的時候發現有點意思。由於是本身寫的,雖然壓縮了,格式化以後仍是很好辨認。固然做爲min的首要準則不是可讀性,而是精簡。那麼它會盡可能的縮短代碼,儘可能的保持一行,最大化的減小的空白。咱們經常使用的分號都會被替換成了逗號,短句變成了連貫的長句。

1.當即執行函數

我本是第二種寫法,uglify給我替換成了第一種(固然更短一點)。其實括號和!號的做用都是將funtion的部分轉成一個表達式,而再也不是申明。這樣就能當即執行,同理~   +均可以作到。

2.變量名替換

這個是天然的,函數名、參數名、變量名都替換成了單個字母。甚至是‘_’

3.函數置頂

function foo (){} 這種形式的代碼都會被放到模塊的最頂端。固然這是一種規範,後來發現還有另一個做用就是方便後面的代碼合併。 好比 咱們這樣定義:
複製代碼
var self=this;
function a(){}
self.a=a;
function b(){}
self.b=b;
return self;
複製代碼

會替換成:

function a(){}
function b(){}
var s={}
return  s.a={},s.b={},s

注意到最後的s 不能漏了,return會以最後一個表達式的結果爲準。

複製代碼
  function rt(n) {
    return n;
   }
  function xx() {
      return rt(1), rt(2);
  }
複製代碼

執行xx()獲得的是2,若是 rt(2)後面還有個不返回值的函數執行,那麼xx()會獲得undefined。

4.bool值替換

false-->!1  true-->!0

5.if 

if語句是壓縮最多的地方。

1) return 前置:
複製代碼
 function load() {
            if (t) {
                x = false;
                log("error");
                return;
            }
            console.log("22")
        }
複製代碼

好比個人原函數大概是這樣。壓縮後成了這樣:

  if (t) return x =!1,void log("error")
return提早了,末尾多了一個void。 這是爲何呢。 沒有大括號,if的四段代碼變成了一句話。void的在這裏的做用是抹掉函數的返回值。由於原本的這個if 是沒有返回值的 。若是這個時候log方法帶有返回值。那麼調用load就會拿到這個返回值。這會產生干擾,違背了原函數的本意。因此用void抹掉了。 
2) 短路
複製代碼
     function foo() {
            if (!x) {
                return;
            }
            console.log("doA");
            console.log("doB");
  }
複製代碼

壓縮後:

    function f() {
            x || console.log("doA"), console.log("doB");
      }

這樣蠻不錯的。同理:

複製代碼
if(x&&y){
doa();
dob();
}
doc();
--> x&&y&&(doa(),dob()),doc()
複製代碼

本來四行變成了一行代碼。

3).爲了合併一行,這也行:

    console.log("doA");
    console.log("doB");
     if (x>0) {
         console.log("true");
      }

合併成這樣:

 if (console.log("doA"), console.log("doB"), x > 0) console.log("true");

平時這麼寫可能不太友好,重點是在if語句中,最後一句纔是判斷句。結合以前的return。想必對逗號語句有了深入的認識。

4)throw也不放過

 if (errMsg) {
       util.triggerCallback(fail, "模型驗證錯誤");
       throw Error(errMsg);
  }

壓縮後:

 if (a)  throw x.triggerCallback(o, "模型驗證錯誤"), Error(a)

調換了語句的順序,把throw當作return 就明白了。

5) if else

這個會替換成三元表達式  a?b:c 。

6.數字處理

整百整千的會處理成科學計數 1000 -->1e3 。

7. while

複製代碼
var offset = 0;
            while (true) {
                if (offset >= bufferLength) {
                    break;
                }
}
複製代碼

會替換成這樣:

  for (var n = 0; ; ) {
                if (n >= K)
                    break
 }

確實不錯,節省了一行代碼。

以上只是獨自對比本身的代碼發現的一些東西,有的能夠在平時的編碼中用起來,固然不是追求全部代碼都寫成一行,這樣可讀性比較差,另外可能你下次看壓縮代碼就不那麼費勁了。歡迎補充。

 

protobuf.js的結構和webpack的加載以後的結構很類似。這樣的模塊化組合是個不錯的結構方式。1個是適應了不一樣的加載方式,2個模塊直接很獨立。webpack的功能更全一點。但若是本身封裝js庫這樣夠用了。並且模塊對外統一接口 module.exports。這和node很像。

複製代碼
(function(global, undefined) {
    "use strict";
    (function prelude(modules, cache, entries) {
        function $require(name) {
            var $module = cache[name];
            //沒有就去加載
            if (!$module)
                modules[name][0].call($module = cache[name] = { exports: {} }, $require, $module, $module.exports);

            return $module.exports;
        }

        //曝光成全局
        var proto = global.proto = $require(entries[0]);

        // AMD
        if (typeof define === "function" && define.amd) {
            define(["long"], function(Long) {
                if (Long && Long.isLong) {
                    proto.util.Long = Long;
                    proto.configure();
                }
            });
            return proto;
        }

        //CommonJS
        if (typeof module === "object" && module && module.exports)
            module.exports = proto;


    })
    //傳參
    ({
        1: [function (require, module, exports) {

            function first() {
                console.log("first");
            }

            module.exports = first;

        }, {}],
        2: [function(require, module, exports) {
            function second() {
                console.log("second");
            }
            module.exports = second;
        }],
        3: [function (require, module, exports) {

            var proto = {};
            proto.first = require(1);
            proto.second = require(2);
            proto.build = "full";

            module.exports = proto;
        }]
      }, {}, [3]);


})(typeof window==="object"&&window||typeof self==="object"&&self||this)
複製代碼

在處理超過16位的整形就得使用Long.js了。 主要是fromString和toString。

複製代碼
  function fromString(str, unsigned, radix) {
        if (str.length === 0)
            throw Error('empty string');
        if (str === "NaN" || str === "Infinity" || str === "+Infinity" || str === "-Infinity")
            return ZERO;
        if (typeof unsigned === 'number') {
            // For goog.math.long compatibility
            radix = unsigned,
            unsigned = false;
        } else {
            unsigned = !!unsigned;
        }
        radix = radix || 10;
        if (radix < 2 || 36 < radix)
            throw RangeError('radix');

        var p;
        if ((p = str.indexOf('-')) > 0)
            throw Error('interior hyphen');
        else if (p === 0) {
            return fromString(str.substring(1), unsigned, radix).neg();
        }

        // Do several (8) digits each time through the loop, so as to
        // minimize the calls to the very expensive emulated div.
        var radixToPower = fromNumber(pow_dbl(radix, 8));

        var result = ZERO;
        for (var i = 0; i < str.length; i += 8) {
            var size = Math.min(8, str.length - i),
                value = parseInt(str.substring(i, i + size), radix);
            if (size < 8) {
                var power = fromNumber(pow_dbl(radix, size));
                result = result.mul(power).add(fromNumber(value));
            } else {
                result = result.mul(radixToPower);
                result = result.add(fromNumber(value));
            }
        }
        result.unsigned = unsigned;
        return result;
    }
複製代碼

fromstring的思路是把字符串8位一個截取。而後轉成Long型(高位,地位,符號位) 加起來。最後是一個Long型。 4294967296 是2的32次方。每次操做以前都會有一個基數的操做 mul(radixToPower)或者mul(power)這二者都是保證result的位數是正確的。

好比{low:123} 和{low:1} 相加以前,先要讓{low:123}乘以10,獲得{low:1230}再與{low:1}進行位操做。由於第一個是高位,不能直接相加。

function fromBits(lowBits, highBits, unsigned) {
        return new Long(lowBits, highBits, unsigned);
    }

fromBits 即轉爲Long對象。value%4294967296 獲得低位。/獲得高位。結果經過位移合併起來。mul是bit的乘法,add是bit的加法。 原理是講一個64位的拆成四段。分別16位。this.low左移16位 就獲得 low的32-17位是啥。 而後和addend對象的同位相加

最後的合併是經過|運算。位移以後再還原確實很巧妙。一時看上去都不大理解。

複製代碼
 LongPrototype.add = function add(addend) {
        if (!isLong(addend))
            addend = fromValue(addend);

        // Divide each number into 4 chunks of 16 bits, and then sum the chunks.

        var a48 = this.high >>> 16;
        var a32 = this.high & 0xFFFF;
        var a16 = this.low >>> 16;
        var a00 = this.low & 0xFFFF;

        var b48 = addend.high >>> 16;
        var b32 = addend.high & 0xFFFF;
        var b16 = addend.low >>> 16;
        var b00 = addend.low & 0xFFFF;

        var c48 = 0, c32 = 0, c16 = 0, c00 = 0;
        c00 += a00 + b00;
        c16 += c00 >>> 16;
        c00 &= 0xFFFF;
        c16 += a16 + b16;
        c32 += c16 >>> 16;
        c16 &= 0xFFFF;
        c32 += a32 + b32;
        c48 += c32 >>> 16;
        c32 &= 0xFFFF;
        c48 += a48 + b48;
        c48 &= 0xFFFF;
        return fromBits((c16 << 16) | c00, (c48 << 16) | c32, this.unsigned);
    };
複製代碼

>>>和>>有什麼區別??。 

toString

複製代碼
LongPrototype.toString = function toString(radix) {
        radix = radix || 10;
        if (radix < 2 || 36 < radix)
            throw RangeError('radix');
        if (this.isZero())
            return '0';
        if (this.isNegative()) { // Unsigned Longs are never negative
            if (this.eq(MIN_VALUE)) {
                // We need to change the Long value before it can be negated, so we remove
                // the bottom-most digit in this base and then recurse to do the rest.
                var radixLong = fromNumber(radix),
                    div = this.div(radixLong),
                    rem1 = div.mul(radixLong).sub(this);
                return div.toString(radix) + rem1.toInt().toString(radix);
            } else
                return '-' + this.neg().toString(radix);
        }

        // Do several (6) digits each time through the loop, so as to
        // minimize the calls to the very expensive emulated div.
        var radixToPower = fromNumber(pow_dbl(radix, 6), this.unsigned),
            rem = this;
        var result = '';
        while (true) {
            var remDiv = rem.div(radixToPower),
                intval = rem.sub(remDiv.mul(radixToPower)).toInt() >>> 0,
                digits = intval.toString(radix);
            rem = remDiv;
            if (rem.isZero())
                return digits + result;
            else {
                while (digits.length < 6)
                    digits = '0' + digits;
                result = '' + digits + result;
            }
        }
    };
複製代碼

也是sub以後拼出來的。也就是fromstring的反向操做。

 

【微信開發】-- 發送模板消息

2017-06-28 20:25 by stoneniqiu, 8795 閱讀, 7 評論, 收藏編輯

咱們須要將一些行爲的進展消息推送給用戶。除了短信,發送微信模板消息也是不錯的選擇。模板消息免費、精準到達、並且能夠引導用戶回到網站上來。但它有兩個前提條件。1個是認證的服務號,你才能選擇模板。2個是被推送的用戶必須關注了你的公衆號,並且你也拿到了他的openid。

先在模板庫中找到本身的想要的模板,添加到「個人模板」中。

展開詳情,咱們能夠看到示例。接下來用C#代碼發送一次:

官方文檔的示例中咱們能夠看到除了推送人的openid,還能夠設置每一個字段的顏色及跳轉地址。先能夠定義以個TempModel對象:

複製代碼
  public class TemplateModel
    {
        public string touser { get; set; }
        public string template_id { get; set; }
        public string url { get; set; }

        public string topcolor { get; set; }

        public TemplateData data { get; set; } 
    
        public TemplateModel(string hello,string state,string reason,string last)
        {
            data=new TemplateData()
            {
                first = new TempItem(hello),
                keyword1 = new TempItem(state),
                keyword2 = new TempItem(reason),
                remark = new TempItem(last)
            };
             
        }
    }

    public class TemplateData
    {
        public TempItem first { get; set; }
        public TempItem keyword1 { get; set; }
        public TempItem keyword2 { get; set; }
        public TempItem remark { get; set; }
    }
    public class TempItem
    {
        public TempItem(string v,string c = "#173177")
        {
            value = v;
            color = c;
        }
        public string value { get; set; }
        public string color { get; set; }
    }
複製代碼

還有一個返回結果對象:

複製代碼
 public class OpenApiResult
    {
        public int error_code { get; set; }
        public string error_msg { get; set; }

        public string msg_id { get; set; }
    }
複製代碼

而後定義一個發送方法:

複製代碼
using SendHelp= Senparc.Weixin.CommonAPIs.CommonJsonSend;

public OpenApiResult SendTemplateMessage(string token,TemplateModel model)
        {
            var url = string.Format("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token={0}", token);
            try
            {
                var res = SendHelp.Send<OpenApiResult>(token, url, model);
                return res;
            }
            catch (Exception e)
            {
                
                return new OpenApiResult(){error_code = -1,error_msg = e.Message};
            }
          
        } 
複製代碼

SendHelp是基於Senparac.Weixin 最後就能夠調用了:

複製代碼
        public ActionResult SendMessage()
        {
            var token = getToken();
            var toUserId = "oBSBmwQjqwjfzQlKsFNjxFLSiIQM";
            var data = new TemplateModel("你好,stoneniqiu","審覈經過","資料完整","祝你生活幸福!");
            data.touser = toUserId;
            data.template_id = "gXmkeL7Kc-KUy2EQzKqjPKY-kzFyatTztiYFKCaUPO4";
            data.url = "http://www.xxx.com/xx/xx";
            data.topcolor = "#FF0000";
            var res=wxDeviceService.SendTemplateMessage(token, data);
            return View(res);
        }
複製代碼

token即經過AppID和APPSECRET獲取。發送以後,手機上立刻收到消息。這裏的url就是下圖詳情的跳轉地址。 只能是註冊域名下面的地址,不能跳到別的域名去。

但若是你只是拿到了用戶的openid,但該用戶沒有關注公衆號,發送時會拋出下面的錯誤:

其餘信息: 微信Post請求發生錯誤!錯誤代碼:43004,說明:require subscribe hint: [Q2OfvA0092ge21]

相關部分代碼:http://files.cnblogs.com/files/stoneniqiu/wx-template.zip

官方文檔:https://mp.weixin.qq.com/advanced/tmplmsg?action=faq&token=1798469214&lang=zh_CN

所有錯誤類型:http://www.szdyhd.com/news/view/webdesign/2016/0614/519.html

 

    幾個月前由於一個事情被diao了。原由是臨近上線的時候項目後端統一了消息協議(.proto),而後要我前端也支持。我研究了一天,沒走通,要麼依賴項太多,要麼一直報錯,並且須要使用的對象兼容性有問題。當時內心有些急,也有幾份抵觸這種方案,因而在會上說出了個人想法:能不能友好的發發json,兼容性好也不須要什麼第三方解析。結果天然是被否決了,理由是大廠出品的,怎麼可能不能用呢,用屁股想一想就知道?你爲啥遇到問題就想着退縮呢。我無語凝噎。重要是給我強調了能編程與會編程是不同的

    開完會情緒有點低落,回到座位上打開github 繼續找方案,不一下子竟然找到了!啪啪打臉的感受好酸爽。而後開始思索...

是否抵觸

     一件事帶有抵觸情緒以後,那基本是作很差的。在找方案的時候,眼中只看到「NO」,而自動忽略了「YES」。解決方法在你眼前你可能都看不到。就像一我的不想作事就找藉口,這些藉口在他本身看來都是很合理的。要帶有這種情緒,那不如先別開始,要麼自我消化,要麼拿更好的方案去說服別人。

只要有一種解釋是對本身有利的,咱們便不想去推敲和反駁,再漏洞百出的事情看上去也不無可能,並且只要一種解釋是可能的,咱們就認定是必定的,強大的情緒大腦會阻止理性大腦往深刻的想。而對於本身不利的解釋,咱們或忽略,或者異常仔細的去推敲,抓住一個漏洞則相信本身推翻了全部的解釋。----《暗時間》

因此一件事情在本身着手作的時候,先整理好相似的情緒。不少時候擺在咱們面前的方案不少,若是是你熟悉的領域固然好選擇,利弊清晰,能快速判斷。但不熟悉的時候,就要注意到每一個方案所適用的環境和條件,要歸類和總結,本身所遇到的問題自己已經提供了一些前提條件。用這些條件先過濾到一部分。而不是瞎貓抓死耗子同樣一個個去碰。

另一點,咱們在嘗試新的事物的時候,老是會遇到各類困難,不一樣的人在不一樣的碰壁次數以後會退出。用程序員的話來講,咱們都在for循環,區別在於你是什麼狀況下break;的。有的人退出閾值高,這是能堅持的一類人,有的人退出閾值低。過早退出的緣由在於對將來的不肯定性,對投資時間最終沒法收到回報的恐懼。其實在堅持堅持,再想想,答案立刻就出來了。

不要等待

   編程工做中咱們常常遇到需求不完整,接口文檔沒有,接口返回值錯,誤諸如此類 別人的因素,而後致使項目進度緩慢或者停滯。其實我想說,編程簡直過輕鬆愉快了,由於還有人給你提供需求,提供設計稿,你實現就好了。實際生活中不少事情根本沒有人會告訴你需求,好比本身裝修,你須要定風格,而後選材料,按照流程喊施工隊伍,考慮風格和成本,考慮材料合不合適,喜不喜歡,甲醛高不高等等。建材市場魚龍混雜,裝修師傅可能陽奉陰違。即便你監工他都敢用料不夠,總有一款讓你交點學費。 可能很忙的時候,父母又生病了..... 生活的事情更考驗的人的協做和溝通能力、承壓能力。沒有誰告訴你截止日期和責任,可是你沒作好,就是沒有作好,不要說什麼裝修的人坑了你。工做的事情責任範圍清晰,不屬於你的鍋你均可以甩的遠遠的。但若是團隊內部都是這樣的氛圍,那又能成什麼事。雪崩的時候,沒有一片雪花以爲本身有責任,應該積極主動起來,由於等待耗費的也是本身的時間。    

作完了仍是作好了

按照需求和效果圖,你可能很快就實現了全部功能和效果。可是本身測試了嗎?可用性高嗎?穩定嗎?兼容性如何?功能作完每每只到了一個階段,後面還須要本身作檢驗性工做。確保交出去的東西是ok的,達到預期的。有信心對別人說我作好了,讓別人用的放心。而不是說一句我作完了,暗藏的坑讓別人先踩。有時間還應該思考一下,代碼是否能夠更簡潔?接口設計是否能夠更簡明?多個相似方案是否能夠統一成產品?思考的價值總會爲你省下將來的時間,特別是重複勞動的時間、遇到問題溝通的時間。

知識體系完善

 你選擇的方案,都是你所知道的方案。也就是說,你的知識範圍,決定了你的處理能力範圍。甚至於,有的知識你會,但關鍵的時候你未必想的出來。這個過程就像解題,本身苦思冥想不得,看到答案恍然大悟。爲何呢?你的大腦就像一個圖書館,知識的碎片就如書架上的書,你想用的時候,發現找不到地址了。

知識分兩種,一種是咱們一般所謂的知識,即領域知識。二是關於咱們大腦吸取知識的機制的知識,後者不妨成爲元知識。雖然說這也是領域知識,但跟其餘的領域知識不一樣的是,它指導咱們學習其它全部的領域知識。

除了完善咱們的領域知識,也許須要補充一下其餘領域的,譬如心理學和思惟方面的,固然最好是到生活中去解決問題。 

小結:會編程是基於現有經驗辦事的能力,而能編程是對整個事情的解決能力。在學習一門技術的成本差很少的狀況下,差異就來自於編程以外的能力。

 

學習了Vue全家桶和一些UI基本夠用了,可是用元素的方式使用組件仍是不夠靈活,好比咱們須要經過js代碼直接調用組件,而不是每次在頁面上經過屬性去控制組件的表現。下面講一下如何定義動態組件。

 Vue.extend

 思路就是拿到組件的構造函數,這樣咱們就能夠new了。而Vue.extend能夠作到:https://cn.vuejs.org/v2/api/#Vue-extend

複製代碼
// 建立構造器
var Profile = Vue.extend({
  template: '<p>{{firstName}} {{lastName}} aka {{alias}}</p>',
  data: function () {
    return {
      firstName: 'Walter',
      lastName: 'White',
      alias: 'Heisenberg'
    }
  }
})
// 建立 Profile 實例,並掛載到一個元素上。
new Profile().$mount('#mount-point')
複製代碼

官方提供了這個示例,咱們進行一下改造,作一個簡單的消息提示框。

動態組件實現

建立一個vue文件。widgets/alert/src/main.vue

複製代碼
<template>
 <transition name="el-message-fade">
<div  v-show="visible" class="my-msg">{{message}}</div>
  </transition>
</template>

<script  >
    export default{
        data(){
           return{
               message:'',
               visible:true
           } 
        },
        methods:{
            close(){
                setTimeout(()=>{
                     this.visible = false;
                },2000)
            },
        },
        mounted() {
        this.close();
      }
    }
</script>
複製代碼

這是咱們組件的構成。若是是第一節中,咱們能夠把他放到components對象中就能夠用了,可是這兒咱們要經過構造函數去建立它。再建立一個widgets/alert/src/main.js

複製代碼
import Vue from 'vue';
let MyMsgConstructor = Vue.extend(require('./main.vue'));

let instance;

var MyMsg=function(msg){
 instance= new MyMsgConstructor({
     data:{
         message:msg
}})

//若是 Vue 實例在實例化時沒有收到 el 選項,則它處於「未掛載」狀態,沒有關聯的 DOM 元素。可使用 vm.$mount() 手動地掛載一個未掛載的實例。
instance.$mount();
 
 document.body.appendChild(instance.$el)
 return instance;
}


export default MyMsg;
複製代碼

require('./main.vue')返回的是一個組件初始對象,對應Vue.extend( options )中的options,這個地方等價於下面的代碼:

import alert from './main.vue'
let MyMsgConstructor = Vue.extend(alert);

而MyMsgConstructor以下。

 參考源碼中的this._init,會對參數進行合併,再按照生命週期運行:

複製代碼
  Vue.prototype._init = function (options) {
    ...// merge options
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options);
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      );
    }
// expose real self
    vm._self = vm;
    initLifecycle(vm);
    initEvents(vm);
    initRender(vm);
    callHook(vm, 'beforeCreate');
    initInjections(vm); // resolve injections before data/props
    initState(vm);
    initProvide(vm); // resolve provide after data/props
    callHook(vm, 'created');

    ...

    if (vm.$options.el) {
      vm.$mount(vm.$options.el);
    }
  };
複製代碼

而調用$mount()是爲了得到一個掛載實例。這個示例就是instance.$el。

能夠在構造方法中傳入el對象(注意上面源碼中的mark部分,也是進行了掛載vm.$mount(vm.$options.el),可是若是你沒有傳入el,new以後不會有$el對象的,就須要手動調用$mount()。這個方法能夠直接傳入元素id。

 instance= new MessageConstructor({
     el:".leftlist",
     data:{
         message:msg
}})

 這個el不能直接寫在vue文件中,會報錯。接下來咱們能夠簡單粗暴的將其設置爲Vue對象。

調用

在main.js引入咱們的組件:

複製代碼
//..
import VueResource from 'vue-resource'
import MyMsg from './widgets/alert/src/main.js';
//..
//Vue.component("MyMsg", MyMsg);
Vue.prototype.$mymsg = MyMsg;
複製代碼

而後在頁面上測試一下:

複製代碼
<el-button type="primary" @click='test'>主要按鈕</el-button>
//..

 methods:{
  test(){
  this.$mymsg("hello vue");
  }
 }

複製代碼

 

這樣就實現了基本的傳參。最好是在close方法中移除元素:

複製代碼
 close(){
    setTimeout(()=>{
       this.visible = false;
       this.$el.parentNode.removeChild(this.$el);
      },2000)
   },
複製代碼

 回調處理

回調和傳參大同小異,能夠直接在構造函數中傳入。先修改下main.vue中的close方法:

複製代碼
export default{
        data(){
           return{
               message:'',
               visible:true
           } 
        },
        methods:{
            close(){
                setTimeout(()=>{
                     this.visible = false;
                      this.$el.parentNode.removeChild(this.$el);

                if (typeof this.onClose === 'function') {
                 this.onClose(this);
                }
                },2000)
            },
        },
        mounted() {
        this.close();
      }
    }
複製代碼

若是存在onClose方法就執行這個回調。而在初始狀態並無這個方法。而後在main.js中能夠傳入

複製代碼
var MyMsg=function(msg,callback){

 instance= new MyMsgConstructor({
     data:{
         message:msg
    },
    methods:{
        onClose:callback
    } 
})
複製代碼

這裏的參數和原始參數是合併的關係,而不是覆蓋。這個時候再調用的地方修改下,就能夠執行回調了。

   test(){
      this.$mymsg("hello vue",()=>{
        console.log("closed..")
      });
    },

你能夠直接重寫close方法,但這樣不推薦,由於可能搞亂以前的邏輯且可能存在重複的編碼。如今就靈活多了。

統一管理

 若是隨着自定義動態組件的增長,在main.js中逐個添加就顯得很繁瑣。因此這裏咱們可讓widgets提供一個統一的出口,往後也方便複用。在widgets下新建一個index.js 

複製代碼
import MyMsg from './alert/src/main.js';

const components = [MyMsg];

let install =function(Vue){
  components.map(component => {
    Vue.component(component.name, component);
  });

 Vue.prototype.$mymsg = MyMsg;

}

if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue);
};

export default {
    install
}
複製代碼

在這裏將全部自定義的組件經過Vue.component註冊。最後export一個install方法就能夠了。由於接下來要使用Vue.use

安裝 Vue.js 插件。若是插件是一個對象,必須提供 install 方法。若是插件是一個函數,它會被做爲 install 方法。install 方法將被做爲 Vue 的參數調用。

也就是把全部的組件當插件提供:在main.js中加入下面的代碼便可。

複製代碼
...
import VueResource from 'vue-resource'
import Widgets from './Widgets/index.js'

...
Vue.use(Widgets)
複製代碼

這樣就很簡潔了。

小結: 經過Vue.extend和Vue.use的使用,咱們自定義的組件更具備靈活性,並且結構很簡明,基於此咱們能夠構建本身的UI庫。以上來自於對Element源碼的學習。

widgets部分源碼:http://files.cnblogs.com/files/stoneniqiu/widgets.zip

vue2入坑隨記(一)-- 初始全家桶

 

低版本的安卓上傳圖片是個問題,能出現選擇圖片,但點擊圖片後沒有反應,轉成base64也無解。因而改成用微信的接口上傳。和以前的微信分享功能都是基於微信的jssdk。

步驟比咱們平時上傳到服務器多一步,他是先調用chooseeImage方法得到用戶要上傳的圖片id。而後上傳到微信的服務器,微信的服務器默認只保存三天,因此還要讓後臺下載到本身的服務器上,而後返回地址,前端顯示,這樣纔算完成。

複製代碼
     var time = '@ViewBag.Share.timestamp';
      wx.config({
        debug: false, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。
        appId: '@ViewBag.Share.appId', // 必填,公衆號的惟一標識
        timestamp: parseInt(time), // 必填,生成簽名的時間戳
        nonceStr: '@ViewBag.Share.nonceStr', // 必填,生成簽名的隨機串
        signature: '@ViewBag.Share.signature',// 必填,簽名,見附錄1
          jsApiList: ["chooseImage", "previewImage", "uploadImage", "downloadImage"] // 必填,須要使用的JS接口列表,全部JS接口列表見附錄2
      });
        wx.ready(function() {
            $(document).on("click", ".ctcon", function() {
                wx.chooseImage({
                    count: 1, // 默認9
                    sizeType: ['original', 'compressed'], // 能夠指定是原圖仍是壓縮圖,默認兩者都有
                    sourceType: ['album', 'camera'], // 能夠指定來源是相冊仍是相機,默認兩者都有
                    success: function (res) {
                        var localIds = res.localIds; // 返回選定照片的本地ID列表,localId能夠做爲img標籤的src屬性顯示圖片
                        uploadimg(localIds[0].toString());

                    }
                });
            });

                
function uploadimg(lid) { wx.uploadImage({ localId: lid, // 須要上傳的圖片的本地ID,由chooseImage接口得到 isShowProgressTips: 1, // 默認爲1,顯示進度提示 success: function (res) { var serverId = res.serverId; // 返回圖片的服務器端ID //alert(serverId); $.post("/Question/DownWxImage", { serverId: serverId }, function(res) { //alert(res.SaveName); if (res.Success === true) { // 顯示圖片 } }); }); } });
複製代碼

count表示讓用戶選擇圖片的張數,而後這裏的localIds要tostring。否則上傳不了。uploadImage執行完了就能夠通知讓後臺上傳:

複製代碼
  public ActionResult DownWxImage(string serverId)
        {
            var token = getToken();
             var url = string.Format("http://file.api.weixin.qq.com/cgi-bin/media/get?access_token={0}&media_id={1}",
                 token, serverId);//圖片下載地址

             HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);

             req.Method = "GET";
             using (WebResponse wr = req.GetResponse())
             {
                 HttpWebResponse myResponse = (HttpWebResponse)req.GetResponse();

                var strpath = myResponse.ResponseUri.ToString();
                 WebClient mywebclient = new WebClient();

                 var path = "/Content/UploadFiles/mobile/";
                 var uploadpath = Server.MapPath(path);
                 if (!Directory.Exists(uploadpath))
                 {
                     Directory.CreateDirectory(uploadpath);
                 }
                 string saveName = Encrypt.GenerateOrderNumber() + ".jpg";
                 var savePath = uploadpath + saveName;

                 try
                 {
                     mywebclient.DownloadFile(strpath, savePath);
                     return Json(new { Success = true, SaveName = path + saveName });
                 }
                 catch (Exception ex)
                 {
                     savePath = ex.ToString();
                 }

             }
             return Json(new {Success = false, Message = "上傳失敗!"});
        }
複製代碼

 這樣安卓是能上傳了,可是也沒有了進度條。

相關文章
相關標籤/搜索