Vue基础

2,394 阅读1分钟

一.简介

Vue是一套用于构建用户界面的渐变式框架。

优点:高效,生态丰富

二.导入和实例化

导入

<!-- 开发环境版本,包含了有帮助的命令行警告 --> 
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>

实例化

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

三.指令

指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。

1.文本渲染指令

  • {{}}

  • v-text 文本渲染指令

  • v-html html文本渲染指令

       1.渲染Vue数据
       2.数字运算 
       3.执行js普通方法 
       4.三元运算
    
    <div class="app">
        <h1>{{msg}}</h1>
        <input type="text" v-model="msg">
        <p>{{msg}}</p>
        <p>{{5*8>20?"大":"于"}}</p>
        <p>{{msg.split("").reverse().join("")}}</p>
        <p>{{msg + "2"}}</p>
        <p>{{`123${msg}`}}</p>
    </div> 

2.条件渲染指令

  • v-if(dom操作,少量使用)

  • v-else-if

  • v-else

  • v-show(css操作,大量使用)

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

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

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

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

3.遍历指令

  • v-for

    我们可以用 v-for 指令基于一个数组来渲染一个列表。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名

<ul id="example-1">
    <li v-for="item in items" :key="item.message">
        {{ item.message }}
    </li>
</ul>

4.属性渲染指令

  • v-bind
<button v-bind:disabled="isButtonDisabled">Button</button>
<!--缩写:disabled-->

5.事件渲染指令

  • v-on
<button v-on:click="num++">Button</button>
<!--缩写@disabled-->

事件修饰符

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive
<!-- 阻止单击事件继续传播 -->
<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>

<!-- 点击事件将只会触发一次 --> 
<a v-on:click.once="doThis"></a>

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

6.表单渲染指令

  • v-model

    v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

<button v-on:click="num++">Button</button>
<!--缩写@disabled-->

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

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

修饰符

  • .lazy

    在 change 事件_之后_进行同步

  • .number

    自动将用户的输入值转为数值类型,如果这个值无法被 parseFloat() 解析,则会返回原始的值

  • .trim

    自动过滤用户输入的首尾空白字符

7.计算属性

var vm = new Vue({
    el: '#example',
    data: {     
        message: 'Hello'   
    },   
    computed: {
        // 计算属性的 getter     
        reversedMessage: function () {
        // `this` 指向 vm 实例       
        return this.message.split('').reverse().join('')
        }
    }
})

我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。

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

8.侦听属性

Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。

    el: '#demo',
    data: {
        firstName: 'Foo',
        lastName: 'Bar',
        fullName: 'Foo Bar'
    },
    watch: {
        firstName: function (val) {
            this.fullName = val + ' ' + this.lastName
        },
        lastName: function (val) {
            this.fullName = this.firstName + ' ' + val
        }
    }
})

9.自定义指令

  • 自定义指令

对DOM元素进行底层操作,分为全局的自定义指令和局部自定义指令

  • 全局自定义指令:通过Vue.directive('第一个参数是指令的名称',{第二个参数是一个对象,这个对象上有钩子函数})

  • 局部自定义指令:在组件中定义选项对象directives:{ 指令名 :{} }

  • 钩子函数:

      1.Bind:只调用一次,指令第一次绑定到元素时调用
      3.Inserted:被绑定元素插入父节点时调用
      4.Update:所在组件的 VNode 更新时调用
      5.ComponentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用
      6.Unbind:指令与元素解绑时调用
    

10.过滤管道

Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式

<!-- 在双花括号中 -->
{{ message | capitalize }}

<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>


filters: {
    capitalize: function (value) {
        if (!value) return ''
        value = value.toString()
        return value.charAt(0).toUpperCase() + value.slice(1)
    }
}

四.组件

组件是可复用的 Vue 实例

1. 组件是vue的一个重要的特点
2. 实现多人协作开发
3. 通过组件划分降低开发的难度
4. 实现复用,降低重复劳动

1.组件使用

//使用组件
//接受子组件传参
<btn :visible="true" @update:visible="visible=$event"></btn>


//定义组件
const btn = {
    template: `
    //向父元素传参
    <button @click="this.$emit("update:visible",false)">按钮</button>`
    //接受父组件传参
    props:{
        visible:{
            type:Boolean,
            default:false
           }
    }    
};

new Vue({
    el: ".app",
    //注册组件
    components: { btn }
})

