Vue学习笔记 - 常用特性

213 阅读7分钟

表单操作

基础用法

文本

<input v-model="message" placeholder="edit me"> 
<p>Message is: {{ message }}</p>

多行文本

<span>Multiline message is:</span> 
<p style="white-space: pre-line;">{{ message }}</p> 
<br> 
<textarea v-model="message" placeholder="add multiple lines"></textarea>

image.png

注意:

在文本区域插值 <textarea>{{text}}</textarea> 并不会生效,应用 v-model 来代替。


复选框

  • 单个复选框

单个复选框,绑定到布尔值:

<input type="checkbox" id="checkbox" v-model="checked"> 
<label for="checkbox">{{ checked }}</label>

image.png


  • 多个复选框

多个复选框,绑定到同一个数组:

html:

<input type="checkbox" id="jack" value="Jack" v-model="checkedNames"> 
<label for="jack">Jack</label> 
<input type="checkbox" id="john" value="John" v-model="checkedNames"> 
<label for="john">John</label> 
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames"> 
<label for="mike">Mike</label> 
<br> 
<span>Checked names: {{ checkedNames }}</span>

js:

new Vue({
    el: '...',
    data: { 
        checkedNames: [] 
    } 
})

image.png


单选按钮

html:

<div id="example-4"> 
    <input type="radio" id="one" value="One" v-model="picked"> 
    <label for="one">One</label> 
    <br> 
    <input type="radio" id="two" value="Two" v-model="picked"> 
    <label for="two">Two</label> 
    <br> 
    <span>Picked: {{ picked }}</span> 
</div>

js:

new Vue({ 
    el: '#example-4', 
    data: { 
        picked: '' 
    } 
})

image.png


下拉选择框

  • 单选选择框:

html:

<div id="example-5"> 
    <select v-model="selected"> 
        <option disabled value="">请选择</option> 
        <option>A</option> 
        <option>B</option> 
        <option>C</option> 
    </select> 
    <span>Selected: {{ selected }}</span> 
</div>

js:

new Vue({ 
    el: '...',
    data: { 
        selected: '' 
    } 
})

image.png

注意:

如果 v-model 表达式的初始值未能匹配任何选项,<select> 元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像上面这样提供一个值为空的禁用选项。


  • 多选选择框:

绑定到一个数组

html:

<div id="example-6"> 
    <select v-model="selected" multiple style="width: 50px;"> 
        <option>A</option> 
        <option>B</option> 
        <option>C</option> 
    </select> 
    <br> 
    <span>Selected: {{ selected }}</span> 
</div>

js:

new Vue({ 
    el: '#example-6', 
    data: { 
        selected: [] 
    } 
})

image.png


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

html:

<select v-model="selected">
    <option v-for="option in options" v-bind:value="option.value"> 
        {{ option.text }} 
    </option>
</select> 
<span>Selected: {{ selected }}</span>

js:

new Vue({ 
    el: '...', 
    data: { 
        selected: 'A', 
        options: [ 
            { text: 'One', value: 'A' }, 
            { text: 'Two', value: 'B' }, 
            { text: 'Three', value: 'C' } ] 
    } 
})

image.png


表单操作值的绑定

对于单选按钮,复选框及选择框的选项,v-model 绑定的值通常是静态字符串 (对于复选框也可以是布尔值):

<!-- 当选中时,`picked` 为字符串 "a" --> 
<input type="radio" v-model="picked" value="a"> 

<!-- `toggle` 为 true 或 false --> 
<input type="checkbox" v-model="toggle"> 

<!-- 当选中第一个选项时,`selected` 为字符串 "abc" --> 
<select v-model="selected"> 
    <option value="abc">ABC</option> 
</select>

但是有时我们可能想把值绑定到 Vue 实例的一个动态 property 上,这时可以用 v-bind 实现,并且这个 property 的值可以不是字符串。


复选框

html:

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

js:

// 当选中时 
vm.toggle === 'yes' 
// 当没有选中时 
vm.toggle === 'no'

