Let's VUE[1]

210 阅读6分钟

简介

Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

指令

v-bind 动态的绑定数据

<div v-bind:color="color"></div>
// 简写形式
<div :color="color"></div>

v-text 更新元素的文本内容

<div v-text="content"></div>

v-html 更新元素的 innerHTML

<div v-html="content"></div>

v-cloak 隐藏未编译的 Mustache 标签直到实例准备完毕 配合样式使用

//样式
[v-cloak]{
  display: none;
}

<div id="app" v-cloak>
  {{content}}
</div>

v-once 只渲染一次

<div v-once>只渲染一次: {{content}}</div>

v-for 循环

//循环数组
<div id="app">
  <ul>
    <li v-for="book in books">{{book}}</li>
  </ul>
  <ul>
    <li v-for="(book,index) in books">{{index}} - {{book}}</li>
  </ul>
</div>

new Vue({
  el: '#app',
  data: {
    books: ['javascript','nodejs','vuejs']
  }
})

循环数组结果

//循环对象
<div id="app">
  <ul>
    <li v-for="value in user">{{value}}</li>
  </ul>
  <ul>
    <li v-for="(value,key) in user">{{key}} : {{value}}</li>
  </ul>
  <ul>
    <li v-for="(value,key,index) in user">{{index}} - {{key}} : {{value}}</li>
  </ul>
</div>

new Vue({
  el: '#app',
  data: {
    user: {
      name: 'js',
      age: 18,
      city: 'china'
    }
  }
})

循环对象结果

v-if 根据表达式的值的真假条件渲染元素和移出元素

<div v-if="true">我被渲染了</div>
<div v-if="false">我不会被渲染</div>

v-show 根据表达式的值的真假条件,切换元素的display属性

<div v-show="true">我显示了</div>
<div v-show="false">我隐藏了</div>

v-model 在表单控件或者组件上创建双向绑定

<div>
  <input v-model="message" type="text" />
</div>
<h2>{{message}}</h2>

new Vue({
  el: '#app',
  data: {
    message: 'hello vue'
  }
})

v-on 绑定事件处理函数监听 DOM 事件,简写为@

<div v-on:click="clickHandle">点击事件</div>
<div @click="clickHandle">点击事件</div>

// 需要手动传入$event事件对象
<div v-on:click="clickHandle($event,params)">点击事件</div>

//事件处理函数中的this都指向实例

new Vue({
  el: '#app',
  data: {},
  methods: {
    clickHandle(event,params){
      console.log(event)
    }
  }
})

事件修饰符

  • .stop 阻止冒泡
  • .prevent 阻止默认事件
  • .capture 捕获事件
  • .self 事件源是本身才出发
  • .once 只触发一次
  • .left 点击鼠标左键时触发
  • .right 点击鼠标右键时触发
  • .middle 点击鼠标中键时触发

按键修饰符

  • .enter
  • .tab
  • .delete
  • .es
  • .space
  • .up
  • .down
  • .left
  • .right
new Vue({
  el: '#app',
  data: {},
  methods: {
    clickA(){
      alert('我是A');
    },
    clickB(){
      alert('我是B');
    }
  }
})
//阻止冒泡
<div @click="clickA">
  我是A
  <div @click.stop="clickB">
    我是B
  </div>
</div>
//self
<div @click="clickA">
  我是A
  <div @click.self="clickB">
    我是B
  </div>
</div>
//捕获
<div @click="clickA">
  我是A
  <div @click.capture="clickB">
    我是B
  </div>
</div>
//阻止默认事件
<a @click.prevent href="http://www.juejin.com">阻止默认事件</a>
//只触发一次
<div @click.once="clickA">只触发一次</div>

选项卡实例

<style>
button.active{
  background: yellow;
}
.card{
  padding: 10px;
  width: 500px;
  height: 500px;
  border: 1px solid #ccc;
  display: none;
}
.card.active{
  display: block;
}
</style>
<div id="app">
  <div>
    <button v-for="(book,index) in books" @click="showTab(index)" :class="{active: tabIndex==index}"  type="button">{{book.name}}</button>
  </div>

  <div v-for="(book,index) in books" :class="{active: tabIndex==index}" class="card">
    <h2>{{book.name}}</h2>
    <p>{{book.info}}</p>
  </div>
</div>
new Vue({
  el: '#app',
  data: {
    books: [
      {
        name: 'javascript',
        info: 'JavaScript一种直译式脚本语言,是一种动态类型、弱类型、基于原型的语言,内置支持类型。'
      },
      {
        name: 'nodejs',
        info: 'Node.js是一个Javascript运行环境(runtime environment),发布于2009年5月,由Ryan Dahl开发,实质是对Chrome V8引擎进行了封装。'
      },
      {
        name: 'vuejs',
        info: 'Vue是一套用于构建用户界面的渐进式框架。'
      }
    ],
    tabIndex: 0
  },
  methods: {
    showTab(i){
      this.tabIndex = i;
    }
  }
})

双向数据绑定

双向数据绑定

Vue将数据对象和DOM进行绑定,彼此之间互相产生影响,数据的改变会引起DOM的改变,DOM的改变也会引起数据的变化

