zl程序教程

您现在的位置是:首页 >  前端

当前栏目

Vue核心知识

Vue 知识 核心
2023-09-11 14:16:24 时间

Vue简介

Vue是一款渐进式JavaScript框架,作用是为了动态构建用户界面,该框架遵循MVVM模式,编码简洁,体积小,运行效率高。

Vue的基本使用

引入Vue

直接引入CDN

<script src="https://unpkg.com/vue@next"></script>

NPM方法

# 最新稳定版
$ npm install vue@next

Vue CLI 脚手架

// 安装脚手架
npm install -g @vue/cli
// 脚手架生成 vue 项目,同时会自动安装依赖
vue create vue-cli-demo

启动项目

$ cd my-project
$ cnpm install
$ cnpm run dev

实例的创建

Vue3中的应用是通过使用createApp函数来创建的,语法格式如下:

const app = createApp({
	/*选项*/
})

实例的挂载

一个应用需要被挂载到一个DOM元素中,挂载时使用mount()

举例:以下代码使用mount(‘#hello-vue’)将应用HelloVueApp挂载到<div id="hello-vue"></div>中。

<div id="hello-vue" class="demo">
  {{ message }}//插值语法
</div>
<script>
const HelloVueApp = {
  data() {
    return {
      message: 'Hello Vue!!'
    }
  }
}
Vue.createApp(HelloVueApp).mount('#hello-vue')
</script>

data属性

组件的data选项是一个函数。Vue会在创建新组件实例的过程中调用此函数。他应该返回一个对象,然后Vue会通过响应性系统将其包裹起来,并以$data的形式存储在组件实例中。

const app = Vue.createApp({
  data() {
    return { count: 4 }
  }
})
//mount 不返回应用本身,它返回的是根组件实例。
const vm = app.mount('#app')
console.log(vm.$data.count) // => 4
console.log(vm.count)       // => 4

面试题:vue中的data属性为什么必须是函数?

  1. JavaScript中的对象是引用类型的数据,当多个实例引用同一个对象时,只要一个实例对这个对象进行操作,其他实例中该对象数据也会发生变化。
  2. 在Vue中,更多的是想要复用组件,那就需要每个组件都有自己的数据,这样组件之间才不会相互干扰。
  3. 组件的数据不能写成对象的形式,而是要写成函数的形式。数据以函数返回值的形式定义,这样当每次复用组件的时候,就会返回一个新的data,也就是说每个组件都有自己的私有数据空间,它们各自维护自己的数据,不会干扰其他组件的正常运行。

模板语法

所谓的模板就是动态的Html页面,包含了一些JS语法代码,在Vue中使用插值语法指令(以v-开头的自定义属性标签)

插值语法

语法格式:{{XXX}},作用就是向页面输出数据,可以调用对象的方法,例如:
{{XXX.toUpperCase()}}

指令

强制数据绑定 v-bind(:)

下面代码中img标签的src属性不会获取到data中定义的imgSrc属性的值,这个时候就需要使用强制数据绑定。

强制数据绑定,功能是指定变化的属性值,完整写法是:v-bind:src='imgSrc',一般采用简洁写法::src='imgSrc'

<body>
  <div id="app">
      <p>{{msg}}</p>
      //可以调用对象的方法
      <p>{{msg.toUpperCase()}}</p> 
      //<img src="imgSrc" alt="">//这样写无法获取到data中定义的imgSrc属性的值
      //应该写为
      <img :src="imgSrc" alt="">
  </div>
<script src="https://unpkg.com/vue@next"></script>
<script>
    const app=createApp({
        data: {
            msg: 'Hello Word',
        }
    })
    app.mount('#app')
</script>
</body>

绑定事件监听 v-on:click(@click)

绑定事件监听指令的作用就是绑定指定事件名的回调函数,完整写法:v-on:click='xxx'或者v-on:click='xxx(参数)'再或者v-on:click.enter='xxx',简洁写法就是:@click='xxx',使用@符号;

<body>
  <div id="app">
      <button v-on:click = 'test1'>test1</button>
      <button v-on:click = 'test2(msg)'>test2</button>
      <button @click = 'test'>test</button>
  </div>
<script src="https://unpkg.com/vue@next"></script>
<script>
    const app=createApp({
        data: {
            msg: 'Hello Word',
            imgSrc: 'http://image.luokangyuan.com/1.jpg'
        },
        methods: {
            test1() {
                alert(123)
            },
            test2(content) {
                alert(content)
            },
            test() {
                alert(123)
            }
        }
    })
    app.mount('#app')
</script>
</body>

事件修饰符

使用方式很简单,在绑定事件后面加上修饰符就可以

  • .stop:停止事件冒泡
    举例:
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
  • .prevent:阻止事件的默认事件和默认行为
    举例:
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
  • .keyCode:keyCode是键盘对应的按键,当键盘弹起时触发事件,也可以直接使用按键名称
    举例:
<!-- 按下Alt + C 清除输入框内容 -->
<input @keyup.alt.67="clear" />
  • capture:给元素添加一个监听器,当元素发生冒泡时,先触发带有该修饰符的元素。若有多个该修饰符,则由外而内触发。

capture举例:

<div id="content">
    <div id="obj1" v-on:click.capture="doc">
        obj1
        <div id="obj2" v-on:click.capture="doc">
            obj2
            <div id="obj3" v-on:click="doc">
                obj3
                <div id="obj4" v-on:click="doc">
                obj4
                <!--。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。点击obj4的时候,弹出的顺序为:obj1、obj2、obj4、obj3;
                由于12有修饰符,故而先触发事件,然后就是4本身触发,最后冒泡事件。
                -->
            	</div>
            </div>
        </div>
    </div>
</div>

v-once一次性插值

一次性插值,数据改变时插值处的内容不会更新

 <span v-once>{{msg}}</span>

v-html

使用 v-html 指令用于输出 html 代码

<div id="example1" class="demo">
    <p>使用双大括号的文本插值: {{ rawHtml }}</p>
    <p>使用 v-html 指令: <span v-html="rawHtml"></span></p>
</div>
 
<script>
const RenderHtmlApp = {
  data() {
    return {
      rawHtml: '<span style="color: red">这里会显示红色!</span>'
    }
  }
}
Vue.createApp(RenderHtmlApp).mount('#example1')
</script>

HTML属性中的值应使用v-bind指令

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

对于布尔属性,常规值为 true 或 false,如果属性值为 null 或 undefined,则该属性不会显示出来。
举例:

<button v-bind:disabled="isButtonDisabled">按钮</button>

以上代码中如果 isButtonDisabled 的值是 null 或 undefined,则 disabled 属性甚至不会被包含在渲染出来的 元素中。

表达式

Vue.js 提供了完全的 JavaScript 表达式支持。

<div id="app">
    {{5+5}}<br>
    {{ ok ? 'YES' : 'NO' }}<br>
    {{ message.split('').reverse().join('') }}
    <div v-bind:id="'list-' + id">hello</div>
</div>
    
<script>
const app = {
  data() {
    return {
      ok: true,
      message: 'RUNOOB!!',
      id: 1
    }
  }
}
 
Vue.createApp(app).mount('#app')
</script>

表达式会在当前活动实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效:

<!--  这是语句,不是表达式:-->
{{ var a = 1 }}

<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}

