Vue响应式原理

解析都在代码注释中;

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id='app'>
    {{name}}
    <input type="text" v-model='name'>
  </div>
  <script>
    //存储所有的订阅者
    class Dep{
      constructor(){
        //储存所有的订阅者
        this.subs=[]
      }
      //添加订阅者
      addSub(item){
        this.subs.push(item);
      }
      //通知所有的订阅者
      notify(){
        for(let ele of this.subs){
          ele.update();
        }
      }
    }
    //订阅类
    class Watcher{
      constructor(vm,node,name,type){
        Dep.target=this;
        this.vm = vm;//vue实例
        this.node = node;//节点Dom对象
        this.name=name;//该dom节点使用的vue实例上的data数据属性名
        this.type=type;//当给不同节点赋值时,表单需要用到value属性,而文本节点则需要通过nodeValue赋值
        this.update();
        Dep.target=null;
      }
      update(){
        //调用get方法获取数据的最新值
        this.get();
        //为节点赋值
        this.node[this.type]=this.value;
      }
      //获取vm实例上数据的最新值
      get(){
        this.value=this.vm[this.name];
      }
    }
    class Compile{
      constructor(node,vm){
        this.frag = this.nodeToFragment(node,vm);
      }
      //循环将所有节点
      //这里我们只涉及一层子节点
      nodeToFragment(node,vm){
        let fragment = document.createDocumentFragment();
        let child;
        while(child=node.firstChild){
          //将所有节点进行编译以及对双向绑定的表单元素绑定事件
          this.compileElement(child,vm);
          fragment.appendChild(child);
        }
        return fragment;
      }
      compileElement(node,vm){
        //编译元素节点以及文本节点
        //匹配文本节点的正则表达式
        let reg = /\{\{(.*)\}\}/;
        if(node.nodeType===1){
          //元素节点
          //获取节点的所有属性,检测是否有v-model,即是否需要进行双向数据绑定
          let attributes = node.attributes;
          for(let ele of attributes){
            if(ele.nodeName==='v-model'){
              let name = ele.nodeValue;
              node.addEventListener('input',(e)=>{
                vm[name]=e.target.value;
              })
              //订阅数据改变通知
              new Watcher(vm,node,name,'value');
            }
          }
        }
        if(node.nodeType===3){
          //文本节点
          if(reg.test(node.nodeValue)){
            let name = RegExp.$1;//获取第一个捕获组中的内容
            new Watcher(vm,node,name,'nodeValue');
          }
        }
      }
    }
    class Vue{
      constructor(params){
        //将传递过来的data内的数据挂载为实例的根元素
        let data = params.data;
        let keyArr = [];
        for(let key in data){
          this[key] = data[key];
          keyArr.push(key);
        }
        this.observe(keyArr,this)
        //编译模板文件
        this.el=params.el;
        let model = document.querySelector(this.el);
        //接收编译好的模板代码
        let compiledModel = new Compile(model,this).frag;
        //将编译好的模板代码添加至DOM中
        model.appendChild(compiledModel);
      }
      //循环递归遍历每一个属性
      observe(keyArr,self){
        keyArr.forEach(key=>{
          //循环判断每一个属性值如果是对象需要递归进行遍历
          if(Object.prototype.toString.call(self[key])==='[object Object]'){
            let dataArr = [];
            for(let keyOne in self[key]){
              dataArr.push(keyOne);
            }
            observe(dataArr,self[key]);
          }else{
            this.defineActive(self,key,self[key]);
          }
        })
      }
      //数据劫持
      defineActive(self,key,val){
          //创建一个储存订阅者实例的Dep实例
          let dep = new Dep();
          Object.defineProperty(this,key,{
            get(){
              //检测,如果Dep.target不为null,则代表有watcher实例在初始化中,需要将其放入Dep实例中存储
              if(Dep.target){
                dep.addSub(Dep.target);
              }
              return val;
            },
            set(newVal){
              if(val===newVal){
                return;
              }
              val=newVal;
              //当vue实例中的数据发生变化,通知所有的订阅者
              dep.notify();
            }
          })
      }
    }
    let vm = new Vue({
      el:'#app',
      data:{
        name:'jack',
        age:16
      }
    })
  </script>
</body>
</html>

 

 