双向数据绑定

MVVM模式

MVVM模式

<div>
  <input v-model="message" type="text" />
</div>
<h2>{{message}}</h2>

new Vue({
  el: '#app',
  data: {
    message: 'hello vue'
  }
})

响应式原理

  • 把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项
  • Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter
  • Vue内部会对数据进行劫持操作,进而追踪依赖,在属性被访问和修改时通知变化

Object.defineProperty

  • 作用:直接在一个对象上定义一个新属性,或者修改一个对象的现有属性
  • 语法:Object.defineProperty(obj, prop, descriptor)
  • 参数:(对象,属性,属性描述符/存取器描述)
[属性描述符]

  是否可配置删除,默认false
  configurable: false

  是否可枚举,默认false
  enumerable: false

  属性值,默认undefined
  value: undefined

  是否可被重写,默认false
  writable: false

[存取器描述]

  获得属性值的方法
  getter: function(){}

  设置属性值的方法
	setter: function(){}
//添加修改对象属性
let obj = {
  a: 1,
  b: 2
}
Object.defineProperty(obj, 'a', {
  value: 3
});
Object.defineProperty(obj, 'c', {
  configurable: true,
  enumerable: true,
  value: 4,
  writable: true
});
console.log(obj) //{a: 3, b: 2, c: 4}
  • 使用defineReactive劫持数据
//劫持数据
function observer(data,cb){
  Object.keys(data).forEach( (key) => {
    defineReactive(data,key,data[key],cb)
  })
}
//转换getter,setter
function defineReactive(obj,key,value,cb){
  Object.defineProperty(obj,key,{
    get(){
      return value;
    },
    set(newValue){
      value = newValue;
      cb(newValue);
    }
  })	
}
  • 使用Proxy劫持数据
function observer(data,cb){
  return new Proxy(data,{
    get(target,attr){
      return target[attr];
    },
    set(target,attr,newValue){
      target[attr] = newValue;
      cb(newValue);
    }
  });
}
<button id="btn" type="button">改变内容</button>
<div id="content"></div>

let content = document.querySelector('#content');
let btn = document.querySelector('#btn');
let data = {
  text: 'Vue是一套用于构建用户界面的渐进式框架。'
}
observer(data,function(newVal){
  content.innerHTML = newVal;
})
content.innerHTML = data.text;
btn.onclick = function(){
  data.text = '内容改变了';
}

选项

data

Vue 实例的数据对象

methods

事件处理器

computed

  • 计算属性定义在computed中,它不是方法,属性的值是函数的返回值。
  • 把对处理数据的逻辑抽离在计算属性中,使得模板更加轻量易读
  • 计算属性的值会被缓存,并根据依赖的数据变化而重新计算
//默认设置的get函数
new Vue({
  el: '#app',
  data: {
    a: 1
  },
  computed: {
    b(){
      return 2;
    }
  }
})
//设置get,set函数
new Vue({
  el: '#app',
  data: {
    a: 1
  },
  computed: {
    b: {
      get(){
        return 2;
      },
      set(newVal){
        this.b = newVal;
      }
    }
  }
})

watch

watch观察 Vue 实例上的数据变动,键是需要观察的表达式,值是对应回调函数

let vm = new Vue({
  el: '#app',
  data: {
    html: 'html',
    js: {
      javascript: 'javascript',
      nodejs: 'nodejs',
      vuejs: 'vuejs'
    }
  },
  watch: {
    html(newVal,oldVal){
      console.log(newVal,oldVal) // -> 改变html html
    }
  }
})
vm.html = '改变html';
//深度监控
let vm = new Vue({
  el: '#app',
  data: {
    html: 'html',
    js: {
      javascript: 'javascript',
      nodejs: 'nodejs',
      vuejs: 'vuejs'
    }
  },
  watch: {
    'js.vuejs':{
      handler(newVal,oldVal){
        console.log(newVal,oldVal) // -> 改变vuejs vuejs
      },
      deep: true
    }
  }
})
vm.js.vuejs = '改变vuejs';
//侦听开始之后被立即调用
let vm = new Vue({
  el: '#app',
  data: {
    html: 'html',
    js: {
      javascript: 'javascript',
      nodejs: 'nodejs',
      vuejs: 'vuejs'
    }
  },
  watch: {
    html:{
      handler(newVal,oldVal){
        console.log(newVal,oldVal) // -> html undefined
      },
      immediate: true
    }
  }
})

响应的数据变化

  • Vue.set( target, key, value )
  • vm.$set( target, key, value )
<div id="app">
  <button @click="addCity1" type="button">Vue添加城市属性</button>
  <button @click="addCity2" type="button">vm添加城市属性</button>
  <ul>
    <li v-for="(value,key) in user">{{key}} : {{value}}</li>
  </ul>
</div>

new Vue({
  el: '#app',
  data: {
    user: {
      name: 'js',
      age: 18
    }
  },
  methods: {
    addCity1(){
      Vue.set( this.user, 'city', 'china' )
    },
    addCity2(){
      this.$set( this.user, 'city', 'china' )
    }
  }
})