头图

一、vue简介
Vue.js是一款渐进式JavaScript框架。
优点:

  1. 体积小-压缩后33k
  2. 基于虚拟DOM操作,大幅度提高了页面渲染及运行效率。

    虚拟DOM-预先通过js进行计算,把最终DOM操作计算出来并优化的技术。
  3. 双向数据绑定-让DOM操作变得更简单
  4. 生态丰富,学习成本低,市面上有大量成熟稳定的基于vue的UI框架和常用组件,帮助我们实现快速开发。

二、安装与部署
1、使用<script>引入
下载vue.js文件或者使用cdn方式

<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

2、使用vue-cli脚手架工具搭建复杂vue项目

三、声明式渲染
vue.js核心是采用简洁的模板语法来声明式地将数据渲染进DOM系统。

<div id='app'>
    {{message}}
</div>
let app = new Vue({
    el: '#app',
    data: {
        message: 'Hello Vue!'
    }
})

四、Vue实例
1、通过new运算符创建一个vue实例:

let vm = new Vue({
    el: '#app',
    ...
})

2、实例的数据property:
当一个vue实例被创建时,它将data对象中的所有的property加入到vue的响应式系统中,当这些property发生改变的时候,视图将会产生响应,匹配更新为新的值。
只有在实例被创建时就已经存在于data中的属性才是响应式的

let data = {a: 1}
let vm = new Vue({
    el: '#app',
    data: data
})

data.a = 2 //直接修改data
console.log(vm.a)  //2  实例上的property也会发生改变

vm.a = 3 //更改实例property
console.log(data.a) //3   原始数据也会被更改

data.b = 1  //实例化之后,在原始数据中新添加的属性,发生更改,不会触发视图的更新

3、实例的方法
Vue实例暴露了一些有用的实例property和方法,使用前缀$与自定义property区分。

vm.$data === data // => true
vm.$el === document.getElementById('app') // => true

// $watch 是一个实例方法
vm.$watch('a', function (newValue, oldValue) {
  // 这个回调将在 `vm.a` 改变后调用
})

4、实例生命周期
每个实例被创建时都要经过一系列的初始化过程,例如需要设置数据监听,编译模板,将实例挂载到DOM并在数据变化时更新DOM等。这些过程中会运行一些函数--生命周期钩子,为用户提供在不同阶段添加自己代码的机会。

let vm = new Vue({
    el: '#app',
    data: {},
    //在实例初始化后,数据观测(data observer)和event/watcher事件配置前被调用
    beforeCreate:function(){
        console.log('beforeCreate')
    },
    //在实例创建完成后被立即调用
    //此时,实例已完成以下配置:数据观测,属性和方法的运算,watch/event事件回调。
    //但此时,挂载阶段还没开始,$el属性目前不可见。
    created:function(){
        console.log('created')
    },
    //在挂载开始之前被调用,相关的渲染函数首次被调用
    beforeMount: function(){
        console.log('beforeMount')
    },
    //el被新创建的vm.$el替换,挂载成功
    mounted:function(){
        console.log('mounted')
        //mounted不会保证所有的子组件也都一起被挂载,若希望等整个视图都渲染完毕后,可以调用vm.$nextTick()
        this.$nextTick(function(){
            //...
        })
    },
    //每次数据将要被更新时被调用
    //发生在虚拟DOM打补丁之前,可在这里更新之前访问现有的DOM,比如手动移除已添加的事件监听器等
    beforeUpdate: function(){
        console.log('beforUpdate')
    },
    //组件DOM已经更新,组件更新完毕时被调用
    updated:function(){
        console.log(updated)
        //updated不保证所有子组件都更新完毕,可使用vm.$nextTick
        this.$nextTick(function(){
            //...
        })
    },
    //实例销毁之前调用,在这一步,实例仍然完全可用
    beforeDestroy:function(){
        console.log('beforeDestroy')
    },
    //实例销毁后调用,该钩子被调用后,对应vue实例的所有指令都被解绑,所有的事件监听器被移除,所有子实例也都被销毁。
    destroyed:function(){
        console.log('destroyed')
    }
    
})

生命周期钩子函数不能使用箭头函数定义,因箭头函数没有this。

image.png
五、模板语法
vue将模板编译成虚拟DOM渲染函数,结合响应系统,Vue能够智能地计算出最少需要重新渲染多少组件,并把DOM操作的次数减到最少。
1、插值
使用Mustache语法({{}})插入文本

<div>message: {{msg}}</div>

使用若想插入html代码,使用{{}}只会将数据解释成普通文本,可以使用v-html指令

<p v-html='<span>this is span</span>'></p>

