「 Vue 」如何上手创建一个 Vue 应用

589 阅读7分钟

这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战

关于 Vue 的使用方法,官方文档写的很详细,这里我通过自己的个人理解,再次梳理一下 Vue 的知识学习流程。

为什么要使用 Vue

前端技术的不断发展导致前端开发能够处理的业务越来越多,网页也变得越来越强大和动态化,这些进步都离不开 JavaScript 。在目前的开发中,已经把很多服务端的代码放到了浏览器中来执行,这就产生了成千上万行的 JavaScript 代码,他们连接着各式各样的 HTML 和 CSS 文件,但是缺乏正规的组织形式。这也是为什么越来越多的前端开发者使用 JavaScript 框架的原因,目前比较流行的前端框架有 Angular 、 React 、 Vue 等。

Vue 是一套用于构建用户界面的渐进式框架,渐进式是指 Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

创建一个 Vue app

引入 Vue 最简单的方法是导入 CDN 包:

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

首先创建一个标签:

<div id='root'></div>

createApp 表示创建一个应用存储到 app 变量中,传入的参数表示这个应用最外层的组件该如何展示。

Vue 的编程是面向数据的编程,这种模式参考了 MVVM 设计模式。M 代表 model,这里的 data 就是数据层;V 代表 view,template 就是视图层;VM 代表 viewModel,数据与视图进行连接就是视图数据连接层,这是 Vue 的组件完成的,而不是 Vue 应用。

const app = Vue.createApp({
    data(){
        return{
            message:'hello world'
        }
    },
    template:/*html*/`
        <div>{{message}}</div>
    `
})

vm 表示的是 Vue 应用的根组件实例。

const vm = app.mount('#root')

在控制台中,我们可以通过vm.$data.messagevm.message来获得根节点上的数据。

Vue 的生命周期函数

生命周期函数就是在某一个时刻自动执行的函数。

image.png

创建 App 并挂载节点
分析事件绑定和生命周期函数
beforeCreate() 在实例生成之前自动执行
分析依赖注入和双向绑定
created() 在实例生成之后自动执行
判断实例里是否存在 template 选项
    -存在 将模板编译成 render 函数
    -不存在 将 'root' 中的 innerHTML 编译成 template
beforeMount() 在模板已经被编译成函数之后、挂载到页面之前自动执行
将新的 Dom 替换 'root' 中的 Dom
mounted() 组件内容被渲染到页面之后自动执行
如果改变数据
    beforeUpdate() 当 data 中数据发送变化时立即自动执行
    虚拟 DOM 重新渲染页面
    updated() 当 data 数据发生变化,同时页面完成更新后自动执行
'app.unmount()' 取消挂载,view 不再接管 'root' 挂载的节点
    beforeUnmount() 当 Vue 应用失效,实例销毁时自动执行
    ummounted() 当 Vue 应用失效,且 Dom 完全销毁时自动执行

模板语法

template 中的{{message}}使用的是模板语法,两个花括号之间可以使用 JavaScript 表达式。

v-html的 Vue 指令可以在 div 标签上通过 html 的方式展示其 property 值。

v-bind指令将属性与 data 绑定,简写为:

v-once指令使变量只使用一次,降低无用渲染,提高性能。

<div v>{{'a' + 'b'}}</div>
<div v-html:title="message"></div> <!-- 显示 message 内容 -->
<div v-bind:id="id">{{message}}</div>
<div v-once>{{message}}</div>

v-ifv-elsev-else-if根据表达式的值来决定是否展示标签。

v-on可以进行事件的绑定,简写为@

<div v-on:click="handleClick"></div>

在指令参数中可以使用动态参数,方法是在方括号中使用 JavaScript 表达式。

data() {
    return {
	message: 'hello world',
	name: 'title',
	event:'mouseenter'
    }
}
<div @[event]='handleEvent' :[name]='message'></div>

直接在绑定的事件后使用.prevent修饰符来阻止默认行为。

数据、方法、计算属性和侦听器

