vue问题总结1

双向绑定
vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
var obj = {}
var val = "val"//txt属性默认值
Object.defineProperty(obj, 'txt', {
    get: function () {
        console.log("diaoyong")
        return val
    },
    set: function (newValue) {
        document.getElementById('txt').value = newValue
        document.getElementById('show').innerHTML = newValue
    }
})
document.addEventListener('keyup', function (e) {
    obj.txt = e.target.value
})            

 为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty?

Object.defineProperty 本身有一定的监控到数组下标变化的能力,但是在 Vue 中,从性能/体验的性价比考虑,尤大大就弃用了这个特性(Vue 为什么不能检测数组变动 )。为了解决这个问题,经过 vue 内部处理后可以使用以下几种方法来监听数组
push();
pop();
shift();
unshift();
splice();
sort();
reverse();

由于只针对了以上 7 种方法进行了 hack 处理,所以其他数组的属性也是检测不到的,还是具有一定的局限性。

Object.defineProperty 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue 2.x 里,是通过 递归 + 遍历 data 对象来实现对数据的监控的,如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象是才是更好的选择。Proxy 可以劫持整个对象,并返回一个新的对象。Proxy 不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。

如果在created中操作dom 

this.$nextTick

穿透属性

$attrs包含从父组件传过来的属性,但不包含子组件中prop中的属性以及classstyle,所以对于那些html元素原生属性,可以不用再子组件中声明,直接从父组件中传进来就好
// 子组件
<template>
 <div>
     <input type="text" name="" id="" v-bind="$attrs" v-on='listeners'/>
 </div>
</template>
  props: {
    test: {
      type: String,
      default: '123456'
    }
  },
  created () {
    console.log(`props:%o`, this.$props)  // {test: '测试'}
    console.log('attrs:%o', this.$attrs) // {value: '测试'}
  },
 
  // 父组件
 <myInput :value="value" :class="class_" :style='style' :test='test' @input1="input"/>
   data () {
    return {
      style: {
        color: 'red'
      },
      value: '测试',
      class_: 'test',
      test: '测试'
    }
  }

 

由于在子组件中input并不是根元素,默认情况下父组件的不被认作 props 的特性绑定将会“回退”且作为普通的 HTML 特性应用在子组件的根元素上,例如根节点div会有value="测试"的属性,所以子组件需要设置 inheritAttrs: false去掉根元素默认行为,这样就可以通过实例属性 $attrs 可以让这些特性生效,且可以通过 v-bind 显性的绑定到非根元素上。

export default {
  inheritAttrs: true
}

 

自定义组件v-model

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的model 选项可以用来避免这样的冲突
 
ref注册子组件 父组件通过$refs.funcname调用子组件方法
子组件通过$emit
 
vue修饰符
v-model的修饰符
.lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 ,我们可以添加 lazy 修饰符,从而转变为使用 change事件进行同步:
<!-- 在“change”时而非“input”时更新 --><input v-model.lazy="msg" >
.number
如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 .number修饰符:
<input v-model.number="age" type="number">
.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:
<input v-model.trim="msg">
v-on的修饰符
.stop
该修饰符将阻止事件向上冒泡。同理于调用 event.stopPropagation() 方法
.prevent
该修饰符会阻止当前事件的默认行为。同理于调用 event.preventDefault() 方法
.self
该指令只当事件是从事件绑定的元素本身触发时才触发回调
.one
该修饰符表示绑定的事件只会被触发一次
. capture
即是给元素添加一个监听器,当元素发生冒泡时,先触发带有该修饰符的元素。若有多个该修饰符,则由外而内触发。 
就是谁有该事件修饰符,就先触发谁。 
 

父子组件的生命周期执行顺序

 

1.加载渲染过程

 

父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted 

 

2.子组件更新过程

 

父beforeUpdate->子beforeUpdate->子updated->父updated 
   

 

3.销毁过程

 

父beforeDestroy->子beforeDestroy->子destroyed->父destroyed 
   

 

 
computed 计算属性,不需要调用可以直接在dom中使用  不支持异步 可以传参数
1.是计算值
2.应用:就是简化tempalte里面{{}}计算和处理props或$emit的传值,如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一
3.具有缓存性,只有依赖数据发生改变,才会重新进行计算,页面重新渲染值不变化,计算属性会立即返回之前的计算结果,而不必再次执行函数
给计算属性的值赋值必须有set方法
watch监听数据变化
1.是观察的动作  支持异步,监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值
2.应用:监听props,$emit或本组件的值执行异步操作,当一个属性发生变化时,需要执行对应的操作;一对多;
3.无缓存性,页面重新渲染时值不变化也会执行

同:

 computed和watch都是观察页面的数据变化的。

 异:

 computed只有当页面数据变化时才会计算,当数据没有变化时,它会读取缓存。而watch每次都需要执行函数,methods也是每次都需要执行

 数据变化时执行异步操作,这个时候使用watch是合适的

 
常用API指令
v-show v-if v-for v-on v-bind v-model v-slot
Vue.use
Vue.delete 删除对象属性,如果对象是响应式的,确保删除会触发视图更新。
Vue.nextTick
Vue.set设置对象的属性。如果对象是响应式的,确保属性被创建后也是响应式的,同时触发视图更新。这个方法用于避开Vue不能检测属性被添加的限制。
如果你在Vue实例化后添加(或删除)一个属性(例如在方法或生命周期钩子中),Vue是不知道它的。
使用Vue.set设置一个新的对象属性。该方法确保将属性创建为一个响应式属性,并触发视图更新。
对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。例如,对于:
Vue.set(vm.someObject, 'b', 2)
您还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:
this.$set(this.someObject,'b',2)
有时你可能需要为已有对象赋值多个新 property,比如使用 Object.assign() 或 _.extend()。但是,这样添加到对象上的新 property 不会触发更新。在这种情况下,你应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
 
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
 

Vue 组件 data 为什么必须是函数 ?

new Vue()实例中,data 可以直接是一个对象,为什么在 vue 组件中,data 必须是一个函数呢?

因为组件是可以复用的,JS 里对象是引用关系,如果组件 data 是一个对象,那么子组件中的 data 属性值会互相污染,产生副作用。

所以一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。new Vue 的实例是不会被复用的,因此不存在以上问题。

posted @ 2021-02-28 17:14  Panda的前端笔记  阅读(107)  评论(0)    收藏  举报