但这种方式动态渲染html非常危险,极易导致xss攻击,绝对不要对用户提供的内容使用插值。

除了能绑定简单的property键值,也能直接绑定js表达式

{{number + 1}}
{{ok? 'Yes': 'No'}}
{{msg.split('').reverse().join('')}}
...

2、指令
指令是带有v-前缀的特殊attribute,其值为单个js表达式。其职责是,当表达式的值改变时,将产生的连带影响响应式地作用于DOM。
v-if,v-bind,v-on,v-html等都属于指令

v-bind:
v-bind指令可以用于响应式地更新HTML attribute

<a v-bind:href='url'>给a绑定href属性</a>
<span v-bind:id='spanId'>绑定id</span>
<span v-bind:class='className'>绑定class</span>

v-on:
v-on用于监听DOM事件

<div v-on:click='click1'>
    <div v-on:click.stop='click2'><!--.stop修饰符,用于停止事件冒泡-->
        click me
    </div>
</div>
//...
let vm = new Vue({
   el:'#app',
   data:{},
   methods:{//methods的方法也不能用箭头函数
    click1:function{
        console.log('click1')
    },
    click2:function{
        console.log('click2')
    }
   }
})

v-bind:href和v-on:click都是参数,2.6.0新增了动态参数

<a v-bind:[attributeName]="value"> ... </a>
<a v-on:[eventName]="doSomething"> ... </a>

v-bind缩写

<!-- 完整语法 -->
<a v-bind:href="url">...</a>

<!-- 缩写 -->
<a :href="url">...</a>

<!-- 动态参数的缩写 (2.6.0+) -->
<a :[key]="url"> ... </a>

v-on缩写

<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>

<!-- 缩写 -->
<a @click="doSomething">...</a>

<!-- 动态参数的缩写 (2.6.0+) -->
<a @[event]="doSomething"> ... </a>

六、class与style绑定
绑定class:
使用v-bind:class,表达式结果的类型可以是字符串,可以是对象或数组,也可以绑定一个返回对象的计算属性。

<div id="app">
      <button @click="changeColor">切换颜色</button>
      <div class="test" :class="{active: isActive}">Hi</div>
      <div class="test" :class="isActive?'':'active'">Liane</div>
      <div class="test" :class="{active: isActive, green: isGreen}">MUA</div>
      <div class="test" :class="[isActive?'':'active', 'green']">MUA</div>
      <div class="test" :class="[{active:isActive}, 'green']">MUA</div>
      <div class="test" :class="classObject">MUA</div>
</div>
<script>
      let vm = new Vue({
        el: "#app",
        data: {
          isActive: false,
          isGreen: true,
        },
        methods: {
          changeColor: function classObject() {
            this.isActive = !this.isActive;
            this.isGreen = !this.isGreen;
          },
        },
        computed: {
            classObject:function(){
                return {
                    active: this.isActive,
                    green: this.isGreen
                }
            }
        }
      });
</script>

绑定内联样式:
v-bind:style,表达式的对象语法十分直观,CSS的属性名可以用驼峰或短横线分割来命名。
注:使用短横线格式命名时,需加''括起来

<div id="app">
      <div
        class="test"
        :style="{height: divHeight+'px',background: '#fcf', 'line-height': divHeight + 'px', fontSize: '24px'}"
      >
        Hi
      </div>
      <div class="test" :style="styleObject">Liane</div>
      <div class="test" :style="[styleObject, textStyle]">Ann</div>
</div>
<script>
      let vm = new Vue({
        el: "#app",
        data: {
          divHeight: 300,
          textStyle: {
            fontSize: "30px",
            color: "blue",
          },
        },
        computed: {
          styleObject: function () {
            return {
              height: this.divHeight + "px",
              background: "#cfc",
              "line-height": this.divHeight + "px",
              fontSize: "24px",
            };
          },
        },
      });
</script>

七、条件渲染v-if和v-show
用于条件性地渲染一块内容。

<div id="app">
      <button @click="toggleType">切换登录方式</button>
      <div v-if="loginType == 'useEmail'">
        <label>Email</label>
        <input type="text" placeholder="Enter your email address" />
      </div>
      <div v-else-if="loginType === 'usePhone'">
        <label>PhoneNumber</label>
        <input type="number" placeholder="Enter your phone number" />
      </div>
      <div v-else>
        <label>username</label>
        <input type="text" placeholder="Enter your username" />
      </div>
</div>
<script>
      let vm = new Vue({
        el: "#app",
        data: {
          typeArr: ["useEmail", "usePhone", "useUsername"],
          loginType: "useEmail",
        },
        methods: {
          toggleType: function () {
            let i = this.typeArr.indexOf(this.loginType);
            i = i === this.typeArr.length - 1 ? 0 : ++i;
            this.loginType = this.typeArr[i];
          },
        }
      });
