vue 实现个简易版(3)

上一篇文章实现了数据的双向绑定,这一篇来实现v-bind, v-on指令以及methods等。

1. v-model语法糖指令拆分处理

1.1 首先来修改判断是否是指令的函数

isDirective(attrName){
    return attrName.startsWith('v-on:')||attrName.startsWith('v-')
}

1.2 再修改使用指令对应工具函数的部分

compileElement(node){
    let attributes = node.attributes;    //某个元素的属性节点
    [...attributes].forEach((attr)=>{
        let { name, value: expr } = attr
        //判断是否是指令
        if(this.isDirective(name)){
            let [directive, value] = name.substring(2).split(':')
            if( directive === 'on' ) directive = value //2.添加 事件
            if( directive === 'bind' ) directive = value //2.添加 自定义属性
            CompilerUtil[directive]&&CompilerUtil[directive](node, expr, this.vm)//调用不同的处理指令
        }
    })
}

1.3 在CompilerUtil对象中添加,处理v-bind:value指令函数value

value()函数主要,就是根据表达式expr,获取在data上值,然后设置到input中

value(node,expr,vm){
    let fn = this.updater['modelUpdater']
    let content = this.getVal(vm, expr)
    new Watcher(vm, expr, (newVal) => {
        fn(node, newVal)
    })

    fn(node, content)
}

1.4 在CompilerUtil对象中添加,处理v-on:input指令函数input

input()函数,主要通过监听输入框的input方法,获取输入的值,设置到表达式(student.name = $event.target.value)左边

input(node,expr,vm){
    let funcName = arguments.callee.name
    let func = ($event)=>{
        let [exprLeft, exprRight] = expr.indexOf('=')>-1 ? expr.split('=') : [expr,'$event.target.value']
        // console.log(exprLeft,exprRight)	// student.name , $event.target.value
        let value = new Function('$event','return ' + exprRight)($event)
        this.setVal(vm, exprLeft.trim(), value) // exprLeft 会存在空格
    }
    node.addEventListener(funcName, func, false)
}

到此,已经实现了v-bind:value和v-on:input指令,再改造下v-model指令就比较简单了

//处理v-model指令
model(node,expr,vm){
    this.value(node,expr,vm)
    this.input(node,expr,vm)
}

2. methods

接下来实现methods

2.1 先修改html部分,绑定之前在methods中,写好的changeInputValue函数

input type="text" v-bind:value="student.name" v-on:input="changeInputValue" >

此时可以思考,changeInputValue函数应该在什么时候执行呢?其实就是输入框input函数执行的时候;

修改input函数

input(node, expr, vm){
    let funcName = arguments.callee.name
    let func = ($event)=>{
        let fn = vm.$methods[expr] // 2.1添加
        // console.log(expr);
        if(!fn){// 2.1添加
            let [exprLeft, exprRight] = expr.indexOf('=')>-1 ? expr.split('=') : [expr,'$event.target.value']
            // console.log(exprLeft,exprRight)	// student.name , $event.target.value
            let value = new Function('$event','return ' + exprRight)($event)
            //调用setVal方法,设置数据
            this.setVal(vm, exprLeft.trim(), value) // 找了好久 exprLeft 有空格
        }else{// 2.1添加
            fn && fn.call(vm,$event)
        }
    }
	node.addEventListener(funcName, func, false)
}

2.2 v-on:click实现

先添加一个按钮绑定addAge函数

<button v-on:click="addAge">过年了,大一岁</button>

在CompilerUtil对象中添加处理v-bind:click指令函数click

主要就是获取methods中的函数,然后监听click事件在执行这个函数

//处理v-bind:click指令
click(node,expr,vm){
    let funcName = arguments.callee.name
    let func = ($event)=>{
        let fn = vm.$methods[expr]
        fn && fn.call(vm,$event)
    }
    node.addEventListener(funcName, func, false)
}
posted @ 2020-09-17 11:05  tang丶有年  阅读(123)  评论(0编辑  收藏  举报