你不知道的vue那些事

988 阅读2分钟

Vue两大核心

  1. 组件化
  2. 数据驱动

插件开发核心

  1. 以默认配置为优先,以用户配置为覆盖;
  2. 自定义策略
  • vue自定义策略配置
 <script>
        //配置对象
        let vm = new Vue({
            data: {
                id: 'fiona'
            }
        });
        console.log(vm.$options);
    </script>

从上图可以看到,传入的data是个对象,但是vue将options变成了一个function,为什么了?

function initMixin (Vue) {
  Vue.prototype._init = function (options) {  
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      );  
  } 
}

function resolveConstructorOptions (Ctor) {
  options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions);      
}


//组件:parent:父组件对象  child:组件  vm实例
function mergeOptions (
  parent,
  child,
  vm
) {  
  if (!child._base) {
    if (child.extends) {
      parent = mergeOptions(parent, child.extends, vm);
    }
    if (child.mixins) {
      for (var i = 0, l = child.mixins.length; i < l; i++) {
        parent = mergeOptions(parent, child.mixins[i], vm);
      }
    }
  }

  var options = {};
  var key;
  //key指的是components  directives  filters var ASSET_TYPES = ['component','directive', 'filter'];
  for (key in parent) {
    mergeField(key);
  }
  for (key in child) {
    //父组件和子组件都有的字段,只做一次策略处理    
    if (!hasOwn(parent, key)) {
      mergeField(key);
    }
  }
  //自定义策略
  function mergeField (key) {
    var strat = strats[key] || defaultStrat;
    options[key] = strat(parent[key], child[key], vm, key);
  }
  return options
}

//自定义策略处理
strats.data = function (
  parentVal,
  childVal,
  vm
) {
  if (!vm) {
    if (childVal && typeof childVal !== 'function') {
      warn(
        'The "data" option should be a function ' +
        'that returns a per-instance value in component ' +
        'definitions.',
        vm
      );

      return parentVal
    }
    return mergeDataOrFn(parentVal, childVal)
  }

  return mergeDataOrFn(parentVal, childVal, vm)
};


function mergeDataOrFn (
  parentVal,
  childVal,
  vm
) {
 
    return function mergedInstanceDataFn () {    
    }
  }


  //自定义策略函数:比如count 策略函数
  Vue.config.optionMergeStrategies.count = function(parent,child,vm){
    return child>=10?child:10;
  }


  function initGlobalAPI (Vue) {
    // config
    var configDef = {};
    configDef.get = function () { return config; };
    {
      configDef.set = function () {
        warn(
          'Do not replace the Vue.config object, set individual fields instead.'
        );
      };
    }
    Object.defineProperty(Vue, 'config', configDef);
  }

  • 从上面源码可以分析得知vue组装配置的过程:
  1. 有默认策略,以默认配置为优先,用户配置为覆盖;
  2. 有自定义策略,如strats.data,里面组装了data的策略;
  3. 提供用户自第一策略接口,可以自定义一些策略,比如这里可以权限处理;

无所不能的render函数

//Button.vue
<script>
export default{
    props:{
        type:{
            type:String,
            default:'normal'
        },
        text:{
            type:String,
            default:'demo'
        }
    },
    render(h){
        return h('div',{
            class:{
                btn:true,
                'btn-success':this.type === 'success',
                'btn-danger':this.type === 'danger',
                'btn-warning':this.type === 'warning',
                'normal':this.type === 'normal',
            },
            domProps:{
                innerText:this.text
            },
            on:{
                click:this.clickEvent
            }
        })
    },

    methods:{
        clickEvent:function(){
            this.$emit('childClick');
        }
    }
}
</script>
<style scoped>
.btn{
    width:100px;
    height:40px;
    line-height:40px;
    text-align:center;
    color:#ffffff;
}
.btn-success{
    background:green;
}
.btn-danger{
    background:red;
}
.btn-warning{
    background:orange;
}
.normal{
    background:blueviolet;
}
</style>

路由分区,动态路由,按需加载

注册全局组件

//global.js,在main.js引入该文件
import Vue from 'vue';
function changeStr(str){
    return str.charAt(0).toUpperCase() + str.slice(1);
}
const requireComponent = require.context('.',false,/\.vue$/);
requireComponent.keys().forEach(fileName => {
    const config = requireComponent(fileName);
    const componentName = changeStr(fileName.replace(/^\.\//,'').replace(/\.w+$/,''));
    Vue.component(componentName,config.default || config)
});

路由分区,并且统一加入路由

//router下的index.js中统一注册
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'


Vue.use(Router)
const routerList = [];
function importAll(r){
  r.keys().forEach(key => {
    routerList.push(r(key).default);
  });
}
importAll(require.context('.',true,/\.routes\.js/));

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },

    ...routerList
  ]
})