</script>

通过以上例子,我们发现点击切换按钮,切换的仅仅是label标签里的文字和placeholder属性值,input文本框并不会被替换,因为Vue会尽可能高效地渲染元素,通常会复用已有元素而不是从头渲染。我们可以给input标签添加一个具有唯一值的key属性,切换时可让输入框也被重新渲染

//...
    <div v-if="loginType == 'useEmail'">
        <label>Email</label>
        <input type="text" placeholder="Enter your email address" key="email-input" />
      </div>
      <div v-else-if="loginType === 'usePhone'">
        <label>PhoneNumber</label>
        <input type="number" placeholder="Enter your phone number" key="phone-input" />
      </div>
      <div v-else>
        <label>username</label>
        <input type="text" placeholder="Enter your username" key="username-input" />
      </div>
//...

v-show:
与v-if用法大致一样,但v-show的元素始终会被渲染并保留在DOM中,至少简单地切换元素样式的display属性,控制元素显示或隐藏。
v-show不支持<template>元素,也不支持v-else

<div id="app">
        <div class='btn' @click='toggle'>切换</div>
        <div class="test" v-show='isShow'>Hi</div>
</div>
<script>
      let vm = new Vue({
        el: "#app",
        data: {
          isShow: false
        },
        methods: {
          toggle: function () {
            this.isShow = !this.isShow
          }
        }
      });
    </script>

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

八、列表渲染v-for
使用item in items语法,或者item of items。items是源数据,item是被迭代的数组(对象)元素的别名

<div id="app">
      <ul>
        <!--v-for渲染一个数组-->
        <li v-for="(item,index) in fruits">{{index}}-{{item}}</li>
      </ul>
      <ul>
        <!--v-for渲染一个对象-->
        <li v-for="(value,key) in user">{{key}}:{{value}}</li>
      </ul>
</div>
<script>
      let vm = new Vue({
        el: "#app",
        data: {
          fruits: ["apple", "orange", "peach", "banana"],
          user: {
            name: "Liane",
            age: 18,
            gender: "female"
          }
        }
      });
</script>

维护状态:当Vue正在更新使用v-for渲染的元素列表时,它默认使用就地更新的策略。如果数据项的顺序被改变,Vue不会移动DOM元素来匹配数据项的顺序。

九、事件绑定v-on

<div id="app">
      <div class="btn" @click="add">计数{{count}}</div>
      <div class="btn" @click="sayHi('Liane')">{{msg}}</div>
      <!--可以使用特殊变量$event作为参数,访问原始DOM事件-->
      <button class="btn" @dblclick="change('warning',$event)"></button>
      <!--但我们希望方法只用来处理数据逻辑,而不是去处理DOM,因此可以使用事件修饰符来解决这个问题-->
      <!-- 阻止单击事件继续传播 -->
      <a v-on:click.stop="doThis"></a>

      <!-- 提交事件不再重载页面 -->
      <form v-on:submit.prevent="onSubmit"></form>

      <!-- 修饰符可以串联 -->
      <a v-on:click.stop.prevent="doThat"></a>

      <!-- 只有修饰符 -->
      <form v-on:submit.prevent></form>

      <!-- 添加事件监听器时使用事件捕获模式 -->
      <!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
      <div v-on:click.capture="doThis">...</div>

      <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
      <!-- 即事件不是从内部元素触发的 -->
      <div v-on:click.self="doThat">...</div>
      
</div>
<script>
      let vm = new Vue({
        el: "#app",
        data: {
          count: 0,
          msg: "say hi"
        },
        methods: {
          add: function () {
              this.count++
          },
          sayHi:function(str){
            this.msg=`Hi,${str}`
          },
          change:function(str,event){
              event && event.preventDefault()
              alert(str)
          }
        }
      });
</script>

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。

按键修饰符:
当给DOM绑定按键事件时,可以使用按键修饰符:

<div id="app">
      <input type="text" @keyup='press($event)'>
      <!-- 只有在$event.key等于Enter时,才调用submit() -->
      <input type="text" @keyup.enter='submit' v-model='msg'>
      <!-- 也可以使用keyCode attribute触发事件,如下:当keyCode为13(Enter)时触发事件-->
      <input type="text" @keyup.13='submit'>
    </div>
    <script>
      let vm = new Vue({
        el: "#app",
        data: {
          msg: " "
        },
        methods: {
          press:function(event){
            console.log(event.key)
            console.log(event.keyCode)
          },
          submit:function(){
              console.log(`Submit ${this.msg}`)
          }
        }
      });
    </script>

