VUE
根据各类网络教程总结的VUE前端基础知识点
VUE
Vue是一款用于构建用户界面的渐进式JS框架
模块化:项目划分模块,单独开发、维护,提高效率
组件化:将页面的各个组成部分封装为组件,提高复用性
规范化:提供标准的目录结构,编码规范,开发流程
自动化:项目构建、开发、测试、打包、部署
1.1 VUE工程化
创建一个工程化的VUE项目,执行命令npm create vue@{version}
,将会安装并执行create-vue脚手架工具
执行npm install
下载包
项目结构介绍
npm run dev
命令启动Vue项目
Vue实例与容器只能1-1对应
花括号中只能写JS表达式
Vue控制台 选项卡1-观察组件结构
1.3 模板语法
插值/指令 语法
在属性内插值被移除,只能用v-bind:xxx=“”,VUE会将双引号中的字符当作JS表达式执行
标签体中用插值语法,标签属性(解析标签)用指令语法
1.4 数据绑定
v-bind单向绑定,数据从data流向页面
v-model双向绑定,页面与data同时更新
v-model只能运用在表单类/输入类(有value值的)标签中
- el与data
1 |
|
el绑定也可以写成:
1 |
|
好处是可以在绑定时做别的逻辑操作
==data的函数式写法:==
1 |
|
组件中必须使用此类写法,不要写箭头函数(保持this为vue实例)
1.5 MVVM模型 model-view-viewmodel
花括号中 vm中有的属性全都能用
1.6 数据代理
- Object.defineProperty()方法 (ES6)
用此方法加入的参数
默认不参与遍历 enumerable:true
默认不可修改 writable:true
默认不可删除 configurable:true
1 |
|
- 数据代理的定义
通过defineProperty()实现数据代理
- Vue中的数据代理
把vm中的数据用defineproperty()放在data中
使数据操作更方便
1.7 事件处理
1 |
|
- 事件修饰符
@click.stop 阻止事件冒泡
@click.prevent 阻止默认事件
@click.once 事件只触发一次
@click.capture 使用事件的捕获模式(div外到内)
@click.self 仅当e.target是当前操作元素才触发
@click.passive 事件的默认行为立即执行,无需等待回调
- 键盘事件
1.8 计算属性
1.插值语法{{str.slice(0,3)}}
===
1 |
|
===
1 |
|
监视属性 – watch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// 监视属性变化时,handler自动调用
// 监视多层级属性改变时,需给watch配置deep:true
watch:{
func:{
//还有很多配置
immediate:true
handler(newvalue,oldvalue){
pass
}
}
}
vm.$watch('属性', {
immediate:true
handler(newvalue,oldvalue){
pass
}
})计算属性和监视属性的区别
watch不靠返回值,可以实现异步任务不被Vue管理的函数(如定时器setTimeout,Ajax的回调函数,Promise的回调函数)要写成箭头函数
1.9 绑定样式
1 |
|
1.10 条件渲染
v-show / v-if
可以用写条件,template不影响结构,页面渲染时不存在。但只能配合v-if。
1.11 列表渲染 v-for
1 |
|
key的原理
虚拟DOM对比算法 – 不一致的节点:更新 + 一致的节点:不变
如果用index作为key,且对数据破坏了顺序,会导致对应节点信息错位列表过滤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// watch实现
new Vue({
el:"#root",
data:{
keyword:"",
persons:[
{id:'1',name:"马冬梅",age:19},
{id:'2',name:"周冬雨",age:20},
{id:'3',name:"周杰伦",age:21},
{id:'4',name:"温兆伦",age:22},
],
filterPersons:[]
},
watch:{
keywrod:{
immediate:true,
handler(val){
this.filterPerson = this.persons.filter((p)=>{
return p.name.indexOf(val) !== -1
})
}
}
}
})1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21// 计算属性实现
new Vue({
el:"#root",
data:{
keyword:"",
persons:[
{id:'1',name:"马冬梅",age:19},
{id:'2',name:"周冬雨",age:20},
{id:'3',name:"周杰伦",age:21},
{id:'4',name:"温兆伦",age:22},
],
filterPersons:[]
},
computed:{
filterPersons(){
return this.filterPersons = this.persons.filter((p)=>{
return p.name.indexOf(this.keyword) !== -1
})
}
}
})列表排序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38<div id="root">
<h2>列表过滤</h2>
<input type="text" placeholder="请输入名字" v-model="keyword">
<button @click="sortType = 2">年龄升序</button>
<button @click="sortType = 1">年龄降序</button>
<button @click="sortType = 0">原顺序</button>
<ul>
<li v-for="(index,p) in filterPersons" ::key="p.id">
{{p.name}}--{{p.age}}
</li>
</ul>
</div>
new Vue({
el:"#root",
data:{
keyword:"",
sortType:0, //0-原顺序 1-降序 2-升序
persons:[
{id:'1',name:"马冬梅",age:19},
{id:'2',name:"周冬雨",age:20},
{id:'3',name:"周杰伦",age:21},
{id:'4',name:"温兆伦",age:22},
],
filterPersons:[]
},
computed:{
filterPersons(){
const arr = this.filterPersons = this.persons.filter((p)=>{
return p.name.indexOf(this.keyword) !== -1
})
if(this.sortType){
arr.sort((a,b)=>{
return this.sortType === 1 ? b.age-a.age : a.age-b.age
})
}
return arr
}
}Vue监测数据的原理
Vue检测data中的所有数据
==对象==:
Vue.set(target, propertyName/index, value)
/vm.$set(target, propertyName/index, value)
后添加的数据属性也可以保证响应式get set,但只能给vm的对象添加属性,而不能直接给vm本身和vm根数据对象添加==数组==:不会为数组元素匹配get/set,Vue中的数组方法被重新包装过,
push/pop/shift/unshift/splice/sort/reverse
,都会引起模板的渲染。数组也可以用Vue.set/vm.$set()
1.12 收集表单元素
v-model收集的是value值,得在<input>
中配置value
多选框v-model对应的data要配置为数组
v-model也有修饰符,如v-model.number
可以限制输入数据为数字类型,v-model.lazy
可以在失去焦点时再收集,v-model.trim
可以去掉前后空格
1.13 过滤器
1 |
|
1.14 Vue指令
指令 | 用途 |
---|---|
v-bind | 单向绑定解析式,可简写为:xxx |
v-model | 双向数据绑定 |
v-for | 遍历数组/对象/字符串 |
v-on | 绑定事件监听,可简写为@ |
v-else | 条件渲染 |
v-show | 条件渲染 |
v-if | 条件渲染 |
v-text | 向所在节点渲染文本,并且替换原有文本 |
v-html | 支持结构解析(可以在数据中放标签) 安全性问题:cookie作字符传,XSS攻击 |
v-cloak | 配合css可以控制页面在Vue接管前的效果,可以解决JS阻塞,和未经解析的模板渲染到页面 |
v-once | 所在节点在初次动态渲染后,视为静态内容;以后的数据改变不改变内容,可用于优化性能 |
v-pre | 跳过节点编译过程,Vue不解析 |
自定义指令(全局/局部 写法与过滤器一致)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<span v-xxx="n"></span>
data:{
n:1
}
directives:{
// 自定义指令函数何时调用
// 1. 指令与元素绑定时(一上来)
// 2. 指令所在模板被重新解析时
xxx(element真实DOM元素, binding绑定信息){
//操作DOM元素
}
//写成对象可以选择操作的生命周期
xxx2:{
bind(){},
inserted(){}, //绑定元素插入时(获取焦点/拿到父元素...)
update(){}
}
}
1.15 生命周期
1 |
|
1.16 组件
依据不同页面部分编码组件,封装功能,提高复用率
定义:实现应用中局部功能代码和资源的集合
非单文件组件:一个文件中包含n个组件
单文件组件:一个文件只包含一个组件
如何创建组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23// 1. 创建school组件
const school = Vue.extend({
template:`<div><h2>123</h2><div>`
data():{
return {
//data
}
}
})
// 2. 注册组件(局部注册)
// Vue.component('school',school) 全局注册
new Vue({
el:"#root",
components:{
school:school
student:student
}
})
// 3. 编写组件标签
<div id="root">
<school></school>
<student></student>
</div>组件名首字母推荐大写,可以用kebab-case/CamelCase方法命名
使用name配置变量可以改变在开发者工具中的标签名显示
组件嵌套
1
2
3
4
5
6
7
8
9
10
11const school = Vue.extend({
template:`<div><h2>123</h2><div>`
data():{
return {
//data
}
}
components:{
student:student //先在前面准备好stu组件
}
})最外层要写
组件
每次调用Vue.extend,返回的都是全新的VueComponent
Vue实例&组件实例 vm&vc
一个内置关系:
VueComponent.prototype.__proto__ === Vue.prototype
让vc可以访问Vue的原型对象(属性/方法)
1.17 单文件组件
1 |
|
脚手架结构
App.vue ↓
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24<template>
<div>
<School></School>
<Student></Student>
</div>
</template>
<script>
// 引入组件
import School from './School'
import Student from './Student'
// ES6,默认暴露
export default{
name:"App",
components:{
School,
Student
}
}
</script>
<style>
</style>main.js ↓
1
2
3
4
5import App from './App.vue'
new Vue({
el:"#",
component:{App}
})index.html ↓
1
2
3
4
5
6
7
8
9
10
11
12
13
14<!DOCTYPR html>
<html>
<head>
<meta chatset="UTF-8" />
<title></title>
</head>
<body>
<div id="root">
<App></App>
</div>
<script type="text/javascript" src="../js/vue.js"></script>
<script type="text/javascript" src="../main.js"></script>
</body>
</html>
1.18 Vue脚手架 Cli (command line interface)
ref 属性
替代原生JS中id属性,HTML元素
<span ref="xxx">
,this.$refs.xxx
可以拿到DOM节点组件标签加ref可以拿到自定义组件的实例对象vc
props配置项
让组件接收外部传入的数据,如要修改可在data()中作中转
1
<Student name="张三", sex="男", :age="18"></Student>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30<script>
export default {
name:"Student",
data(){
return {
msg:"123"
}
},
props:['name','sex','age'] //1. 简单接收
props:{ //2. 类型限制接收
name:String,
sex:String,
age:Number
}
props:{ //3. 类型限制/默认值/必要性接收
name:{
type:String,
required:true
},
sex:{
type:String,
required:true
},
age:{
type:String,
default:99
}
}
}
</script>mixin配置项
复用JS代码,写一个js文件后,在各Vue组件中用mixin引入
1
2
3
4
5
6//mixin.js
export const mixin = {
methods:{
func(){}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<script>
// 引入一个mixin
import {mixin} from "src"
export default{
name:"",
data(){
return {
name:"",
address:""
}
},
mixin:[mixin]
}
</script>
// 在main.js中引入的话,是全局的引入
Vue.mixin(mixin)Vue插件
增强Vue
src中另起一个plugins.js,新建一个包含install方法的对象,即为插件
1
2
3
4
5
6export default{
// 牛逼的地方是能直接拿到Vue作为形参
// 全局过滤器filter,全局指令directive,混入mixin,
// Vue原型添加方法prototype.hello等,就都可以写在插件中
install(Vue){}
}main.js中import插件,并
Vue.use(plugins)
scoped样式
<style scoped>
可以限制样式标签中的内容只对当前文件有效<style lang="less">
可以用less语法
1.19 组件通信&组件化编码
组件化编码流程
拆分==静态组件==
按功能拆分,命名不与html元素冲突
实现==动态组件==(根据使用数据的组件数量,考虑数据存放位置)
一个组件用 => 放在组件自身
多个组件用 => 放在共同的父组件上(状态提升)
实现交互:绑定事件
props适用
(1). 父组件 → 子组件 通信
(2). 子组件→父组件 通信(父先给子一个函数)
props传的值是不可修改的
若props传的是对象,修改不会报错,但仍不建议修改
1.20 浏览器本地存储
Local Storage
保存数据
window.localStorage.setItem('key','value')
当value为对象时,存入需要调用
JSON.stringify(value)
读取数据
window.localStorage.getItem('key')
同样的,读取结果为对象时需要
JSON.parse(value)
删除数据
window.localStorage.removeItem('key')
localStorage.clear()
Session Storage
与LocalStorage不同的时,关闭浏览器后将会消失。API一致。
1.21 组件自定义事件
通过父组件给子组件==绑定==一个自定义事件,实现子对父传递数据
1
2
3
4
5
6
7
8
9
10
11<template>
// 使用@ / v-on
<sonComponent @customEvent='methodName' />
</template>
<script>
name:'App',
components:{sonComponent},
methods:{
methodName(){...}
}
</script>1
2
3
4
5
6
7
8
9
10// sonComponent
<script>
name:'sonComponent',
methods:{
methodName(){
// 触发子组件组件实例上的自定义事件,完成回调
this.$emit('customEvent',this.name)
}
}
</script>==或者在父组件中使用ref,会更加灵活,可以在钩子上加其他需求==
1
2
3
4
5
6
7
8
9
10
11
12
13
14<template>
// 使用ref
<sonComponent ref='sonComponent' />
</template>
<script>
name:'App',
components:{sonComponent},
methods:{
methodName(){...}
},
mounted(){
this.$refs.sonComponent.$on('customEvent',this.methodName)
}
</script>注意:通过
this.$refs.sonComponent.$on('customEvent',this.methodName回调)
绑定自定义事件时,回调要么配置在methods中,要么使用箭头函数,否则this指向会有问题==解绑==自定义事件
this.$off(['customEvent1','customEvent2'])
this.$off()
- 不传参就解绑所有自定义事件
@click.native
告诉组件使用的是原生事件,不然就全当自定义事件
1.22 全局事件总线
实现任意组件间通信
两个要求:1.所有组件都能看见;2.拥有Vue原型上的API($on/emit/…)
1 |
|
如何使用事件总线?
接收数据:A组件接收数据,就在A组件中给$bus绑定自定义事件,将回调留在自身
1
2
3
4
5
6
7
8
9
10
11methods(){
demo(data){...}
}
mounted(){
this.$bus.$on('customEvent',this.demo)
}
//使用后要销毁,不然将一直占用bus
beforeDestroy(){
this.$bus.$off('customEvent')
}提供数据
this.$bus.$emit('customEvent', 数据)
1.23 消息订阅与发布
实现任意组件间通信
pubsub.js实现消息订阅与发布
接收方:订阅
1 |
|
发布方
1 |
|
1.24 ajax配置代理