_vue.js

這個寫不完整的渲染函數花了我一個早餐時間,測試它也用了我一杯無糖可樂的時間. 早就不只了..

但是建立這個網頁卻弄了我整個下午...
這個函數雖然沒經過仔細測試 但我猜它應該具備以下特性:

原始碼

嗯。是蠻暴力的

            
(function (global) {
    var eventType = {
        'v-click': function(el,event){
        el.addEventListener("click", event);
        },
        'v-change': function(el,event){
        el.addEventListener("onchange", event);
        },
    };
    
    var vMethods = {
        'v-for': function(el,data){
        // console.log(el,data,this);
        var template = el.innerHTML;
        var dataObj = this.state[data];
        var rs = '';
        for(var key in dataObj){
            rs += this.render(template,dataObj[key]);
        }
        el.innerHTML = rs;
        }
    }
    
    function _vue(obj) {
        this.id = obj.domId;
        this.template = document.getElementById(this.id).innerHTML;
        this.state = {};
        this.event = {};
        this.render = function (template, dataObj) {
            var rsHtml = template;
            for (var key in dataObj) {
                var reg = new RegExp('{' + key + '}', 'g')
                rsHtml = rsHtml.replace(reg, dataObj[key]);
            };
            return rsHtml;
        }
        this.change = function (data) {
            for (var key in data) {
                this.state[key] = data[key];
            }
            document.getElementById(this.id).innerHTML = this.render(this.template, this.state);
    
            for(var key in vMethods){
                document.querySelectorAll('#'+this.id+' ['+key+']').forEach(function(el,index){
                for (var i = 0; i < el.attributes.length; i++) {
                    if(el.attributes[i].name){
                    vMethods[el.attributes[i].name].bind(this)(el,el.attributes[i].value);
                    }
                }
                }.bind(this))
            }
    
            for(var key in eventType){
                document.querySelectorAll('#'+this.id+' ['+key+']').forEach(function(el,index){
                for (var i = 0; i < el.attributes.length; i++) {
                    if(el.attributes[i].name){
                    this.event[el.attributes[i].value] && 
                    eventType[el.attributes[i].name](el, this.event[el.attributes[i].value].bind(this) );
                    }
                }
                }.bind(this))
            }
            
            this.componentBind();
        }
        this.componentBind = function () {
            var __vue = this.constructor;
            var render = this.render;
            for (var key in __vue.comTemplate) {
                var comTemplate = __vue.comTemplate[key];
                document.querySelectorAll('#' + this.id + ' ' + key).forEach(function (el, index) {
                    var data = {};
                    for (var i = 0; i < el.attributes.length; i++) {
                        data[el.attributes[i].name] = el.attributes[i].value;
                    }
                    el.innerHTML = render(comTemplate, data);
                })
            }
        }
        for (var key in obj.data) {
            this.state[key] = obj.data[key];
        }
        this.event = obj.methods;
        this.change();
    }
    
    _vue.comTemplate = {};
    _vue.component = function (obj) {
        this.comTemplate[obj.el] = obj.template;
    };
    
    global._vue = _vue;
})(window);
            
        

使用範例

模板

從Vue模仿的模板寫法

HTML
            
<div id="app">
    <strong>{title}</strong>{body}
</div>
            
        
JS
            
var app = new _vue({
    domId:'app',
    data:{
        title:'Hello',
        body:'_vue!'
    }
});
            
        
RESULT
{title}{body}

動態更新

還可以透過change方法動態更新內容,雖然沒有Vue那麼神奇的屬性更新
你可以在console介面使用下面的指令,然後app區塊的body就會跟著變動了

JS
            
app.change({
    body: 'vueeeeeeeeeeeeeee!'
});         
            
        

循環指令

_vue復刻了Vue經常被使用的循環指令,所以列出清單應該也不是什麼難事了

HTML
            
<div id="todo">
    <h2>{title}</h2>
        <ol v-for="list">
        <li>{text}</li>
    </ol>
</div>
            
        
JS
            
var todo = new _vue({
    domId: 'todo',
    data: {
        title: 'Todo list',
        list:[
            {text:'牽摩托車去修理'},
            {text:'吃早餐'},
            {text:'抱怨主管'},
        ],
    }
});
            
        
RESULT

{title}

  1. {text}

事件綁定

現在你可以透過v-click屬性來替元素新增click事件,而在事件裡你可以透過this來取得自己的所有方法
接下來的例子擴增了剛剛的list清單,當你按下button就會新增一個清單

HTML
            
<div id="todoWithAdd">
    <h2>{title}</h2>
    <button v-click="addlist">addlist</button>
    <ol v-for="list">
        <li>{text}-{date}</li>
    </ol>
</div>
            
        
JS
            
var todoWithAdd = new _vue({
    domId: 'todoWithAdd',
    data: {
        title: 'HELLO',
        body: '_vue.js',
        list:[
            {text:'list 1',date:'2017/10/5'},
            {text:'list 2',date:'2017/10/6'},
            {text:'list 3',date:'2017/10/8'},
        ],
    },
    methods: {
        addlist: function () {
            this.state.list.push({
                text:'list new',
                date:new Date()
            });
            this.change();
        }
    }
});
            
        
RESULT

{title}

  1. {text}-{date}

元件系統

雖然很吃力..我還是模仿了Vue的元件系統,反正Vue可能也是模仿React的
使用方法是透過_vue.component指令跟_vue註冊一個元件,之後就可以在_vue裡使用自訂元件

HTML
            
<div id="componentExample">
    <strong>{title}</strong>
    <strike>{body}</strike>
    <vue text="_vue.js"></vue>
</div>
            
        
JS
            
_vue.component({
    el: 'vue',
    template: '{text}'
});
var componentExample = new _vue({
    domId: 'componentExample',
    data: {
        title: 'HELLO',
        body: 'Vue.js',
    }
});  
            
        
RESULT
{title} {body}

Panpan Pan

yecapee@gmail.com 台灣 中文,台語