计算属性和监视

计算属性computed

计算属性在处理一些复杂逻辑是是很有用的

语法模式:{ [key: string]: Function | { get: Function, set: Function } }

举例:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Vue 测试实例</title>
<script src="https://unpkg.com/vue@next"></script>
</head>
<body>
<div id="app">
  <p>原始字符串: {{ message }}</p>
  <p>计算后反转字符串: {{ reversedMessage }}</p>
</div>
    
<script>
const app = {
  data() {
    return {
      message: 'RUNOOB!!'
    }
  },
  computed: {
    // 计算属性的 getter
    reversedMessage: function () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }
  }
}
Vue.createApp(app).mount('#app')
</script>

使用计算属性实现双向绑定

const app = createApp({
  data() {
    return { a: 1 }
  },
  computed: {
    // 仅读取
    aDouble() {
      return this.a * 2
    },
    // 读取和设置
    aPlus: {
         // getter 回调函数,当需要读取当前属性值时回调,根据相关的数据计算并返回当前属性的值
      get() {
        return this.a + 1
      },
        // setter 回调函数,监视当前属性的变化,当属性值发生改变时回调,更新相关的属性数据
      set(v) {
        this.a = v - 1
      }
    }
  }
})
const vm = app.mount('#app')
console.log(vm.aPlus) // => 2
vm.aPlus = 3
console.log(vm.a) // => 2
console.log(vm.aDouble) // => 4

