Vue github下载源码(地址为:https://github.com/vuejs/vue)
一、先找到function Vue
function Vue (options) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword');
}
this._init(options);
}
二、查找function _init
在这里插入代码片
三、查找function initData
function initData (vm) {
var data = vm.$options.data;
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {};
if (!isPlainObject(data)) {
data = {};
process.env.NODE_ENV !== 'production' && warn(
'data functions should return an object:\n' +
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
vm
);
}
// proxy data on instance
var keys = Object.keys(data);
var props = vm.$options.props;
var methods = vm.$options.methods;
var i = keys.length;
while (i--) {
var key = keys[i];
if (process.env.NODE_ENV !== 'production') {
if (methods && hasOwn(methods, key)) {
warn(
("Method \"" + key + "\" has already been defined as a data property."),
vm
);
}
}
if (props && hasOwn(props, key)) {
process.env.NODE_ENV !== 'production' && warn(
"The data property \"" + key + "\" is already declared as a prop. " +
"Use prop default value instead.",
vm
);
} else if (!isReserved(key)) {
proxy(vm, "_data", key);
}
}
// observe data
observe(data, true /* asRootData */);
}
//检查字符串是否以$或_开头
function isReserved (str) {
var c = (str + '').charCodeAt(0); //_ 95 0x5f , $ 36 0x24
return c === 0x24 || c === 0x5F
}
var hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn (obj, key) {
return hasOwnProperty.call(obj, key) //这里判断obj是否有key属性,返回true或false
}
手写v-model
<div id="app">
<form>
<input type="text" v-model="number">
<button type="button" v-click="inorement">增加</button>
</form>
<h3 v-bind="number"></h3>
</div>
<script>
function myVue(options){
this._init(options)
};
myVue.prototype._init=function(options){
this.$options=options;
this.$el=document.querySelector(options.el);
this.$data=options.data;
this.$methods=options.methods;
//_binding保存着model与view的映射关系,也就是我们前面定义的Watcher的实例。当model改变时,我们会触发其中的指令类更新,保证view也能实时更新
this._binding={};
this._obverse(this.$data);
this._complie(this.$el)
}
myVue.prototype._obverse=function(obj){//obj={number:0}
var value;
for(key in obj){//便利obj对象
if(obj.hasOwnProperty(key)){
value=obj[key];
if(typeof value==="object"){//如果值还是对象,则遍历处理
this._obverse(value)
}
this._binding[key]={
_directives:[]
}
var binding=this._binding[key];
Object.defineProperty(this.$data,key,{
enumberable:true,
configurable:true,
get:function(){
console.log(`获取${value}`)
return value
},
set:function(newValue){
console.log(`更新${newValue}`)
if(value!==newValue){
// return newValue
value = newValue;
binding._directives.forEach(item => {
item.update();
});
}
}
})
}
}
}
myVue.prototype._complie=function(root){
var _this=this;
var nodes=root.children;
for(var i=0;i<nodes.length;i++){
var node=nodes[i];
if(node.children.length){
this._complie(node);
}
if(node.hasAttribute("v-click")){
node.onclick=(function(){
var attrVal=node.getAttribute("v-click");
return _this.$methods[attrVal].bind(_this.$data)
})()
}
if(node.hasAttribute("v-model") && (node.tagName=="INPUT" || node.tagName==="TEXTAREA")){
node.addEventListener("input",(function(key){
var attrVal=node.getAttribute("v-model");
console.log("****", nodes[key].value)
_this._binding[attrVal]._directives.push(new Watcher(
"input",
node,
_this,
attrVal,
"value"
))
return function(){
_this.$data[attrVal]=nodes[key].value;
}
})(i))
}
}
}
//指令类Watcher,采用绑定更新函数,实现对DOM元素的更新
function Watcher(name,el,vm,exp,attr){
this.name=name; //指令名称,例如文本节点,该值设为“text
this.el=el; //指令对应的DOM元素
this.vm=vm; //指令所属myVue实例
this.exp=exp; //指令对应的值,本例如”number
this.attr=attr; //绑定的属性值,本例为innerHTML
this.update();
}
Watcher.prototype.update=function(){
this.el[this.attr]=this.vm.$data[this.exp];
}
// 初始化myVue,放最后,确保js方法加载完成
window.onload=function(){
var app=new myVue({
el:"#app",
data:{
number:0,
},
methods:{
inorement:function(){
this.number++;
}
}
})
}
</script>
写的不完美,只能绑定number:0的数据,number:{num:0},就绑定不上