Vue基础入门

55 阅读9分钟

Vue基础入门

什么是vue?

Vue是“渐进式框架”:vue.min.js只包含了vue最核心的内容「例如:options api、数据处理、template模板视图的解析等操作」;真实项目中我们还会根据需求,导入

    • vuex 实现公共状态管理
    • vue-router 实现SPA(single page application)单页面应用
    • element-ui/antdv/iview/vant/cube... 基于这些UI组件库快速创建项目
    • axios 实现数据通信
    • @vue/cli 基于vue的脚手架创建工程化项目
    • ...

Vue是基于MVVM模式构建的框架,它本身实现了viewModel层去监听数据/视图的变化,从而去渲染视图/修改数据,所以我们学习vue主要考虑两条主线

  • Model数据层  + View视图层   最后学习vue的原理,把两条主线关联在一起
  • ==MVVM:(Model-View-Viewmodel):数据-视图-视图模型==
    • M(Model):数据层->后台,对于前段来说就是后端提供的一个API接口
    • V(View):视图层->浏览器
    • VM(Viewmodel):视图模型层-> 一个同步View和Model的对象

ViewModel通过双向数据绑定把View层和Model层连接了起来,而View和Model之间的同步工作完全是自动的,无需人为干涉,因此开发者只需要关注业务逻辑,不需要手动操作DOM,不需要关注数据状态的同步问题,复杂的数据状态维护完全由MVVM来统一管理。

+ Model数据层

如何判断数据是否为响应式?

响应式数据 new Vue的时候,在data中指定的数据,vue默认就会对其做劫持处理,所以这些数据是响应式的;

    • 在vue开发中,我们把需要的数据一般都写在data中(哪怕现在用不着,我们也先在data中初始化一下),目的是让这些数据变为响应式数据
  • 而且对data中所有层级做深层次监听劫持
  • 特殊 :对于数据来讲,数组本身会做劫持;但是数据中的每一个索引项并没有做劫持;这样是不好的,vue为了解决这个问题,把数组中的7个方法(push/pop/shift/unshift/splice/sort/reverse)进行了重写,后期我们操作这个7个方法,不仅可以修改数据中某一项的内容,而且也会触发视图的重新渲染;
     vm.arr=100  这是修改arr的值,触发重新渲染
     vm.arr[0]=100  这是修改arr堆内存中的信息,不属于修改arr本身,不会触发重新渲染
     vm.arr.splice(0, 1, 100); 基于重写的7个方法操作数据每一项,会重新渲染「推荐」

非响应式数据: 自己直接挂在到实例上的是非响应式的数据;

  • Vue.prototype
    • vm.$forceUpdate() 强制让视图重新渲染
    • vm.set([object],[key],[value])针对于data中的某个对象,开始没有初始化某个属性,后期才新加的(这样这个属性默认是非响应式的,改值视图也不会重新渲染)set([object],[key],[value]) 针对于data中的某个对象,开始没有初始化某个属性,后期才新加的(这样这个属性默认是非响应式的,改值视图也不会重新渲染);set可以在后续把对象中的这个属性,设置为响应式的;

响应式数据 VS 非响应式数据

    • 都可以修改值
    • 响应式数据在值修改之后,会通知视图重新渲染;因为其基于Object.defineProperty对其做了get/set劫持;当我们需改响应式数据值,会触发set函数,在set函数中一方面把值修改,一方面会通知视图重新渲染!!
  • 后期在vue的项目中,我们只需要展开实例,看哪些数据做了get/set,做了劫持的数据就是响应式的!!

vm使用规范

vm的optionsAPI对象中的属性

