New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue中容易被忽略的知识点 #12

Open
zhaoqize opened this Issue Jan 11, 2018 · 3 comments

Comments

Projects
None yet
3 participants
@zhaoqize
Owner

zhaoqize commented Jan 11, 2018

Vue版本2.5.13

不要在选项属性或回调上使用箭头函数

比如

  • created: () => console.log(this.a)
  • vm.$watch('a', newValue => this.myMethod())
    因为箭头函数是和父级上下文绑定在一起的,this 不会是如你所预期的 Vue 实例,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误

具体见:这里

v-html

双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令:

<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>

具体见:这里

计算属性缓存 vs 方法

我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
这个 计算属性是基于它们的依赖进行缓存的 是什么意思呢?

computed: {
  now: function () {
    return Date.now()
  }
}

这里虽然Date.now()的值一直在变,但是他没有被watch,因为他不是响应式依赖。

具体见:这里

CSS样式自动添加前缀

v-bind:style 使用需要添加浏览器引擎前缀的 CSS 属性时,如 transform,Vue.js 会自动侦测并添加相应的前缀。

具体见: 这里

<template> 元素上使用 v-if 条件渲染分组

因为 v-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 <template> 元素。

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

具体见:这里

v-ifv-showv-for

  • v-if 是对页面元素的添加和移除操作
  • v-show 是对页面元素的显示和隐藏操作
  • 当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。

具体见:这里

数组更改检测注意事项

Vue 不能检测一下方式变动的数组,从而将不会触发视图更新

  • 当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
  • 当你修改数组的长度时,例如:vm.items.length = newLength

具体见:这里

对象更改检测注意事项

Vue 不能检测对象属性的添加或删除

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 现在是响应式的

vm.b = 2
// `vm.b` 不是响应式的

但是我们可以通过 Vue.set(object, key, value)方法向嵌套对象添加响应式属性。
另外还有这个常用的方法 Object.assign(),当我们想要为某个对象赋予 多个新属性 的时候,你应该这么玩

this.userProfile = Object.assign({}, this.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

具体见: 这里

v-for 中使用 methods 方法

<li v-for="n in even(numbers)">{{ n }}</li>

具体见: 这里

组件使用 v-for

在自定义组件里,你可以像任何普通元素一样用 v-for

<my-component v-for="item in items" :key="item.id"></my-component>

具体见: 这里

.once 事件修饰符(2.1.4 新增)

<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>

.once 也可以使用在 自定义组件 上。

具体见:这里

is 特性

由于dom某些元素本身的一些限制,<ul><ol><table><select> 这样的元素里允许包含的元素有限制。

<div id="app">
  <table>
    <money></money>
  </table>
</div>

Vue.component('txt',{
   template: '<div>I like money!</div>'
})

new Vue({
  el:'#app'
})

将会解析成下面的dom

<div id="app">
  <div>I like money!</div>
  <table></table>
</div>

如果想要解析正确,需要使用 is 这个属性。

<div id="app">
  <table>
    <tr is="money"></tr>
  </table>
</div>

这样dom就解析正确了。

<div id="app">
  <table>
     <tbody>
        <div>I like money!</div>
     </tbody>
  </table>
</div>

具体见:这里

将对象的所有属性作为 prop 进行传递

如果你想把一个对象的所有属性作为 prop 进行传递,可以使用不带任何参数的 v-bind (即用 v-bind 而不是 v-bind:prop-name)。例如,已知一个 todo 对象:

todo: {
  text: 'Learn Vue',
  isComplete: false
}

然后:

<todo-item v-bind="todo"></todo-item>

将等价于:

<todo-item
  v-bind:text="todo.text"
  v-bind:is-complete="todo.isComplete"
></todo-item>

具体见: 这里

非 Prop 特性的替换与合并

  • classstyle这两个特性的值都会做合并 (merge) 操作
  • 其他属性(如: type) 则会进行覆盖

具体见: 这里

Props的一般绑定和动态绑定

我们常用的一般是动态绑定:

// 父组件
<child :my-message="parentMsg"></child>

new Vue({
  data () {
    return {
       parentMsg: '来自父组件的数据'
    }
  }
})

// 子组件
Vue.component('child', {
  // 在 JavaScript 中使用 camelCase
  props: ['myMessage'],
  template: '<span>{{ myMessage }}</span>'
})

显示:

<span>来自父组件的数据</span>

一般绑定:

// 父组件
<!-- 在 HTML 中使用 kebab-case -->
<child my-message="hello!"></child>

子组件获得的是: 字符串 'hello!'

具体见:这里

.sync 修饰符(2.3.0+新增)

之前在 2.0 版本中移除后,在 2.3.0 中又加上了,只是调用的逻辑发生了变化,变成了一种语法糖。
如下代码:

<comp :foo.sync="bar"></comp>

会被扩展为:

<comp :foo="bar" @update:foo="val => bar = val"></comp>

当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:

this.$emit('update:foo', newValue)

有点类似与 v-model

另外需要注意的是:在computed中定义的属性需要手动设置 set

computed: {
    // 仅读取
    aDouble: function () {
      return this.a * 2
    },
    // 读取和设置
    aPlus: {
      get: function () {
        return this.a + 1
      },
      set: function (v) {
        this.a = v - 1
      }
    }
  }

具体见:这里

自定义组件的 v-model(2.2.0 新增)

默认情况下,一个组件的 v-model 会使用 value propinput 事件。这也是之前 v-model 默认绑定的元素 和 事件方法。

但是到 2.2.0 时候,我们可以通过 model 配置这个两个属性。

Vue.component('my-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean,
    // 这样就允许拿 `value` 这个 prop 做其它事了
    value: String
  },
  // ...
})
<my-checkbox v-model="foo" value="some value"></my-checkbox>

