aurora-article icon indicating copy to clipboard operation
aurora-article copied to clipboard

Vue 学习笔记

Open starryiu opened this issue 4 years ago • 0 comments

使用 vue 一段时间了,但是并没有系统的总结过所学习的知识,所以特意新建一篇文章总结一下 vue 中比较重要的知识点,以便之后方便翻阅复习。

数据的响应式

Vue 实例被创建时,data对象所有的属性会被加入到Vue 的响应式系统中。 当data中的属性发生变化,视图也会跟着发生变化。 如果一个值,一开始不会使用,但是之后会使用,可以为这个值设置一个类型相同的初始值

data: {
  newTodoText: '',//字符串类型初始值
  visitCount: 0,//数字类型初始值
  hideCompletedTodos: false,//布尔类型初始值
  todos: [],//数组类型初始值
  obj: {}//对象类型初始值
  error: null//不存在数据的初始值
}

如果没有设置初始值,在Vue实例创建后为data添加属性,此时的属性是非响应式的 除非使用

Vue.set(vm.someObject, 'b', 2)
//or
this.$set(this.someObject,'b',2)

关于对象

对于一个对象类型,使用obj.prop = 'xxx' 新添加属性是非响应式的 如果要添加响应式的属性,可以使用this.$set或重新赋值新对象的方法

  // obj:{
  //   a:1,
  //   b:2
  // }
  //向obj种添加单个属性c
  this.$set(this.obj,'c',3)
  //向obj中添加c和d属性
  this.obj = Object.assign({},this.obj,{c:3,d:4})

关于数组

和对象不同,大多数的数组方法都会触发视图更新 如push() pop() splice() sort() 等 也有些方法不会变更原始数组,那么可以直接把整个数组替换掉

  // numbers: [ 1, 2, 3, 4, 5 ]
  this.numbers = this.numbers.filter(number => number>3)

数组依然有两种情况是非响应的

  1. 直接使用索引修改一个数组项时 this.items[indexOfItem] = newValue
  2. 修改数组长度 this.items.length = 1

对于第一种情况可以使用vm.set

  // numbers: [ 1, 2, 3, 4, 5 ]
  //无法使用索引直接修改
  //this.numbers[3] = 123456
  //应该使用
  this.$set(this.numbers,3,123456)
  // or
  this.numbers.splice(3,1,123456)

对于第二种情况则使用数组的splice

  // numbers: [ 1, 2, 3, 4, 5 ]
  //无法直接修改数组长度
  // this.numbers.length = 2
  //应该使用
  this.numbers.splice(2)

关于数组对象

如过有一个列表,要控制每个列表的显隐

第一种情况 sourceData:[ {id:1,name:'红',show:false}, {id:2,name:'黄',show:false}, {id:3,name:'蓝',show:false}, ],

元数据中就有show这个属性,此时的show为响应式的,此时没有问题。

    changeShow(show,record){
      //直接修改视图可响应
      record.show = !show
    }

第二种情况 因为数据是从后台获取,一般先给默认值sourceData:[],然后赋值

//从后台得到数据
this.handleData = [
  {id:1,name:'红'},
  {id:2,name:'黄'},
  {id:3,name:'蓝'},
]
//处理一下后台的数据
this.handleData = sourceData.map(item=>{
  item.show = false
  return item
})

此时的show属性是非响应的,id和name属性是响应的,因为show属性是后加给对象的,vue没有跟踪,解决方法也非常简单

第一种解决方法,添加对象新属性的时候重新赋予一个新的对象

this.handleData = sourceData.map(item=>{
  item = Object.assign({},item,{show:false})
  return item
})

第二个方法,使用数组的响应式方法

changeShow(show,record){
  //直接修改视图不会响应
  record.show = !show
  //官方推荐使用方法
  this.$set(
    this.handleData,
    this.handleData.findIndex(item => {
      return item.id === record.id
    }),
    Object.assign({},record,{show:!show})
  )
  //使用splice
  this.handleData.splice(
    this.handleData.findIndex(item => {
      return item.id === record.id
    }),
    1,
    Object.assign({},record,{show:!show})
  )
}

