可复用性&组合总结

混入

1.什么是混入?做什么用的?怎么用?

混入(mixins)是一种分发vue组件中可复用功能非常灵活的方式。混入对象可以包含任意组件选项,当组件使用混入对象时,所有混入对象的选项将混入该组件本身的选项。

例如:

//定义一个混入对象
var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin')
    }
  }
}
//定义一个使用混入对象的组件
var Component = Vue.extend({//用来创建一个子类
  mixins: [myMixin]
})
var component = new Component()

2.选项合并是什么意思?

混入对象选项对象需要和组件的选项对象混合到一起,当二者同名时,这些选项将以恰当的方式混合

比如:数据对象在内部会进行浅合并,在和组件的数据发生冲突时以组件数据优先

var mixin = {
  data: function () {
    return {
      message:'hello',
      foo:'abc'
    }
  }
}
new Vue({
  mixins: [mixin],
  data: function () {
    return {
      message:'goodbye',
      bar:'def'
    }
  },
  created: function () {
    console.log(this.$data)
   //{message:'goodbye',foo:'abc',bar:'def'}
  }
}) 

同名钩子函数将混合为一个数组,因此都将被调用。另外,混入对象的钩子将在组件之前调用

var mixin = {
  created: function () {
    console.log("混入对象先被调用")
  }
}
new Vue({
  mixins: [mixin],
  created: function () {
    console.log("组件钩子后被调用")
  }
})

值为对象的选项,例如methods,components和directives,将被混合为同一个对象,两个对象键名冲突时,去组件对象的键值对

var mixin = {
  methods: {
    foo: function () {
      console.log('foo')
    },
    aaa: function () {
      console.log('from mixin')
    }
  }
}

var vm = new Vue({
  mixins: [mixin],
  methods: {
    bar: function () {
      console.log('bar')
    },
    aaa: function () {
      console.log('from self')
    }
  }
})
vm.foo() //foo
vm.bar() //bar
vm.aaa() //from self

Vue.extend()也使用相同的策略进行合并

3.自定义选项合并策略如何实现?用在哪方面?

自定义选项将使用默认策略,即简单地覆盖已有值。如果想让自定义选项以自定义逻辑合并,可以向Vue.config.optionMergeStrategies添加一个函数:

Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {}

对于大多数对象选项,可以使用methods的合并策略

var strategies = Vue.config.optionMergeStrategies
strategies.myOption = strategies.methods

自定义指令

除了核心功能默认内置的指令(v-model和v-show),vue也允许注册自定义指令。有的情况下,仍然需要对普通dom元素进行底层操作,这个时候就用到自定义指令

Vue.directive('focus', {
//当被绑定的元素插入到dom中时
  inserted: function (el) {
    el.focus();
  }
})

如果你想注册局部指令,组件中也接收一个directives的选项

directives: {
  focus: {
    inserted: function (el) {
      el.focus()
    }
  }
}

然后你可以在模板中任何元素使用新的v-focus属性

2.钩子函数

一个指令定义对象可以提供如下几个钩子函数(可选):

  ...bind:只调用一次,指定第一次绑定到元素时调用,在这里可以进行一次性的初始化设置

。。inserted:被绑定元素插入父节点时调用

。。update:所在组件的vnode更新时调用,但是可能发生在其子vnode更新之前

。。componentUpdated:指令所在组件的vnode及其子vnode全部更新后调用

。。unbind:只调用一次,指令与元素解绑时调用

3.钩子函数参数

。。el:指令所绑定的元素,可以用来直接操作DOM

。。binding:一个对象

     。。name:指令名,不包括v-前缀

    。。value:指令的绑定值

    。。oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用

     。。expression

渲染函数 &jsx

vue推荐在绝大多数情况下使用template来创建你的html,然而在一些场景中,你真的需要javascript的完全编程能力,这就是render函数,他比template更接近编译器。

hello world

在html层,我们决定这样定义组件:

hello word
当我们开始写一个通过level prop动态生成的heading标签组件


Vue.component('anchored-heading',{
  template:"#anchored-heading-template",
  props: {
    level: {
      type:Number,
      required: true
    }
  }
})

在这种情况下使用template并不是最好的选择,首先代码冗长,为了在不同级别的标题中插入锚点元素,我们需要重复的使用slot

虽然模板在大多数组件中都非常好用,但是在这里它就不是很简洁了,我们来尝试使用render函数重写上面的例子:

Vue.component('anchored-heading', {
  render: function (createElement) {
    return createElement(
      'h' + this.level, //tag name标签名称
      this.$slot.default //子组件中的阵列
    )
  },
  props: {
    level: {
      type: Number,
      required: true
return createElement('h1',this.blogTitle)

} }})

1.节点 树 以及虚拟dom

当浏览器读到一些html代码时,它会建立一个dom节点树来保持追踪,如同 一个家谱

vue通过建立一个虚拟dom对真实dom发生的变化保持追踪

return createElement('h1', this.blogTitle)

createElement 到底会返回什么呢?其实不是一个实际的dom元素,它更准确的名字可能是createNodeDescription,因为它所包含的信息会告诉vue页面需要渲染什么样的节点,及其子节点。我们把这样的节点描述为虚拟节点Vnode,虚拟dom是我们vue组件树建立起来的整个vnode树的称呼

createElement参数

createElement(
//一个html标签字符串,组件选项对象,或者解析上述任何一种的async异步函数,必要参数
'div',
//一个包含模板相关属性的数据对象,这样,你可以在template中使用这些属性,可选参数
{},
//子节点,或者使用字符串生成的文本节点
[
 '先写一些文字',
 createElement(MyComponent, {
  props: {
    someProp: "foobar"
  }
})
]
)
var getChildrenTextContent = function (children) {
  return children.map(function (node) {
    return node.children
      ? getChildrenTextContent(node.children)
      :node.text
  }).join('')
}

Vue.component('anchored-heading', {
  render: function (createElement) {
    var headingId = getChildrenTextContent(this.$slots.default)
    .toLowerCase()
    .replace(/\W+/g,'-')
    .replace(/(^\-|\-$)/g, '')
   return createElement(
     'h' + this.level,
     [
       createElement('a', {
         attrs: {
            name: headingId,
            href: '#' + headingId
          }
        },this.$slots.default)
      ]
   )
  },
  props: {
    level: {
      type:Number,
      required: true
    }
  }
})

3.约束

组件树中的所有vnodes必须是唯一的,这意味着,下面的render function是无效的

render: function (createElement) {
  var myParagrapVNode = createElement('p','h1')
  return createElement('div', [
    myParagraphVNode,myParagraphVNode
  ])
}

如果你需要重复多次的元素/组件,你可以使用工厂函数来实现

render: function (createElement) {
  return createElement('div',
    Array.apply(null, { length: 20 }).map(function () {
       return createElement('p','hi')
    })
  )
}

4.使用javascript代替模板功能

html

  • {{item.name}}

No items fount.

js

props:['items'],
render: function (createElement) {
  if (this.items.length) {
    return createElement('ul', this.items.map(function (item) {
     return createElement('li', item.name)
}))
  }else {
    return createElement('p','No items found.')
  }
}

render函数中没有与v-model相应的api,你必须自己来实现相应的逻辑

prop: ['value'],
render: function (createElement) {
  var self = this
  return createElement('input', {
    domProps: {
      value: self.value
    },
    on: {
     input: function (event) {
       self.$emit('input', event.target.value)
     }
    }
  })
}

过滤器

vue允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和v-bind表达式。过滤器应该被添加在javascript表达式的尾部,由管道符合

//双花括号中
{{ message | capitalize}}

//在v-bind中

你可以在组件的选项中定义本地的过滤器

filter: {
  capitalize: function (value) {
    if(!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}

或者创建vue实例之前全局定义过滤器:

Vue.filter('capitalize', function (value) {
  if(!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})
new Vue({
})

过滤器函数总接收表达式的值作为第一个参数,并且过滤器可以串联

{{ message | filterA | filterB }}
message作为参数传到filterA中,filterA处理后的数据作为参数传到filterB中


插件

开发插件

插件通常会为vue添加全局功能

1.添加全局方法或者属性

2.添加全局资源:如指令、过滤器、过渡

3.通过全局mixin方法添加一些组件选项

4.添加vue实例方法,通过把他们添加到vue.protetype上实现

5.一个库,提供自己的API,同时提供上面提到的一个或多个功能

vue.js插件应当有一个公开方法install,这个方法的第一个参数是vue构造器,第二个参数是一个可选的选项对象

MyPlugin.install = function (Vue, options) {
  //添加全局方法或属性
  Vue.myGolbalMethod = function () {
    //逻辑
  }
  //添加全局资源
  Vue.directive('my-directive' ,{
    bind (el, binding ,vnode, oldVnode) {
      //逻辑
  }
  })
   //注入组件
  Vue.mixin({
    created: function () {}
  })
}

你可能感兴趣的:(可复用性&组合总结)