const app = Vue.createApp({
    data(){
        return{
            message: 'hello world',
            count: 1,
            price: 5
        }
    },
    method:{
    	formatString(string) {
            return string.toUpperCase();
    	}
    },
    watch:{
    	price(current, prev) {
            setTimeout(()=>{
		console.log(prev, current)
            },3000)
    	}
    },
    computed:{
    	total() {
            return this.count * this.price;
	}
    },
    template:`
        <div>{{formatString (message)}}</div>
        <div>{{total}}</div>
    `
})

在控制台中,我们可以通过vm.$data.messagevm.message来获得根节点上的数据。

app 中的methodthis指向 Vue 的实例,所以定义方法时不要使用箭头函数。

computed定义数据会有较强的语义,当数据发生变化时,计算属性中的数据会重新计算。

computed属性依赖的内容发生变更时其中对应的数据才会重新计算;而只要页面重新渲染,method中的方法就会重新执行。

watch可以监听到变量的变化然后执行对应函数,每个函数有两个参数,分别表示当前的值和变化前的值。

computedmethod都能实现的功能使用computed,因为数据没有变化的时候有缓存;computedwatch都能实现的功能使用 computed,因为更加简洁。

样式绑定

可以采用字符串、数组和对象的方式来指定classstyle

.red {
    color: red;
}
.green {
    color: green;
}
const app = Vue.createApp({
    data(){
        return{
            message:'hello world',
            classString: 'red',
            classObject: {red: false, green: true},
            classArray: ['red', 'green', {class3: true, class4: false}],
            styleString: 'color: yellow',
            styleObject: {
                color: 'orange';
                background: 'yellow';
            }
        }
    },
    template:`
        <div :class='classString'>{{message}}</div>
        <div :class='classObject'>{{message}}</div>
        <div :class='classArray'>
        	{{message}}
        	<demo class='green'/>
        </div>
        
        // 行内样式
        <div :style='styleString'>{{message}}</div>
        <div :style='styleObject'>{{message}}</div>
    `
})

app.component('demo',{
    template:`
        <div :class='$attrs.class'>one</div>
	<div :class='$attrs.class'>two</div>
    `
})

父组件的样式会传递到子组件,在组件的调用时绑定样式只能适用于组件中最外层只有一个节点的情况。

条件渲染

v-ifv-elsev-else-if指令用来条件性地渲染一个元素块,当指令返回值为 truthy 的时候渲染该块,值为 falsy 的时候不渲染。这些指令通过直接控制这个元素在 dom 上的存在与否来控制它的展示和隐藏。

v-show指令也是通过指令返回值来渲染一个元素块。它通过 style 样式display:none来控制元素的展示与否。

如果要频繁切换元素时,我们使用v-show,因为它不会频繁创建和销毁 DOM 元素,性能更好。否则我们使用v-if,因为它的初始渲染开销较小。

当我们想用v-if同时控制多个元素的渲染的时候,在<template>元素上使用。

v-ifv-for优先级更高,不要同时在一个元素上使用这两个指令。

列表渲染

v-for指令用于将数组或对象中的数据循环渲染出来,第一个参数为必选,其他参数可选。

遍历数组时有两个参数,第一个为 value,第二个参数为 index。

遍历对象时有三个参数,第一个为 value,第二个参数为 key,第三参数为 index。

data() {
    return {
	listArray: ['hello', 'world', 'foo', 'bar'],
	listObject: {
            firstName: 'Steven',
            lastName: 'Jobs'
	}
    }
},
method: {
    handleClick() {
	this.listArray.pop();
    }
}
<div v-for='(item, index) in listArray'>
	{{index}} - {{item}}
</div>
<button @click='handleClick'>
<div v-for='(value, key, index) in listObject'>
	{{index}} - {{key}} - {{item}}
</div>

由于 v-for “就地更新”的策略,我们需要为每一个循环元素声明一个不重复的 key 值,这个值只能是数字或者字符串,key 绑定的值最好不要是 index。

<div v-for='(item, index) in listArray' :key='item'></div>

改变数组的内容有两种方法,一种是使用数组的变更函数:

push()pop()shift()unshift()splice()sort()reverse()

还有一种是直接替换数组:

filter()concat()slice()

v-for循环的数组可以是一个计算属性或者是一个带有数组返回值的方法:

computed: {
    evenNumbers(){
	return this.numbers.filter(number => number % 2 === 0)
    }
}
<div v-for='item in evenNumbers' :key='item'></div>

v-for也接收一个整数:

<div v-for='item in 10' :key='item'></div>

v-if的优先级比v-for高,如果想同时使用,可以这样:

<template v-for='item in items' :key='item'>
    <div v-if='item % 2 ===0'>
	{{item}}
    </div>
</template>

事件处理

v-on指令可以让我们绑定一个事件,缩写为@

<button @click='handleClick'>click here</button>

之后我们需要在methods选项中定义这个事件:

methods: {
    handleClick() {
	alert('clicked!');
    }
}

事件可以传参,默认参数为event,如果传递多个参数时要传递event,可以使用$event

<button @click='addNumber(2, $event)'>click here</button>

可以同时绑定多个事件,但是要写为函数调用,不能写为函数引用:

<button @click='handleClick(), handleClick1()'>click here</button>

事件修饰符

事件修饰符让我们在事件调用时轻松处理一些常见的需求,例如阻止事件的继续传播、阻止事件的的默认行为。这样做的好处是让我们在方法中只关注数据逻辑,而不是对 DOM 的操作。

按键修饰符

监听键盘事件时,我们会去检查详细的按键信息,按键修饰符可以让我们在调用事件的时候对按键做出限制。

表单中的双向绑定

基础用法

v-model用于在表单中的<input><textarea><select>等元素上进行双向绑定。

inputtextarea 中,v-model 使用其中的 value property 和 input 方法:

data(){
    return {
        message: 'hello'
    }
},
template:`
    <input v-model='message'/>
    <textarea v-model='message'/>
`

checkboxradio 中,v-model 使用其中的 checked property 和 change 方法,绑定的值可以是 boolean 值、数组或者字符串:

// 绑定的值是数组的情况
data(){
    return {
        message: []
    }
},
template:`
    apple <input type='checkbox' v-model='message' value='apple'/>
    banana <input type='checkbox' v-model='message' value='banana'/>
    pear <input type='checkbox' v-model='message' value='pear'/>
    {{message}}
`
// 如果勾选 apple 和 banana,则 message === ['apple', 'banana']

select 中,v-model 使用其中的 value property 和 change 方法:

单选时:

data(){
    return {
        message: ''
    }
},
template:`
    <select v-model='message'>
	<option disable value=''>请选择内容</option>
	<option>apple</option>
	<option>banana</option>
	<option>pear</option>
    </select>
    {{message}}
`

多选时:( Ctrl + 鼠标左键 多选)

data(){
    return {
        message: [],
        // 这里将 option 的属性用数组保存,用 v-for 渲染
        options: [
            {text: 'apple', value: 'apple'},
            {text: 'banana', value: 'banana'},
            {text: 'pear', value: 'pear'}
        ]
    }
},
template:`
    <select v-model='message' multiple> <!-- 多选 -->
	<option 
            v-for='(option, index) in options' 
            :value='option.value'
            :text='option.text'
            :key='index'
	/>
    </select>
    {{message}}
`

值绑定

对于checkboxradioselectv-model绑定的值一般为静态字符串。

如果我们想把值绑定的到一个动态属性上,可以用v-bind来实现,v-bind还可以将输入值绑定到非字符串。

<select v-model='selected'>
    <option :value='{ number: 123}'>123</option>
</select>
<!--
    被选中时
    typeof vm.selected => 'object'
    vm.selected.number => 123
-->

checkboxtrue-valuefalse-value 的属性值可以根据 checked 返回相应的内容给绑定值。

<input 
    type='checkbox' 
    v-model='toggle' 
    true-value='yes' 
    false-value='no' 
/>
<!-- checked 的值为 true,则 toggle 的值为 yes -->

修饰符

v-model 在每次 input 事件触发后同步输入框的值到数据。通过使用 .lazy 修饰符可以转化为在 change 事件触发后同步:

<input v-model.lazy='message' />

.number 修饰符将输入值转为数值类型;若输入的类型是 number ,Vue 会自动转化:

<input v-model.number="age" type="text" />
<input v-model="amount" type="number" />

若想过滤首尾空白符,使用 .trim 修饰符。