推荐使用第一种,为对象添加新的属性时,不要使用obj.prop = 'xxx',而是使用obj = Object.assign({},obj,{prop:propValue})或this.$set(obj,'propName',propValue),只有在修改对象属性时才使用obj.prop = 'xxx'。

表单输入绑定

v-model 会忽略所有表单元素的 value、checked、selected attribute 的初始值而总是将 Vue实例的数据作为数据 > 来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值。

复选框

单个复选框绑定一个布尔值

<input type="checkbox"  v-model="form.checked" value="apple">是否{{form.checked}}

多个复选框绑定一个数组

<input type="checkbox"  v-model="form.fruits" value="apple">苹果
<input type="checkbox"  v-model="form.fruits" value="banana">香蕉
<input type="checkbox"  v-model="form.fruits" value="peach">桃子

单选按钮

单选按钮绑定一个字符串

<input type="radio"  value="1" v-model="form.gender">男
<input type="radio"  value="2" v-model="form.gender">女

选择框

单选时绑定一个字符串

多选时绑定一个数组

值绑定

对于单个复选框绑定的值为布尔值,也可绑定为字符串

<input
  type="checkbox"
  v-model="toggle"
  true-value="yes"
  false-value="no"
>

也可绑定为其他的数据类型

<select v-model="selected">
  <option v-bind:value="obj">选项1</option>
</select>

关于组件

在组件中使用v-model

<input v-model="searchText">

等价于

<input
  :value="searchText"
  @input="searchText = $event.target.value"
>

运用在组件上也是如此

<custom-input
  v-model="searchText"
></custom-input>

等价于

<custom-input
  :value="searchText"
  @input="searchText = $event"
></custom-input>

所以要在子组件中接收value和触发input事件

Vue.component('custom-input',{
  props:['value'],
  template:`
    <div>
      <input :value="value" @input="$emit('input',$event.target.value)" />
    </div>
  `
})

自定义组件的 v-model

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件

如果是复选框,单选框可能需要监听不同的prop和事件,比如监听复选框的checked的prop和change的事件

Vue.component('child-component',{
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <div>
      <input
        type="checkbox"
        :checked="checked"
        @change="$emit('change', $event.target.checked)"
      >
    </div>
  `
})

动态组件

<component :is="currentComponent"></component> 


Vue.component('home-co',{
  template:`<h1>Home Page</h1>`
})
Vue.component('archive-co',{
  template:`<h1>Archive Page</h1>`
})
Vue.component('post-co',{
  template:`<h1>Post Page</h1>`
})
const app = new Vue({
  el:'#app',
  data(){
    return {
      text:'',
      currentComponent:'archive-co'
    }
  }
})

将原生事件绑定到组件

组件的某个特定的元素监听原生事件

Vue.component('base-input', {
  inheritAttrs: false,
  props: ['label', 'value'],
  computed: {
    inputListeners: function () {
      var vm = this
      return Object.assign({},
        this.$listeners,
        {
          input: function (event) {
            vm.$emit('input', event.target.value)
          }
        }
      )
    }
  },
  template: `
    <label>
      {{ label }}
      <input
        v-bind="$attrs"
        :value="value"
        v-on="inputListeners"
      >
    </label>
  `
})

.sync修饰符

<child-component :message.sync="message"></child-component>

等于

<child-component :message="message" @update:message="message = $event"></child-component>

sync相当于一个缩写,以下是一个简单的例子

Vue.component('parent-component',{
  data(){
    return{
      message:'旧消息',
    }
  },
  template:`
    <child-component :message="message" @update:message="message = $event"></child-component>
  `
})
Vue.component('child-component',{
  props:{
    message:{
      type:String,
      required:false,
      default:''
    }
  },
  template:`<div>
    子组件:{{message}}
    <button @click="$emit('update:message','新消息')">按钮</button>
  </div>`
})

Prop

传入一个对象的所有 property

数据对象

post: {
  id: 1,
  title: 'My Journey with Vue'
}

绑定数据

<blog-post v-bind="post"></blog-post>

相当于

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

单向数据流

注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。

starryiu avatar Mar 01 '21 14:03 starryiu