上述代码等价于:

<my-checkbox
  :checked="foo"
  @change="val => { foo = val }"
  value="some value">
</my-checkbox>

具体见:这里

插槽内容分发

我们不总能遇见我们的组件中包含了哪些元素,这时候我们在开发组件的时候,需要让这部分内容自定义。
假定 my-component 组件有如下模板:

<div>
  <h2>我是子组件的标题</h2>
  <slot>
    只有在没有要分发的内容时才会显示。
  </slot>
</div>

父组件模板:

<div>
  <h1>我是父组件的标题</h1>
  <my-component>
    <p>这是一些初始内容</p>
    <p>这是更多的初始内容</p>
  </my-component>
</div>

渲染结果:

<div>
  <h1>我是父组件的标题</h1>
  <div>
    <h2>我是子组件的标题</h2>
    <p>这是一些初始内容</p>
    <p>这是更多的初始内容</p>
  </div>
</div>

当然还有 具名插槽作用域插槽(2.1.0 新增)、slot-scope(2.5.0新增)

具体见:这里

动态组件

通过使用保留的 <component> 元素,并对其 is 特性进行动态绑定,你可以在同一个挂载点动态切换多个组件:

var vm = new Vue({
  el: '#example',
  data: {
    currentView: 'home'
  },
  components: {
    home: { /* ... */ },
    posts: { /* ... */ },
    archive: { /* ... */ }
  }
})
<component v-bind:is="currentView">
  <!-- 组件在 vm.currentview 变化时改变! -->
</component>

注意这里的 is 与 之前说的 v-bind:is 别混淆

具体见:这里

对低开销的静态组件使用 v-once

尽管在 Vue 中渲染 HTML 很快,不过当组件中包含大量静态内容时,可以考虑使用 v-once 将渲染结果缓存起来,就像这样:

Vue.component('terms-of-service', {
  template: '\
    <div v-once>\
      <h1>Terms of Service</h1>\
      ...很多静态内容...\
    </div>\
  '
})

具体见:这里

混合(mixins)的合并策略

周期钩子的合并策略

  • 同名钩子函数将混合为一个数组,因此都将被调用
  • 混合对象的钩子将在组件自身钩子 之前 调用
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')
    },
    conflicting: function () {
      console.log('from mixin')
    }
  }
}

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

vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "from self"

具体见:这里

@zhaoqize zhaoqize added Blog Vue labels Jan 14, 2018

@zhaoqize zhaoqize changed the title from Vue中常被遗漏的使用方式 to Vue中容易被忽略的知识点 Jan 17, 2018

@lyh2668

This comment has been minimized.

lyh2668 commented Jan 23, 2018

还可以讲一讲directive、filter,文档涉及的内容有点少

@zhaoqize

This comment has been minimized.

Owner

zhaoqize commented Jan 26, 2018

@lyh2668 好的,谢谢您的建议,后面我考虑结合源码说一下这几个问题。

@jessie-zly

This comment has been minimized.

jessie-zly commented Feb 1, 2018

可以聊聊vuex,以及现在2.x主推的axios及其配置

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment