内容简介:
1)Vue指令
2)computed和watch
3)生命周期钩子
4)组件间的传参
5)插槽
6)修饰符
7)nextTick()
前端三大框架:
Vue:尤雨溪开发
React:Facebook主导开发
Angular:谷歌主导开发
为什么选择Vue?
1.国内Vue的市场份额占比多
2.简单易上手,非常适合前端开发初学者学习
前置知识:
1.HTML、CSS和JS基础
2.了解Node和npm
3.webpack(可选,vue-cli已经封装了打包功能)
使用Vue的两种方式:
1.直接script标签引入vue.js文件
2.基于Node环境创建Vue项目(使用vue-cli初始化一个Vue项目)
前端框架与库的区别
• jquery 库 -> DOM(操作DOM) + 动画+ ajax请求
• 框架 -> 全方位功能
一、指令
指令(Directives)是带有 v- 前缀的特殊属性。
v-if(条件渲染)和v-show
v-if是通过控制dom节点的存在与否来控制元素的显隐;v-show是通过设置DOM元素的display样式,block为显示,none为隐藏;
v-if有更高的切换消耗,如果需要频繁地切换,则使用 v-show 较好。v-bind和v-on
<!-- 完整语法 -->
<a v-bind:href="url">...</a>
<!-- 缩写 -->
<a :href="url">...</a>
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>
<!-- 缩写 -->
<a @click="doSomething">...</a>
- v-text和v-html
<div id="app">
<!--插值表达式-->
<p>{{ msg }}</p>
<p v-text="msg"></p>
<p v-html="msg"></p>
</div>
<script type="text/javascript">
var vm = new Vue({
el : "#app",
data : {
msg : "<h1>这是一个h1元素内容</h1>"
}
});
</script>
插值表达式和v-text指令被直接解析为字符串;元素绑定 v-html 指令后,解析了msg 变量值里面的html标签,输出真正的html元素。
- v-model
用于表单数据的双向绑定,它是一个语法糖:
<input v-model="inputValue">
<input :value="inputValue" @input="inputValue= $event.target.value">
v-model也可用在自定义组件上。
5.v-for(列表渲染)
使用v-for时应绑定key属性,key属性可以用来提升v-for渲染的效率
<div id="app">
<p v-for="(item,index) in list" :key="item.id">
{{index}}-{{item.name}}-{{item.age}}
</p>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
data: {
list: [{
id:1,
name: '张三',
age: 24,
}, {
id:2,
name: '李四',
age: 27,
}]
},
});
</script>
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
由于 JavaScript 的限制,Vue 不能检测数组、对象的以下变化:1. 利用索引直接设置数组的某一项 2. 对象属性的添加或删除
<template>
<div id="app">
<div v-for="(item,index) in arr" :key="index">{{item}}</div>
<button @click="handleClick">Click Me</button>
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
arr: [1, 2, 3],
obj: {
a: 10,
b: 20,
c: 30
}
}
},
methods: {
handleClick () {
this.arr[2] = 4
//this.$set(this.arr,2,4)
console.log(this.arr)
//this.obj.d=40
}
}
}
</script>
二、computed和watch
- 计算属性computed
1)支持缓存,只有依赖数据发生改变,才会重新进行计算
2)计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明或者父组件传递的props中的数据通过计算得到的值
3)如果一个属性依赖其他多个属性,一般用computed
4)不支持异步,当computed内有异步操作时无效,无法监听数据的变化
computed: {
totalWeight() {
let result = 0
const formList = this.formList
if (formList && formList.length > 0) {
formList.map((item) => {
result = result + parseFloat(item.chargeableWeight)
})
}
return result.toFixed(2)
},
}
- 侦听器watch
1)不支持缓存,数据改变,直接触发相应的操作
2)监听的数据必须是data中声明或者父组件传递过来的props中的数据
3)watch支持异步
watch: {
"form.receiverCountry"(n, o) {
if (n != o) {
this.form.receiverIdCard = '';
this.form.receiverIdCardr = '';
this.getWeightSizeData(n);
this.getFreight()
}
}
}
三、生命周期钩子
什么是Vue生命周期?
Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程。
总共分为8个阶段:创建前/后,挂载前/后,更新前/后,销毁前/后。
1)beforeCreate
此时实例上只有一些生命周期函数和默认的事件,此时data computed watch methods上的方法和数据均不能访问。
2)created
此时可以读取data的值,并可以对其进行操作,把方法、计算属性也都挂载到了实例。但是依旧不能访问el,不能获取到DOM元素。
在这个钩子函数中,我们可以进行http请求,把请求到的数据储存在data中。
3)模板编译,把data里面的数据和vue语法写的模板编译成HTML
4)beforeMount
将编译完成的HTML挂载到对应虚拟DOM,此时还未挂载到页面上
5)mounted
编译好的HTML已挂载到页面上
6)beforeUpdate和updated
数据更新时调用,通常使用计算属性或侦听器取而代之
7)beforeDestroy
销毁所有观察者、组件及事件监听
8)destroyed
组件已经完全销毁,组件中的数据、方法、计算属性、过滤器等都已不可用。
四、组件间的通信
1.父子组件间的通信
父子组件通信可以总结为props向下传递,事件向上传递。
<!--父组件-->
<blog-post :title="title"></blog-post>
//子组件
export default {
props: {
title: {
type: String,
default: '默认标题'
}
}
}
单向数据流:父级 prop 的更新会向下流动到子组件中,但反过来不行。
每个Vue实例都实现了事件接口:子组件使用this.$emit(eventName,optionalPayload)
触发自定义事件。父组件在使用子组件的地方直接用v-on来监听子组件触发的事件。
父组件通过ref直接调用子组件中的方法。
子组件调用父组件中的方法:
1)子组件中通过this.$parent.fatherMethod()
来调用父组件的方法
2)子组件用$emit向父组件触发一个事件,父组件监听这个事件
3)父组件通过props把方法传入子组件中(type: Function),在子组件里直接调用这个方法
2.兄弟组件间的通信
其中一种方法是让父组件充当两个子组件之间的中间件(中继);
另一种就是使用EventBus(事件总线),它允许两个组件之间直接通信,而不需要涉及父组件:
// main.js
import Vue from 'vue'
export const eventBus = new Vue()
//发布自定义事件的组件
eventBus.$emit('customEvent', data)
//订阅自定义事件的组件
eventBus.$on('customEvent', data => {
console.log(data);
}); //要在页面一加载出来就订阅,一般写在 created 或mounted 钩子里
Vue原型上的方法:
五、插槽
<!--父组件-->
<template>
<div>
<div>大家好我是父组件</div>
<myslot>
<p>测试一下内容写在这里能否显示</p>
</myslot>
</div>
</template>
<script>
import myslot from './myslot';
export default {
components: {
myslot
}
}
</script>
<!--myslot.vue-->
<template>
<div>
<div>我是子组件</div>
<!-- <slot>默认插槽</slot> -->
</div>
</template>
插槽的作用
可以拓展组件,更好地复用组件和对其做定制化处理插槽的分类
1)默认插槽
2)具名插槽
在一个 <template> 元素上使用 v-slot 指令
<!--父组件-->
<template>
<myslot>
<div>大家好我是父组件</div>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template v-slot:footer>
<p>Here's footer info</p>
</template>
</myslot>
</template>
<!--myslot.vue-->
<template>
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>
</template>
3)作用域插槽
<template>
<div class="father">
<h3>这里是父组件</h3>
<!--用列表展示子组件中的数据-->
<child>
<template slot-scope="user">
<ul>
<li v-for="item in user.data">{{item}}</li>
</ul>
</template>
</child>
</div>
</template>
<template>
<div class="child">
<h3>这里是子组件</h3>
<slot :data="data"></slot>
</div>
</template>
<script>
export default {
data(){
return {
data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
}
}
}
</script>
使用场景:
在使用ElementUI组件库的el-table组件时,表格的编辑和删除操作要用到作用域插槽。因为el-table组件,就是当前组件的子组件。通过作用域插槽很容易拿到当前表格行的索引和内容,这样就可以很方便地进行编辑、删除的操作。v-slot指令是Vue2.6之后,作用域插槽的新语法,旧语法(slot-scope)现在还保留,但3.0之后会移除。
六、修饰符
- v-model的修饰符
<div>
<!-- 默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步,添加 lazy 修饰符,从而转变为使用 change 事件进行同步-->
<input v-model.lazy="msg">
<!--自动将用户的输入值转为数值类型-->
<input v-model.number="age" type="number">
<!--自动过滤用户输入的首尾空白字符-->
<input v-model.trim="phone">
</div>
2.事件修饰符
vue提倡的是在方法中只有纯粹的数据逻辑,而不是去处理 DOM 事件细节,所以提供了事件修饰符用于DOM的事件处理。
<div>
<!-- 阻止单击事件冒泡 -->
<div @click.stop="doThis"></div>
<!-- 默认情况下,点击表单提交按钮时会重新加载页面,使用.prevent修饰符可以阻止默认事件 -->
<form @submit.prevent="onSubmit"></form>
<el-dropdown>
<div class="user-toggle-btn">
<img src="@/assets/images/user-pic.png">
<span>{{ cusName }}</span>
</div>
<el-dropdown-menu slot="dropdown">
<!--你可能想在某个组件的根元素上监听一个原生事件,可以使用.native -->
<el-dropdown-item @click.native="logout">
<div>
<svg-icon class="mr-5"
class-name="exit-icon right-menu-item"
icon-class="exit" />
<span>{{ $t('logOut') }}</span>
</div>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
3.按键修饰符
<input v-model="loginForm.loginPassword" @keyup.enter="handleLogin" />
七、nextTick()
定义:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。(当数据更新了,在dom中渲染后,自动执行nextTick的回调)
应用场景:需要在视图更新之后,基于新的视图进行操作。
handleAdd() {
this.type = 'add'
this.dialogFormVisible = true
console.log(this.$refs.cnName)
this.$nextTick(() => {
this.$refs.cnName.focus()
})
}