Vue开发、学习笔记,持续记录

Vue每天学一些,慢慢的也学下来了。记一些笔记

开始

文档理解

1. is 命令

用于动态组件且基于 DOM 内模板的限制来工作。就是扩展 html标签的限制,动态指定组件。

2. slot ,插槽

组件内定义了该标签时,调用组件时,组件标签中间的内容将会替换该标签。<AB>我是插入的内容</AB>。插槽的内容是在父级进行渲染的。vm.$scopedSlots,作用类似$ref,用于获取组件接收到的所有插槽对象。

<main>
    <slot>中间可以定义默认内容</slot>
</main>
/*独占默认插槽*/
<current-user v-slot:default="slotProps"> 
     {{ slotProps.user.firstName }} 
</current-user>

3. 动态指令参数

可以给指令添加动态的参数;如v-bind的绑定的属性名、v-on的事件名、v-slot的插槽名;([任意JS表达式])

v-mydirective:[argument]="value"
<base-layout>
  <template v-slot:[dynamicSlotName]>
    ...
  </template>
</base-layout>
argument 
Vue.directive('pin', {
  bind: function (el, binding, vnode) {
    el.style.position = 'fixed'
    var s = (binding.arg == 'left' ? 'left' : 'top')
    el.style[s] = binding.value + 'px'
  }
})

4. scoped和>>>、v-deep、depp()

可以在一个组件中同时使用有 scoped 和非 scoped 样式;如果希望 scoped 样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用 >>> 操作符

<style scoped>
     .a >>> .b { /* ... */ }
</style>

5. v-bind.sync

<comp :foo.sync="bar"></comp>
/* 拓展为 */
<comp :foo="bar" @update:foo="val => bar = val"></comp>
/* 当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件 */
this.$emit('update:foo', newValue)

6. Vue数据响应式

对于data内的数组和对象初始时定义的元素和属性,都支持响应式,但是对于属性或元素的新增(除特定的被重写的数组对象方法之外的修改)需要使用set接口添加响应式。(深度监视)。

对于整个对象或者数组的替换也会保持响应式。

7. Key详解

使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。也可以用于强制替换元素/组件而不是重复使用它。不使用key时,Vue只会就地更新现有的Dom,最大限度的复用已存在的dom。和v-for一起使用时,key需要使用bind绑定,否则key值只是字符串。

8. 虚拟 DOM

Vue 通过建立一个虚拟 DOM 来追踪自己要如何改变真实 DOM。

return createElement('h1', this.blogTitle)
createElement createNodeDescription

创建 VNode 的方法是 createElement,如 createElement(tag,{},[])或者 createElement(tag,{},string),其中 tag 是创建元素的标签名,「{}」是创建元素的属性,「[]」是创建元素的子元素列表,string 是文本。

9. 渲染函数和模板

/* @return {VNode} */
createElement(
 /* {String | Object | Function} */
 /* 一个HTML标签字符串,组件选项对象,或者一个返回值类型为String/Object的函数。该参数是必须的 */
 'div',
/* {Object} */
 /* 一个包含模板相关属性的数据对象,这样我们可以在template中使用这些属性,该参数是可选的。 */
{
     attrs: {
        name: headingId,
        href: '#'+headingId
    },
     style: {
        color: 'red',
        fontSize: '20px'
    },
     'class': {
        foo: true,
        bar: false
      },
      /* DOM属性 */
      domProps: {
         innerHTML: 'baz'
      },
      /* 组件props */
       props: {
          myProp: 'bar'
      },
       /* 事件监听基于 'on' */
       /* 所以不再支持如 'v-on:keyup.enter' 修饰语 */
       /* 需要手动匹配 KeyCode */
       on: {
           click: function(event) {
                event.preventDefault();
                console.log(111);
          }
        }
  }
/* {String | Array} */
 /* 子节点(VNodes)由 createElement() 构建而成。可选参数 */
 /* 或简单的使用字符串来生成的 "文本节点"。 */
[
   'xxxx',
   createElement('h1', '一则头条'),
   createElement(MyComponent, {
     props: {
       someProp: 'xxx'
    }
  }),
/*获取默认插槽中的内容*/
   this.$slots.default
]
)

实际应用:

render: function (createElement) {
  // `<div><slot></slot></div>`
  return createElement('div', this.$slots.default)
}

10. directives

用于注册一个自定义指令。

11.vue mixins 合并策略 

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

组件的深入理解

  • 分类:非单文件组件(一般直接在html中定义)、单文件组件(CLI下的.Vue),组件:创建、注册、使用。
  • Vue.extend({}),用于创建一个组件(每次调用都会生成并返回一个单独的VueComponent类)。data配置项只能是函数式,使用对象形式在组件复用时会导致引用重复的对象。
  • Vue.component(),用于注册一个全局组件。可直接传入一个配置项对象,该语句被调用时,Vue将自己调用extend函数。
  • Vue实例对象是Vue类的对象(配置项对象中的this是Vue),组件全部是VueComponent类的对象(配置项对象中的this为VueComponent)。
  • 在Vue2.x中程序结构为:Vm对象->Vc对象->单个或多个Vc对象->单个或多个Vc对象;
  • 组件内的使用的组件对象都可以在组件对象的children属性中找到。
  • 父组件给子组件传递值使用props,子组件给父组件传递数据使用自定义事件绑定父组件的对象方法进行事件处理。
  • v-if和v-show的区别:如果使用v-show,切换组件,只不过是相应组件的显示和隐藏;而v-if则会销毁之前的组件并渲染新组建。如果我们在v-if切换的组件之外,套上标签,那么本该销毁的组件则会被缓存起来。当我们重新切换回来时依旧会重新渲染(确实找不到对应的dom元素),但是之前的vue实例没有被销毁,vue实例中的属性和变量都还在,这个标签非常适合做单页面应用。
  • 所有组件都有完整的生命周期。
  • Vue.extends(),用于继承一个组件的配置。

1.动态组件

<!-- 动态组件由 vm 实例的 `componentId` property 控制 -->
<component :is="componentId"></component>
<!-- 也能够渲染注册过的组件或 prop 传入的组件 -->
<component :is="$options.components.child"></component>
component,渲染一个“元组件”为动态组件。依 is 的值,来决定哪个组件被渲染。

2.异步组件

Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。(不要要渲染时,相当于无视,普通组件则是直接解析)。

把 webpack 2 和 ES2015 语法加在一起,我们可以这样使用动态导入:

Vue.component(
  'async-webpack-example',
  // 这个动态导入会返回一个 `Promise` 对象。
  () => import('./my-async-component')
)

3.拓展

凡是函数都有一个prototype(显式原型对象),函数本身也是一个对象,有__proto__属性。

凡是对象都会有一个属性那就是__proto__(指向构造函数的prototype,隐式原型对象)

原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。

Props属性

1.完整的prop声明

app.component('my-component', {
  props: {
    // 基础的类型检查 (`null` 和 `undefined` 值会通过任何类型验证)
    propA: Number,
    // 多个可能的类型
    propB: [String, Number],
    // 必填的字符串
    propC: {
      type: String,
      required: true
    },
    // 带有默认值的数字
    propD: {
      type: Number,
      default: 100
    },
    // 带有默认值的对象
    propE: {
      type: Object,
      // 对象或数组的默认值必须从一个工厂函数返回
      default() {
        return { message: 'hello' }
      }
    },
    // 自定义验证函数
    propF: {
      validator(value) {
        // 这个值必须与下列字符串中的其中一个相匹配
        return ['success', 'warning', 'danger'].includes(value)
      }
    },
    // 具有默认值的函数
    propG: {
      type: Function,
      // 与对象或数组的默认值不同,这不是一个工厂函数——这是一个用作默认值的函数
      default() {
        return 'Default function'
      }
    }
  }
})

2.传递对象

如果想要将一个对象的所有 property 都作为 prop 传入,可以使用不带参数的 v-bind (用 v-bind 代替 :prop-name)。

<blog-post v-bind="post"></blog-post>
//等价于
<blog-post v-bind:id="post.id" v-bind:title="post.title"></blog-post>

问题总结

1. 计算属性和自定义方法的区别

methods

2. 实战笔记

/* 开始模板渲染 */
this.$nextTick(function() {
     /* 使添加的input自动获取焦点 */
     this.$refs.addInput.focus();
 })				

3. 动态设置元素的ref并获取元素对象

$nextTickrefv-for$refs$refs

补充知识

1.全局事件总线

总线:组件绑定事件,另一个组件触发事件,通过事件传递数据。

Vue2.x 可以使用inject、provide 接口替代全局事件总线。

Vue 2 当中事件总线是通过在现有的 Vue 应用实例中新建一个新的 Vue 实例,通过这个实例来传递事件触发行为。 可更宽范围地跨组件状态通信
但显然从使用上就可以看出这个方案是相对比较笨重的,在 Vue 3 版本中,子孙组件之间的状态通信有了一种新的方案:Provide / Inject

前提:

  1. 必须拥有$on、$off、$emit组件事件方法。
  2. 必须让所有组件都可以访问到。
  3. 最简洁的实现方法。
/*创建vm*/
new Vue({
	el:'#app',
	render: h => h(App),
	beforeCreate() {
		Vue.prototype.$bus = this /*安装全局事件总线*/
	},
})

全局事件总线适用于 父子、子父以外的数据传输情况。可以在Vue的beforeCreate事件里,将Vue的实例作为Vue的prototype对象的一个属性,即可满足上方所有条件。所有组件都可以使用this.$bus访问到作为总线的对象。

使用时应注意避免事件名冲突。组件销毁之前,应解绑在总线上绑定过的事件。

2.监视属性

user.user = res.data.data;
  /* res.data.data = news = olds  = user.user */
  /* 他们引用的都是一个对象 */
 watch(user.user,function (news,olds) {
}

3.provide、inject

provide() {
    return {
      foo: this.foo,
      bar: this.bar
   }
}