单选按钮

html:

<input type="radio" v-model="pick" v-bind:value="a">

js:

// 当选中时 
vm.pick === vm.a

选择框的选项

html:

<select v-model="selected"> 
    <!-- 内联对象字面量 --> 
    <option v-bind:value="{ number: 123 }">123</option> 
</select>

js:

    // 当选中时 
    typeof vm.selected // => 'object' 
    vm.selected.number // => 123

修饰符

.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">

自定义指令

内置指令不满足需求时,自定义

基本用法

全局自定义指令: Vue.directive

局部自定义指令:组件中也接受一个 directives 的选项

示例: 输入框聚焦

html:

<div id='app'>
    <input type="text">
    <input type="text" v-focus>
    <!-- 或 -->
    <input type="text" v-focuslocal>
</div>

vue:

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {//指令名
    inserted: function(el) {
        //el表示指令所绑定的元素
        el.focus();// 聚焦元素
    }
})
var vm = new Vue({
    el: '#app',
    data() {
        return {
        }
    },
    methods: {
        handle: function(){
        }
    },
    directives: {
        focuslocal: {//名字都得是小写
            // 局部自定义指令 `v-focuslocal`
            inserted: function (el) {
            el.focus()
            }
        }
    }
})

参数

  • el:指令所绑定的元素,可以用来直接操作 DOM。

  • binding:一个对象,包含以下 property:

    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }
  • vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。

  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

注意

除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。

示例:

html:

<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>

js:

Vue.directive('demo', { 
    bind: function (el, binding, vnode) { 
    var s = JSON.stringify 
    el.innerHTML = 
        'name: ' + s(binding.name) + '<br>' + 
        'value: ' + s(binding.value) + '<br>' + 
        'expression: ' + s(binding.expression) + '<br>' + 
        'argument: ' + s(binding.arg) + '<br>' + 
        'modifiers: ' + s(binding.modifiers) + '<br>' + 
        'vnode keys: ' + Object.keys(vnode).join(', ')
    } 
})

new Vue({ 
    el: '#hook-arguments-example', 
    data: { 
        message: 'hello!' 
    } 
})

image.png


计算属性

为啥需要计算属性

抽取模板复杂的计算

<div id='app'>
    <div>{{msg}}</div>
    <div>{{msg.split('').reverse().join('')}}</div>
</div>

表达式的计算逻辑可能很复杂,使用计算属性可以使模板内容更加简洁。


基本用法

示例:

<div id='app'>
    <div>{{msg}}</div>
    <div>{{msg.split('').reverse().join('')}}</div>
    <div>{{reverseString}}</div>
</div>
var vm = new Vue({
    el: '#app',
    data() {
        return {
            msg: 'Hello'
        }
    },
    computed: {
        reverseString: function(){
            return this.msg.split('').reverse().join('')
        }
    }
})

计算属性就是基于 data 中的数据来进行处理的data 中的数据改变,计算属性也跟着变。


计算属性和方法的区别

  • 计算属性是基于依赖( data 中的数据)进行缓存。
  • 方法不存在缓存。

计算属性计算完一次后,只在相关响应式依赖( data 中的数据)发生改变时它们才会重新求值。

相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。

为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。

示例:

<div id='app'>
    <div>{{reverseString}}</div>
    <div>{{reverseString}}</div>
    <div>{{reverseMessage()}}</div>
    <div>{{reverseMessage()}}</div>
</div>
var vm = new Vue({
    el: '#app',
    data() {
        return {
            msg: 'Hello'
        }
    },
    methods:{
        reverseMessage: function(){
            console.log('methods');
            return this.msg.split('').reverse().join('')
        }
    },
    computed: {
        reverseString: function(){
            console.log('computed');
            return this.msg.split('').reverse().join('')
        }
    }
})

image.png

computed 只计算了一次,methods 每次都重新计算了。


侦听器

什么是侦听器

侦听器 watch 用来监听数据,数据一旦发生变化就通知侦听器所绑定的方法。