2.插槽

让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于父组件===>子组件(形象的说就是挖个坑,等着组件的使用者进行填充)

1.默认插槽

父组件中:
<Category>
      <div>html结构</div>
</Category>

子组件中:
<template>
     <div>
       <!--定义插槽-->
       <slot>插槽默认内容</slot>
     </div>
</template>

2.具名插槽

父组件中:
<Category>
    <template slot='center'>
      <div>html结构1</div>
    </template>
    <template v-slot:footer>
       <div>html结构2</div>
    </template>
</Category>

子组件中:
<template>
  <div>
    <slot name='center'>插槽默认内容</slot>
    <slot name='footer'>插槽默认内容</slot>
  </div>
</template>

3.作用域插槽

数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的机构由App组件决定)

父组件中:
<Category>
    <template slot='scpeData'>
        <!--生成的ul列表-->
        <ul>
           <li v-for='(m,index)  in scpeData.games' :key='index'>{{m}}</li>
        </ul>
    </template>
</Category>
<Category>
    <template slot='scpeData'>
        <!--生成的ol列表-->
        <ol>
           <li v-for='(m,index)  in scpeData.games' :key='index'>{{m}}</li>
        </ol>
    </template>
</Category>

子组件中:
<template>
  <div>
    <slot :games='games'>插槽默认内容</slot>
  </div>
</template>
<script>
export default {
   name:'CategoryC',
   props:['title'],
   data(){
     return {
        games:['火锅','烧烤','小龙虾','牛排'],
    }
}
}
</script>

五.动画

1.动画使用

Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡

  • 条件渲染 (使用 v-if)
  • 条件展示 (使用 v-show)
  • 动态组件
  • 组件根节点
<transition> 
    <h3 v-if="bool">111</h3> 
</transition>

  1. v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
  2. v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
  3. v-enter-to2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
  4. v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
  5. v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
  6. v-leave-to2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。

如果需要设置多个标签动画,需要给transition添加属性name,在设置动画效果时,就可以单独设置这个transition的入场和出场,只需要把v-前缀改成name值前缀即可 如: .v-enter 改成 .yu-enter

2.动画列表

transition组件的子标签只能有一个,不能写列表,而transition-group可以写多个子标签。transition-group默认会被渲染成span标签,使用tag属性可指定渲染的标签类型。

<transition-group tag="ul"> 
    <li v-for="item,i in list" :key="item">项目{{item}}</li> 
</transition-group>

transition-group组件中的元素要求必须设置key属性,key属性有两个要求:

1.必选性,key必须设置,不设置会报错
2.不变性,key的值一旦设置,不能发生变化,所以在此例中key值不能设置为索引,因为数组从前删除元素时数组的索引会发生变化,造成动画显示异常
3.key不要求唯一性,即使key值有重复,也可以正常执行

3.位移动画

如果 transition-group中的列表长度不变,不涉及显示隐藏和创建销毁,就不能设置入场出场动画。此时只设计列表元素位置的更新,使用v-move设置位移动画即可(在css中设置v-move类即可)

.v-move {
    transition: transform 1s;
}

踩坑

  • 修改数组中的对象

vue进行开发的过程中,可能会遇到一种情况:当生成vue实例后,当再次给数据赋值时,有时候并不会自动更新到视图上去;
Vue文档有这么一句话:如果在实例创建之后添加新的属性到实例上,它不会触发视图更新.

// 数组:第一个参数是要修改的数组, 第二个值是修改的下标或字段,第三个是要修改成什么值
// 对象:第一个参数是要修改的对象, 第二个值是修改属性字段,第三个是要修改成什么值
this.$set(this.classes,1,{id:123,name:'计应171班'});
或者
Vue.set(this.classes,1,{id:123,name:'计应171班'})
//或者通过Object.assign(target, sources)方法
this.student = Object.assign({}, this.student)

  • 对象赋值影响原对象、对象赋值后原对象值随之变化

直接用 的方式把一个对象赋值给另一个对象,会导致修改新对象时,原对象也发生变化, JavaScript 中对象的赋值是默认引用赋值的(两个对象指向相同的内存地址),所以修改另一个对象时,即修改了内存地址里的对象,其他关联对象也会改变

1. obj2=JSON.parse(JSON.stringify(obj1))
2. obj2=Object.assign({},obj1)
3. 使用递归的方式进行对象([数组])的深拷贝