let vm = new Vue({
    //指定视图,将html中的视图元素与vm绑定
    el: "#app",
    //构建数据模型,挂载需要在视图中渲染的数据,这里的数据都是==响应式数据==
    data: {
        msg: '<a href="">你好,世界</a>',
        num: 8,
        arr: [{
            id: 1,
            title: "今天天气很好"
        }, {
            id: 2,
            title: "很适合学习"
        }]
 
    },
    /* methods编写普通方法 */
    // 1.这样写方法,不论方法咋执行的,也不论在哪执行的,方法中的this是vue的实例「vue内部做了处理」;所以我们不会把其设置为箭头函数(this->window)!!
    // 2.methods编写的方法会直接挂载到实例上(不做get/set劫持),所以可以直接在视图中使用
    methods: {
        hadle(e) {
            console.log('handle', ev.keyCode);
        },
        submit() {
            console.log('submit');
        },
        fn() {
            console.log("fn");
        }
    },
    // 计算属性:依赖于某些数据值,计算出新的值 【多个值变化,影响到一个结果值变化】
        **计算**:以函数的形式定义 - **属性**:以属性的形式使用
    //【==缓存效果==:依赖的值没变,会用之前计算的值,只有依赖的值变了,才会重新计算】
    // - ==这里的this也指向vm==
       computed:{
           fun1(){}
           fun1(){}
       },
    // ==watch:侦听属性【一个值变化,影响多个结果值变换】==
    - **侦听**:watch中的定义的属性名就是我们监控的vm里的私有属性名,当这个私有属性发生变化是,会自动执行watch中对应方法:可以看作是`computed`和`methods`的结合体
      **特点**:`watch能够监控路由`,如果不需要监控路由,==我们尽可能的用computed的set方法来代替watch==,原因是computed有缓存
-     **注意**:我们监控的对象必须vm里已经存在该私有属性
 
})

computed、watch、methods的区别

  • computed是属性调用,而methods是函数调用
    • computed带有缓存功能,而watch没有
    • watch可以监控对象,而computed、methods不能

computed用法

computed是依赖已有的变量来计算一个目标变量,大多情况下都是多个变量凑在一起,计算出一个变量,并且computed具有缓存机制,依赖值不变的情况下,其会直接读取缓存进行复用.computed不能进行异步操作 多对一

     <div>{{funllname}}</div>
        <script>
            let vm=new Vue({
                computed:{
                    // 以函数的形式定义
                    fullname(){
                        return this.first+"-"+this.last;
                    }
                }   
            })
对象定义方式**:computed中的计算属性本身其实存在两个方法,只是默认获取,`get()和set`方法,原理:使用了Object.defineProperty()中的get/set劫持
	computed:{
                fullname:{
                    // 对fullname属性获取时拦截,也是函数定义形式使用的默认方法
                   get(){
                       //实现多个值变换,改变一个结果值
                    return this.first+"-"+this.last;
                   },
                    //对fullname属性赋值时拦截     
                   set(val){//val是想赋给fullname的值,也可以说是心值
                    let arr=val.split("-");
                    //实现一个值变化,改变多个结果只
                    this.first=arr[0];
                    this.last=arr[1];
                   }
                }
            } 
watch的用法

监听,某一个变量的变化,并执行响应的回调函数,通常是一个变量的变化决定对个变量的变化,watch可以进行异步操作 一对多

       watch:{
                    //fullname就是我们监控的vm实例中的私有属性,存在两个值
                    //函数式写法
                    "obj"(newVal,oldVal){
                        let arr=newVal.split("-");
                        //实现一个值变化,改变多个结果值
                        this.first=arr[0];
                        this.last=arr[1];
                    },
                    // 对象式写法
                    "obj":{
                        // 这是函数式写法默认用的方法
                        // handler(newVal,oldVal){...}
                        //设置对obj的属性是否进行深侦听
                        deep:true,
                        // 设置对obj的属性是否在第一次渲染页面时立即侦听一次
                        immediate:true
                    }
                }
vm实例的方法
  • vm.$forceUpdate():强制让vm视图渲染
    • vm.$set([obj],[key],[value]):将obj对象中[key]属性的值改为[value],并且把[key]属性转换为响应式数据
    • 针对于data中的某个对象,开始没有初始化某个属性,后期才新加的(这样的属性默认是非响应式的:改值视图不会重新渲染):$set可以在后续把对象只能够的这个属性,设置为响应式的。

指定视图的方法4种

 let vm=new Vue({
    	//方案一:指定页面中存在的DOM元素作为视图
    	el:`#box`,
    	//方案二:创建视图
           template:`<div>
            //最后把数据渲染在这个视图中
        </div>`,
        //方案四:render渲染视图
            render:h=>{
           ...
        		}
    })
    	//方案三:挂载视图
       vm.$mount(('#app'));

View视图层

Vue构建视图是基于“template”模板语法:template中定义了很多vue内置的语法规范,这些规范不能被浏览器直接识别,需要基于vue进行渲染「流程:根据数据和template视图,把其识别为一个虚拟DOM对象(vnode) -> DOM-DIFF -> 把vnode虚拟DOM变为真实DOM」

思维导图

vue内部指令

vue修饰符

普通指令:v-xxx