常用于当需要在数据变化时执行异步或开销较大(执行慢)的操作时。


基本用法

监听的属性名称要和 watch 绑定方法的名称一致

示例:

<div id='app'>
    <div>
        <span>用户名:</span>
        <span>
            <!-- .lazy 失去焦点时才会触发 -->
            <input type="text" v-model.lazy="uname"> 
        </span>
        <span>{{tips}}</span>
    </div>
</div>
var vm = new Vue({
    el: '#app',
    data() {
        return {
            uname: '',
            tips: ''
        }
    },
    methods:{
        checkName: function(uname){
            //使用定时器模拟接口调用
            let that = this;//setTimeout里面的this是Window对象
            setTimeout(function(){
                if(uname === 'admin'){
                    that.tips = '用户名已经存在,请更换一个'
                }else {
                    that.tips = '用户名可以使用'
                }
            }, 2000);
        }
    },
    watch: {
        uname: function(val){//和监听的属性名一致
            this.checkName(val);
            this.tips = '正在验证。。。。'

        }
    }
})

过滤器

干啥的

可被用于一些常见的文本格式化

过滤器可以用在两个地方:双花括号插值和 v-bind 表达式

<!-- 在双花括号中 --> 
{{ message | capitalize }} 
<!-- 在 `v-bind` 中 --> 
<div v-bind:id="rawId | formatId"></div>

基础用法

示例:

<div id='app'>
    <input type="text" v-model="msg"> 
    <div>{{msg | upper}}</div>
    <!-- 过滤器可以串联 -->
    <div>{{msg | upper | lower}}</div>
    <div>{{msg | upper | lower | upperlocal}}</div>
</div>
// 定义全局过滤器
Vue.filter('upper', function(val){
    return val.charAt(0).toUpperCase() + val.slice(1);
});
// 定义全局过滤器
Vue.filter('lower', function(val){
    return val.charAt(0).toLowerCase() + val.slice(1);
});

var vm = new Vue({
    el: '#app',
    data() {
        return {
            msg: ''
        }
    },
    filters: {// 定义局部过滤器
        upperlocal: function(val){
            return val.charAt(0).toUpperCase() + val.slice(1);
        }
    }
})


生命周期

啥是生命周期

vue实例有一个完整的生命周期,生命周期也就是指一个实例从开始创建到销毁的这个过程

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

注意:

不要在选项 property 或回调上使用箭头函数,比如 created: () => console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。因为箭头函数并没有 thisthis 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。

主要阶段

  • 挂载(初始化相关属性)
  1. beforeCreate
  2. created
  3. beforeMount
  4. mounted
  • 更新
  1. beforeUpdate
  2. updated
  • 销毁
  1. beforeDestroy
  2. destroyed

对生命周期的理解

  • beforeCreate() 在实例创建之间执行,数据未加载状态
  • created() 在实例创建、数据加载后,能初始化数据,dom渲染之前执行
  • beforeMount() 虚拟dom已创建完成,在数据渲染前最后一次更改数据
  • mounted() 页面、数据渲染完成,真实dom挂载完成
  • beforeUpadate() 重新渲染之前触发
  • updated() 数据已经更改完成,dom 也重新 render 完成,更改数据会陷入死循环
  • beforeDestory() 和 destoryed() 前者是销毁前执行(实例仍然完全可用),后者则是销毁后执行

image.png

各个周期适用场景

image.png

image.png

示例 :

  • beforecreate : 加loading事件
  • created :在这结束loading,还做一些初始化,实现函数自执行
  • mounted : 在这发起后端请求,拿回数据,配合路由钩子做一些事情
  • beforeDestory: 确认删除XX吗? destoryed :当前组件已被删除,清空相关内容

created和mounted的区别?

  • beforecreated:el 和 data 并未初始化
  • created: 完成了 data 数据的初始化,el没有 渲染前调用,初始化某些属性值,再渲染
  • beforeMount:完成了 el 和 data 初始化
  • mounted :完成挂载 渲染后再调用,初始化页面完成后,再对DOM节点进行操作