computed vs methods

可以使用 methods 来替代 computed,效果上两个都是一样的。

但是

  • computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。
  • 而使用 methods ,在重新渲染的时候,函数总会重新调用执行。

监视属性watch()

监听属性,就是监测指定的属性是否发生变化,如果发生了,回调函数自动调用,进行相关操作,如果没发生变化,则监视属性也不会被触发。

语法格式:

{ [key: string]: string | Function | Object | Array}

举例:

watch:{
  sum:{
      // 深度监视,因为watch默认只是浅层监视
      depp:true,
      // 在初始化完成之后就触发监听
      immediate:true,
      // 监视属性的回调
      handler(newValue, oldValue){
          console.log('求和的值变化了',"变化后的值是"+newValue, '变化前的值是'+oldValue);
      }
// 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
    c: {
      handler:function(val, oldVal) {
        console.log('c changed')
      },
      deep: true  // 深度监视,因为watch默认只是浅层监视 有时候对象的属性发生变化了也需要监听到,则需要将deep设置为true
    },
    // 侦听单个嵌套 property
    'c.d': function (val, oldVal) {
      // do something
    },

methods VS watch VS computed

在这里插入图片描述

class与style绑定

在某些页面中,某些元素的样式是动态发生变化的,class和style绑定就是用来实现改变样式效果的技术,其中class绑定中,表达式可以是字符串,可以是对象,也可以是数组。

v-bind:class 可以简写为 :class
v-bind:style可以简写为style

举例:
点击更新按钮样式发生改变

<head>
  <meta charset="UTF-8">
  <title>class和style绑定</title>
  <style>
      .aClass{color: red}
      .bClass{color: blue}
  </style>
</head>
<body>
  <div id="app">
      <h1>class绑定</h1>
      <p :class="a">我是字符串</p>
      <p :class="{aClass: isA,bClass: isB}">我是对象</p> <!--class绑定的是对象。当为true才会留下-->
      <h1>style绑定</h1>
      <p :style="{color: activeColor, fontSize: fontSize+'px'}">我是style强制绑定</p>
      <button @click='update'>更新</button>
  </div>
<script src="https://unpkg.com/vue@next"></script>
<script>
    const app =createApp({
       data: {
        a: 'aClass',
        isA: true,
        isB: false ,// 以上是绑定class
        activeColor: 'red', // 以下是绑定style
        fontSize : 20
       },
       methods: {
        update(){
            this.a = 'bClass';
            this.isA = false;
            this.isB = true;// 以上是绑定class
            this.activeColor = 'blue';
            this.fontSize = 30;
        }
       }
    })
    app.mount('#app')
</script>
</body>

分支结构

在vue中条件渲染使用v-ifv-elsev-else-ifv-show指令。

举例:
v-if:

这里,v-if指令将根据表达式seen的值(true或false)来决定是否插入p元素。

因为v-if是一个指令,所以必须将他添加到一个元素上。如果是多个元素,可以包裹在元素上,并在上面使用v-if。最终的渲染结果将不包含元素。

<div id="app">
    <p v-if="seen">现在你看到我了</p>
</div>
    
<script>
const app = {
  data() {
    return {
      seen: true /* 改为false,信息就无法显示 */
    }
  }
}
 
Vue.createApp(app).mount('#app')
</script>

v-else-if,v-else:

<div v-if="type === 'A'">Type A</div>
<div v-else-if="type === 'B'">Type B</div>
<div v-else>Default Type</div>

v-show:

<body>
  <div id="app"> 
      <p v-show = 'ok'>显示失败-v-show</p>     
     </button>
  </div>
<script src="https://unpkg.com/vue@next"></script>
<script>
    const app = createApp({
        data: {
            ok: false
        }
    })
    app.mount('#mount')
</script>
</body>

v-if VS v-show

v-if是不会生成不应该显示的元素,v-show是通过css控制隐藏不应该显示的节点元素。

当需要频繁的切换的时候,使用v-show比较好,当条件不成立时,v-is的所有子节点也不会被解析;

具体区别如下表:
在这里插入图片描述

遍历

v-for指令需要使用item in items形式的特殊语法,除了遍历数组以外,v-for还能遍历对象、数字。

v-for迭代数组

<!-- 遍历数组时 -->
<!-- 其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名,可选的第二个参数 index 为当前项的索引 -->
<ul>
  <li v-for="(item, index) in items">
    {{index}}: {{ item.message }}
  </li>
</ul>

v-for迭代整数

<div id="app">
  <ul>
    <li v-for="n in 10">
     {{ n }}
    </li>
  </ul>
</div>

v-for迭代对象

<!-- 在遍历对象时,会按 Object.keys() 的结果遍历 -->
<!-- 其中 object 是源数据对象,而 value 则是被遍历的对象值,可选的第二个参数 key 为当前值的键名,可选的第三个参数 index 为当前项的索引 -->
<div v-for="(value, key, index) in object">
  {{ index }}.{{ key }}: {{ value }}
</div>

key

key的作用

key作为一个DOM节点的标识值,结合Diff算法可以实现节点的服用。

只有当key(或其他导致isSameNode判断为false)发生改变时,才会触发节点的重新渲染。否则Vue将会复用之前的节点,通过改变节点的属性来实现节点的更新。

<div v-for="item in items" v-bind:key="item.id">

使用id值作为key值和使用index值作为key值的区别

== 不推荐使用index作为key,因为这种做法会导致某些节点被错误的原地复用。==

具体描述:

使用index作为key和没写基本上没区别,因为不管数组顺序怎么颠倒,index都是0,1,2......这样排列的,导致Vue会复用错误的旧子节点,做很多额外的工作。而id值是唯一的,不存在这种问题。

v-if和v-for中key的设置

  • 在Vue2中,建议在v-if、v-else-if、v-else的分支中使用key;Vue2中标签中不能使用key,若想使用,可以为其每个子节点分别设置key。

  • Vue3中我们不再建议在v-if、v-else-if、v-else的分支中继续使用key,因为没有为条件分支提供key时,也会自动生成唯一的key;Vue3中,key则应该被设置在标签上。

v-for与v-if的优先级

两者作用于同一元素上时,Vue3版本中的v-if总是优先于v-for,Vue2则相反

表单数据绑定v-model

表单的数据绑定使用v-model指令,举例:

<body>
    <div id="app">
        <form action="/xxx" @submit.prevent="handSubmit">
            <span>用户名:</span>
            <input type="text" v-model="userName">
            <br>
            <span>密码:</span>
            <input type="password" v-model="pwd">
            <br>
            <span>性别:</span>
            <input type="radio" id="wman" value="女" v-model="sex">
            <label for="wman"></label>
            <input type="radio" id="man" value="男" v-model="sex">
            <label for="man"></label>
            <br>
            <span>爱好:</span>
            <input type="checkbox" id="basket" value="basket" v-model="likes">
            <label for="basket">篮球</label>
            <input type="checkbox" id="footbal" value="foot" v-model="likes">
            <label for="footbal">足球</label>
            <input type="checkbox" id="pingpang" value="pingpang" v-model="likes">
            <label for="pingpang">乒乓球</label>
            <br>
            <span>城市:</span>
            <select name="" id="" v-model="cityId">
                <option value="">未选择</option>
                <option :value="city.id" v-for="(city,index) in allCitys" :key="index">{{city.name}}</option>
            </select>
            <br>
            <span>个人介绍:</span>
            <textarea name="" id="" cols="30" rows="10" v-model="desc"></textarea>
            <br>
            <input type="submit" value="注册">
        </form>
    </div>
     <script src="https://unpkg.com/vue@next"></script>
    <script>
    const app = cretaeApp({            
            data: {
                userName: '',
                pwd: '',
                sex: '男', // 默认选中性别男
                likes: ['foot'], // 默认选中foot对应的多选框
                allCitys: [{ id: 1, name: "北京" }, { id: 2, name: "成都" }, { id: 3, name: "上海" }, { id: 4, name: "宁波" }],
                cityId: '',// 这里默认是空,则匹配未选择,如果默认选中成都,则写2即可
                desc: ''
            },
            methods: {
                handSubmit() {
                    console.log(this.userName, this.pwd, this.sex, this.likes, this.cityId, this.desc)
                }
            }
        })
        app.mount('#app')
    </script>
</body>

修饰符

在这里插入图片描述