AI实战-学生生活方式模式数据集分析预测实例(含24个源代码+69.54 KB完整的数据集) 代码手工整理,无语法错误,可运行。 包括:24个代码,共149.89 KB;数据大小:1个文件共69.54 KB。 使用到的模块: pandas os matplotlib.pyplot seaborn plotly.express warnings sklearn.model_selection.StratifiedShuffleSplit sklearn.pipeline.Pipeline sklearn.compose.ColumnTransformer sklearn.impute.SimpleImputer sklearn.preprocessing.OrdinalEncoder numpy sklearn.model_selection.cross_val_score sklearn.linear_model.LinearRegression sklearn.metrics.mean_squared_error sklearn.tree.DecisionTreeRegressor sklearn.ensemble.RandomForestRegressor sklearn.model_selection.train_test_split sklearn.preprocessing.PowerTransformer imblearn.pipeline.Pipeline imblearn.over_sampling.SMOTE sklearn.ensemble.AdaBoostClassifier sklearn.metrics.accuracy_score sklearn.metrics.precision_score sklearn.metrics.recall_score sklearn.metrics.f1_score optuna scipy.stats torch torch.nn torchvision.transforms torchvision.models torch.optim cv2 glob glob.glob torch.utils.data.DataLoader torch.utils.data.Dataset random.shuffle torch.utils.data.random_split torchsummary.summary matplotlib.ticker pyspark.sql.SparkSession pyspark.sql.functions.count pyspark.sql.functions.max pyspark.sql.functions.min pyspark.sql.functions.avg pyspark.sql.functions.stddev_samp pyspark.sql.functions.skewness pyspark.sql.functions.kurtosis pyspark.sql.functions pyspark.ml.feature.Tokenizer pyspark.ml.feature.VectorAssembler sklearn.preprocessing.LabelEncoder keras.models.Sequential keras.layers.Dense keras.utils.to_categorical ptitprince statsmodels.distributions.empirical_distribution.ECDF statsmodels.stats.outliers_influence.variance_inflation_factor ppscore sklearn.feature_selection.mutual_info_classif sklearn.decomposition.PCA sklearn.model_selection.StratifiedKFold sklearn.tree.DecisionTreeClassifier sklearn.metrics.balanced_accuracy_score sklearn.metrics.confusion_matrix mlxtend.plotting.plot_confusion_matrix scipy.stats.pearsonr scipy.stats.f_oneway sklearn.feature_selection.mutual_info_regression sklearn.feature_selecti
AI实战-信用卡申请风险识别数据集分析预测实例(含9个源代码+91.57 KB完整的数据集) 代码手工整理,无语法错误,可运行。 包括:9个代码,共44.98 KB;数据大小:1个文件共91.57 KB。 使用到的模块: pandas os matplotlib.pyplot seaborn wordcloud.WordCloud sklearn.model_selection.train_test_split sklearn.preprocessing.LabelEncoder sklearn.ensemble.RandomForestClassifier sklearn.metrics.accuracy_score sklearn.metrics.classification_report sklearn.metrics.confusion_matrix plotly.express plotly.subplots.make_subplots plotly.graph_objects plotly.io sklearn.base.BaseEstimator sklearn.base.TransformerMixin sklearn.preprocessing.StandardScaler sklearn.preprocessing.OrdinalEncoder sklearn.pipeline.make_pipeline sklearn.compose.make_column_transformer imblearn.over_sampling.RandomOverSampler sklearn.svm.SVC sklearn.tree.DecisionTreeClassifier sklearn.ensemble.HistGradientBoostingClassifier sklearn.ensemble.GradientBoostingClassifier sklearn.neighbors.KNeighborsClassifier sklearn.model_selection.GridSearchCV sklearn.ensemble.VotingClassifier torch lightning torchmetrics.Accuracy torch.utils.data.Dataset torch.utils.data.DataLoader numpy warnings matplotlib wordcloud.STOPWORDS collections.Counter sklearn.ensemble.ExtraTreesClassifier sklearn.ensemble.AdaBoostClassifier sklearn.ensemble.BaggingClassifier xgboost.XGBClassifier lightgbm.LGBMClassifier catboost.CatBoostClassifier sklearn.linear_model.LogisticRegression sklearn.model_selection.RandomizedSearchCV sklearn.preprocessing.MinMaxScaler imblearn.over_sampling.SMOTE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值