vue提供了大多数按键码别名

  • .enter
  • .tab
  • .delete (捕获“删除”和“退格”键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

十、表单输入绑定

<div id="app">
      <input type="text" v-model="inputValue" />
      <span>{{inputValue}}</span>
      <textarea name="text" id="text1" v-model="textareaVal" cols="30" rows="10" ></textarea>
      <span>{{textareaVal}}</span>
      <!--单个复选框绑定到布尔值,多个复选框,绑定到同一个数组-->
      <label><input type="checkbox" name="fruits" value="apple" id="c1" v-model="checkedItems"/>apple</label>
      <label><input type="checkbox" name="fruits" value="peach" id="c2" v-model="checkedItems" />peach</label >
      <label><input type="checkbox" name="fruits" value="banana" id="c3" v-model="checkedItems" />banana</label >
      <span>{{checkedItems.join('-')}}</span>
      <label><input type="radio" value='Yes' v-model='picked'>Yes</label>
      <label><input type="radio" value='No' v-model='picked'>No</label>
      <span>{{picked}}</span>
</div>
<script>
      let vm = new Vue({
        el: "#app",
        data: {
          inputValue: "",
          textareaVal: "",
          checkedItems: [],
          picked: ''
        }
      });
</script>

选择框select绑定数据

<div id="app">
      <select name="fruits" id="s1" v-model='selected'>
      <!--若需要多选,则加上multiple属性-->
      <!--<select name="fruits" id="s1" multiple v-model='selected'>-->
          <option value="" disabled>选择爱吃的水果</option>
          <option value="apple">苹果</option>
          <option value="peach">桃</option>
          <option value="banana">香蕉</option>
      </select>
      <span>I like {{selected}}</span>
</div>
<script>
      let vm = new Vue({
        el: "#app",
        data: {
          selected:''
          //selected: [] //多选时绑定到一个数组
        },
      });
</script>

使用v-for渲染的动态选项:

<div id="app">
      <select v-model="selected">
        <option value="" disabled>请选择爱吃的水果</option>
        <option v-for="option in options" :value="option.value">
          {{option.text}}
        </option>
      </select>
      <span>selected: {{selected}}</span>
</div>
<script>
      let vm = new Vue({
        el: "#app",
        data: {
          options: [
            {
              text: "苹果",
              value: "apple"
            },
            {
              text: "桃",
              value: "peach"
            },
            {
              text: "香蕉",
              value: "banana"
            },
          ],
          selected: ""
        }
      });
</script>

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;
  • checkbox 和 radio 使用 checked property 和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

值绑定
若想把值绑定到Vue实例的一个动态property上,可以使用v-bind绑定
值绑定-checkbox

<div id="app">
        <label><input @change='checkChange' type="checkbox" value='apple' v-model='selected' true-value='yes' false-value='no'>apple</label>
        <span>selected: {{selected}}</span>
</div>
<script>
      let vm = new Vue({
        el: "#app",
        data: {
          selected: ''
        },
        methods:{
            checkChange:function(){
                //当选中是,this.selected === 'yes',未选中时this.selected==='no'
                //虽然有给input设置value为apple,但最后selected的值为yes/no
                //当this.selected的初始化为[]时,即使设置了true-value,被选中时,this.selected[0] ==='apple'
                console.log(this.selected)
            }
        }
      });
</script>

修饰符

<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">
<!--自动将用户输入值转为number类型-->
<input v-model.number="age" type="number">
<!--自动过滤用户输入的首尾空白字符-->
<input v-model.trim="msg">

十一、组件基础~~~~

<div id="app">
      <my-component title='计数器' text='添加' @clicknow='getCount'>
        <!-- span会被放如到组件中<slot>标签的位置 -->
        <span>我是一个插入到组件末尾的span</span>
      </my-component>
</div>
<script>
      Vue.component('myComponent', {
        props:[
          'title',
          'text'
        ],
        data: function(){
          return {
            count: 0
          }
        },
        methods:{
          add:function(){
            this.count++
            //可以派发一个事件到组件实例,抛出一个值
            //使用$emit(),第一个参数是事件名称,第二个值是传递参数
            this.$emit('clicknow',this.count)
          }
        },
        template: `<div>
            {{title}}
            <div class="btn" @click='add'>{{text}}</div>
            <span>{{count}}</span>
            <!--通过插槽,可以向一个组件传递内容-->
            <slot></slot>
          </div>`
      })
      let vm = new Vue({
        el: '#app',
        data: {},
        methods: {
          getCount:function(e){
            alert(e)
          }
        }
      })
</script>

Liane
16 声望2 粉丝