可复用性&组合总结

本文介绍了Vue中的混入(mixins)概念及应用,包括混入的使用方式、选项合并规则以及自定义选项合并策略。同时,还探讨了自定义指令的注册与使用方法,包括钩子函数的应用及参数说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

混入

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属性

<input 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更接近编译器。

<h1>
  <a name='hello-world' href='#hello-world'>hello world</a>
</h1>

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

<anchored-heading :level="1">hello word</anchored-heading>
当我们开始写一个通过level prop动态生成的heading标签组件
<script type='text/x-template' id='adchored-heading-template'>
 <h1 v-if="level === 1">
    <slot></slot>
  </h1>
  <h2 v-else-if="level === 2">
    <slot></slot>
  </h2>
  <h3 v-else-if="level === 3">
    <slot></slot>
  </h3>
  <h4 v-else-if="level === 4">
    <slot></slot>
  </h4>
  <h5 v-else-if="level === 5">
    <slot></slot>
  </h5>
  <h6 v-else-if="level === 6">
    <slot></slot>
  </h6>
</script>

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

<ul v-if='items.length'>
  <li v-for='item in items'>{{item.name}}</li>
</ul>
<p v-else>No items fount.</p>

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中
<div v-bind:id='rawId | formatId'></div>

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

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 () {}
  })
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值