1.渲染数据的属性 v-text/v-html:[string]:把数据渲染到指定的容器中

    • <h2 v-html="msg"></h2>:把msg数据渲染到h2标签中,如果数据内容是html字符串【带标签】,会自动进行识别渲染
    • <h2 v-text="msg"></h2>:把msg数据渲染到h2标签中,如果数据内容是html字符串【带标签】,不会进行识别渲染,与{{}}小胡子语法相同
        <h2 v-text="msg"></h2>//带标签
        <h2 v-html="msg"></h2>//不带标签
        <h2>{{msg}}</h2>//小胡子语法{{}}与v-text相同

2.v-show:[boolen] 控制元素的显示隐藏{原理:控制display='none/block'};所以这种方式,不论结果是TRUE还是FALSE,元素都渲染出来了,只是display值不同而已!!

  <h2 v-show="num>15">{{msg}}</h2>

3.v-if/v-else-if/v-else

v-if:[boolean]`:控制元素的显示隐藏,但是和v-show不一样,如果值是false,元素是不进行渲染的(页面中没有这个元素),只有结果是true,元素才会渲染!!

- ==两者应该分场景使用:==

    • 如果元素切换显示隐藏频率不高的情况下,使用v-if性能更好
    • 如果元素切换显示隐藏频率比较高的情况下,v-if会使元素一直销毁和重新渲染,此时使用v-show更好
  • v-else-if:[boolean]/v-else:与v-if联合使用,如果三个组合用,用的标签必须挨着,否则无法生效

    • v-else-if:[boolean]:if条件不成立则判断这个条件是否成立
    • v-else: if或else-if条件不成立,则判断这个条件
        <button v-if='num>10'>红色</button>
        <button v-else-if="num<10">蓝色</button>
        <button v-else="num<20">绿色</button>

4. v-for

v-for="(item,index) in xxx" :key="index"`:循环创建元素,实现内容绑定

  • 想让哪个元素创建多个,就给哪个元素设置v-for
    • 循环的元素要设置唯一值key【最好不要使用索引作为key?
    • xxx可以是数字、字符串、数组类型
    
    :xxx是数字,先隐式转换为数组`[1,2,3,4,5]`,再进行逐项循环渲染
       <ul>
             <li v-for="(item,index) in 5">
                {{item}}--{{index}}
            </li>
      xxx是字符串,先隐式转为数组`[s,t,r]`,再逐项循环渲染
             <li v-for="(item,index) in 'str'">
                {{item}}--{{index}}
            </li>
      xxx是数组类型,直接逐项循环渲染
             <li v-for="(item,index) in arr" :k='item.id'>
                {{item.title}}
            </li>
        </ul>

为什么在v-for中必须有:key="xxx"属性,并且不能用index?

  • 当在组件中使用 v-for 时,key 现在是必须的
  • 当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。
  • 如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。

比如我们用多选框选中了数组中的第二个数据:

    • 如果没有存key值:则浏览器默认认为index=2的数据被选中了,当我们在数组最前面插入数据项,则后面的数据位置都发生了改变,而系统仍然认为index=2的数据项被选中了,这时正确被选中的应该是第三项猜对
    • 如果有:key值,但是:key="index":浏览器回去找:key=2的数据选中,但是当在最前面插入数据项时,后面所有数据的key值,都会跟着改变,结果仍然是不正确的

所以我们为了保证Vue能够跟踪每个节点的身份,从而重用和重新排序现有的元素,==我们应该给每一项提供一个唯一的key属性,且这个key属性不会被改变。

.template与div用v-for的区别

v-for的优先级高于v-if那么就会出现一个问题

  <div v-for="(item,index) in arr" v-if=" item>10">{{item}}</div>
        以上标签在渲染时,会首先通过`v-for`循环创建3个div标签,再通过`v-if`判断是否符合条件,不符合条件的再被销毁,但这里有item=10的标签并不需要渲染创建再销毁,这样是消耗性能的
//-----------------------------解决方法-----------------------------------------
- template标签:==template标签不会被渲染到页面上,
 template里面的div在渲染时已经知道了item值,所以不符合规则的div不会再无用的生成再销毁一次,优化了性能
      <template v-for="(item,index) in arr">
            <div v-if="item>10">{{item}}</div>
        </template>

5.v-on

v-on:[事件]="要执行的方法":缩写为`@事件="要执行的方法"

原理 基于DOM2事件绑定实现的 addEventLinstener冒泡事件==【好处是,后期获取到这个DOM元素对象,再做事件绑定,也不会和@click绑定的方法冲突】

*以下写法都是点击的时候才会把handle执行

    •      @click="handle"=>handle(ev){...}
    • @click="handle(10,20)"=>handle(10,20){...}:也不是把handle立即执行,而是点击才执行,只不过点击的时候,会把10/20传递给handle

原生中

button.addEventListener('click',handle(10,20)) 不等点击  handle就已经执行了

button.addEventListener('click',handle.bind(null,10,20));  这样才是基于bind预先把handle中的this和值处理好,点击的时候,才会执行handle

    • @click="handle(10,20,$event)"=>handle(10,20,ev){...}:视图中出现的$event代表是事件对象
        <button @click="handle">按钮</button>
        <button @click="handle(10,20)">按钮</button>
        <button @click="handle(10,20,$event)">按钮</button>

点击事件的修饰符

  • .stop @click.stop:阻止事件的冒泡传播=>同理于:e.stopPropergation()`
  • .prevent @click.prevent:阻止事件的默认行为=>同理于:e.preventDefault()
  • .capture @click.capture:将事件变为==捕获事件===>同理于:dom.addEventListener([event],[fun],true)`,[默认都是在冒泡阶段触发]
  • .self @click.self:只有点击的事件源就是当前元素本身,绑定的方法才会执行{但是没有阻止冒泡传播}=>如同在函数执行之前做了校验:if(e.target==e)=true时,才会执行
  • **.once** @click.once:只触发执行一次,然后把事件绑定的方法一吃掉=>相当于执行一次后会默认执行dom.removeEventListener([event],fn)
    • ..passive @click.passive`:当我们在监听元素滚动事件的时候,会一直触发onscroll事件,在pc端没有啥问题,但是在移动端会让网页变卡,因此我们使用这个修饰符的时候想到相当于给onscroll事件整了一个lazy修饰符

键盘事件的修饰符

@keydown/@keyup/@keypress

  • @keydown.13:直接使用键码也可以,【所有的键码】
    • @keydown.enter:只有按下enter键时会触发事件
    • @keydown.tab:按下tab键时会触发
    • .delete/esc/space/up/down/left/right
    • ctrl/alt/shift/meta
  • left/right/middle 鼠标左中右按键

自定义按键修饰符

- `Vue.config.keyCodes.a=65;`
- `@keydown.a='xxx'`
- `@keydown.65='xxx'`

组合按键

@keydown.ctrl.65="xxx"`:按下ctrl+a就会触发

  • 默认情况下,按下的按键只要包含组合键(==哪怕还按了其他键)==也会触发,但是我们可以基于.exact修饰符,设置精准匹配(只有按下规定的键,其他键不按,才会触发)

  • @keydown.ctrl.65.exact:只有按下ctrl+a才会触发

  • @click.exact:只有只点击了单击按键时触发

6. v-bind

给元素的attribute动态绑定值

v-bind:xxx="xxx":简写为:xxx="xxx"给元素的attribute动态绑定值

    • 但凡属性值是一个变量的值或者是一个表达式计算的结果,都需要给属性v-bind一下
    • 基于属性给子组件传递信息的时候,如果想让属性值是字符串以外的类型,也需要v-bind一下

动态绑定class

  • 对象语法:class="{box:true,active:true/false}":active是class样式类名,它的值true/false决定元素是否拥有这个样式类名
  • - 数组语法:class="['box',num>10?'active':'']":box是肯定有的类名,根据num条件决定是否有active类名

动态绑定style:

样式需要用驼峰命名法

  • 对象语法::style="{color:'red',fontSize:num>10?'20px':'12px'}":元素颜色静态为红色,字体大小根据num决定
    • 数组语法::style="[color,fontSize]":每个数组中的数据项都是一个对象,存在样式名和值

修饰符

..came l``:sup-name.camel:把设定的sup-name自动转为camel规范=>supName`

.prop :supName.prop

  • 默认情况下,给元素设置的属性都会呈现在元素的结构上,我们可以基

getAttribute/setAttribute来设置获取;

  • 但是设置了prop修饰符,设置的自定义属性不在结构上,不再html结构中显示,而是放到了DOM对象的堆内存中
  • 给元素设置自定义属性有两种方式

    • 方式一:写在结构上,<div index="8"></div>,用setAttribute、getAttribute
    • 方式二:写在堆内存中,box{index:8},用box.index=8、box.index

.sync: supName.sync

性能优化指令

7. v-pre 让元素及其后代元素跳过编译

  • v-pre:在视图编译渲染的时候,跳过拥有这个指令的元素及其后代元素[不进行任何的语法的编译,你写的是啥,呈现在视图上就是啥];
    • 真实项目中,我们完全可以把一些“静态内容”不进行任何的编译,以此来优化视图编译渲染的速度!!

8. v-once 控制元素或组件的编译次数

  • v-once:让元素或者组件只在视图第一次渲染的时候编译一次,当视图重新渲染的时候,这部分内容就不再重新编译了;
    • 适用于第一次动态绑定完成后,后期不会再更新的内容

9. v-clock 延迟显示元素

    • v-clock:在非工程化的vue项目中,在js没有加载出来之前,页面会呈现出原始的{{xxx}}这种内容,只有js加载出来并处理完成,才能把template语法编译为真实DOM渲染到页面中。
    • 为了防止这种“闪”的效果,我们在js没有加载完成之前让容器隐藏,加载完成之后再让它显示。
  • 用法:
    <style>
      	[v-clock]{
      		display:none;
      	}
      </style>
      <div v-clock></div>

10. v-model

v-model`:实现==视图更新控制状态修改==

- 实现原理:

    • @1把状态值赋值给文本框的value属性
    • @2基于==input==事件监听文本框内容的改变,当内容改变的时候,去修改对应的状态值

修饰符

.lazy 把监听事件从input换成change*

  • input事件:只要正在输入就触发,不一定输入的内容进入到文本框中(例如:中文输入框)
  • change事件:内容已经进入到文本框,摁下enter键时,(value值确认改变时),才会触发
    • 所以change比input性能消耗低、但是流畅度也比较低

.number` 规定输入的内容必须是数字格式

文本框中默认输入的内容都是字符串格式,设置了这个修饰符,vue内部会把输入的内容自动转换为数字(如果出现非有效数字字符,则会把非有效字符及以后的内容干掉)

.trim 自动去除输入内容的首尾空格

能够用v-model的修饰符的标签类型有input/textarea、select(option)、input[type='radio']、input[type='checkbox']

select下拉框

    • 1、拿city状态值和option中的value值做比较,和谁一样,谁默认选中
    • 2、监听下拉框的change事件,选中的是谁,就把那个选项的value赋值给city状态
    • 3、select标签加mutiple属性表示可多选,则==状态值需要是一个数组==
        <select v-model="city">
            <option value="">请选择</option>
            <option value="beijing">北京</option>
            <option value="shanghai">上海</option>
            <option value="shenzhen">深圳</option>
        </select>
<script>
    let vm = new Vue({
        data: {
            city: 'beijing'
        }
    })
    vm.$mount('#app')
</script>

在radio点选框中

    • 1、会把v-model中的sex状态值相同的作为同一组,一组中只能选中一个【也可以自己设置name】
    • 2、根据sex状态值和value值做对比,相同的则默认被选中
    • 3、监听每一个radio的change事件,把选中radio的value值赋值给sex状态值
        <input type="radio" name="sex" :value="0" v-model="sex">男
        <input type="radio" name="sex" :value="1" v-model="sex">女
   let vm = new Vue({
        data: {
            sex: 0
        }
    })
    vm.$mount('#app')

在checkbox多选框中

    • 1、会把v-model中的hobby状态值相同的作为同一组,一组中可以选中多个,所以==hobby状态值必须是一个数组==
    • 2、监听每一个checkbox的change事件,只要有选项被选中或取消选中,都会把value值赋值给hobby状态值
        <input type="checkbox" name="hobby" value="jump" v-model="hobby">音乐
        <input type="checkbox" name="hobby" value="movie" v-model="hobby">电影
        <input type="checkbox" name="hobby" value="music" v-model="hobby">跳舞
        <input type="checkbox" name="hobby" value="read" v-model="hobby">阅读
  let vm = new Vue({
        data: {
            hobby: ['jump', 'read']
        }
    })
    vm.$mount('#app')

vue2.0中如何使用过滤器?

vue1.0中 存在自带的过滤器

vue2.0 中需要在vm实例options API的filters里定义局部过滤器,也可以用Vue.filter定义全局过滤器

  • 能够用filter过滤器的有{{}}(小胡子语法)v-bind指令
    Vue.filter("uppercase", function (value) {
        console.log(value); //msg abc
        return value.toUpperCase();
    })