文章目录
入门呢案例分析
<div id="app">
<h1>你好,我是{{name}}</h1>
</div>
<script>
// Vue.config.productionTip = false;
const x = new Vue({
el: '#app', //el指定当前Vue为实例化哪个对象
data() {
return {
name: '张三',
age: 20
};
},
});
</script>
//分析,一个容器交给一个vue实例去处理,他们之间的关系是一一对应,他们分别对应第一个
//{{}}之间可以写入的是什么,{{}}里边只可以写js代码0】
//(1)表达式 a a+b x==y?'a':'b'
//(2)js代码 if(){} for(){}
总结
- Vue实例和容器时一一对应的关系,并且会配合着组件一起使用
- {{xxx}}中的xxx要写js表达式,且xxx可以自动读取data中的所有属性;
- 一旦data中的数据发生改变,那么模板中用到该数据的地方也会自动更新
模板语法
Vue模板语法分为2大类:
- 插值语法
- 功能:用于解析标签体内容
- 写法:{{xxx}},xxx时js表达式,而且可以直接读取到data中所有属性
- 指令语法
- 功能:用于解析标签(包括啊:标签属性,标签内容,绑定事件)
- 举例:v-bind:href=“xxx“简写为:href=“xxx”,xxx同样要写js表达式,且可以直接读取道data中的所有属性
- 备注:Vue中有很多的指令,且形式都是v-???开头,在此举得例子时v-bind
数据绑定
<div id="root">
单向绑定:<input type="text" v-bind:value="school.name">
双向绑定:<input type="text" v-model:value="school.name">
简写
单向绑定:<input type="text" :value="school.name">
双向绑定:<input type="text" v-model="school.name">
</div>
<script>
// Vue.config.productionTip = false;
const x = new Vue({
el: '#root', //el指定当前Vue为实例化哪个对象
data() {
return {
uname: '张三',
age: 20,
url: "https://www.baidu.com/",
school: {
name: '河南科技学院'
}
};
},
});
</script>
Vue中有两种数据绑定
- 单向绑定(v-bind):数据只能重data流向页面
- 双向绑定(v-model):数据不仅可以从data流向页面,还可以从页面流向data
- 备注
- 双向绑定一般用在表单类元素上(如:input,select等)
- v-model:value可以简写成v-model,因为v-model默认收集的就是value值
- 备注
el与data的两种写法
-
el有两种写法
- .new Vue时配置el属性
- 先创建Vue实例,随后再通过vm.$mount(‘#app’)指定el的值
-
data有两种写法
-
对象式
-
函数式
如何选择:目前用哪种都可以,在学习函数组件时,data必须要用函数式,否则会报错
-
-
一个重要原则
由Vue管理的函数一定不要用箭头函数,箭头函数没有自己的this
MVVM模型
- M:模型(Model)
- V:视图(View)
- VM:视图模型(ViewModel):Vue实例对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YT8rVA4B-1666772187950)(img/image-20220906213326911.png)]
数据代理
let number = 13;
let person = {
name: '张三',
sex: '男',
adress: '郑州'
}
Object.defineProperty(person, 'age', {
// value: 19,
// enumerable: true, //控制属性是否可可以枚举,默认值式false
// writable: true, //控制属性是否可以被修改,默认值式false
// configurable: true //控制属性是否被删除
//get函数,当读取person的age属性时,get函数自动会被调用
get() {
return number
},
//set函数,当修改person的age属性时,set函数自动会被调用
set(value) {
number = value;
console.log('有人修改了person的age值是' + value);
}
})
console.log(person);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CmqzKqIH-1666772187951)(img/image-20220907092507149.png)]
- 将obj2添加属性x,值为objx的值,当修改obj2的值时自动修改obj中的x值
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nH42stzQ-1666772187952)(img/image-20220907153424087.png)]
事件处理
<div id="app">
<h1>开始练习</h1>
<button @click="showInfo1">点我提示信息(不传参)</button>
<!-- 采用占位符号$ -->
<button @click="showInfo2(18,$event)">点我提示信息(传参)</button>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
property: 'value',
};
},
methods: {
showInfo1(event) {
console.log(event.target);
},
showInfo2(number, e) {
console.log(number, e.target);
}
}
})
</script>
事件的基本使用
- 使用v-on:xxx或者@xxx绑定事件,其中xxx时事件名
- 时间的回调需要配置子methods中,最总会在vm中
- methods中配置的函数不要使用箭头函数!否则this就不是vm了
- methods中配置的函数,都是被Vue所管理的函数,this的指向时vm或者组件实例对象
- @click="demo"和@click="demo($event)"效果是一样的,但后者可以传参
Vue中事件的修饰符
Vue常用的事件修饰符,修饰符可以连续写
- prevent:阻止默认事件(常用)
- stop:阻止事件冒泡(常用)
- once:事件只触发一次
- capture:使用事件捕获模式
- self:只有event.target是当前操作的元素时才触发事件
- passive:事件的默认行为立即执行,无需等待回调函数执行完毕
<div id="app">
<h1>开始练习</h1>
<!-- 阻止事件默认行为,a标签的默认行为是跳转 -->
<a href="http://www.baidu.com" @click.prevent="a">点我进行页面跳转</a>
<!-- 阻止事件冒泡 -->
<div class="box1" @click.stop="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
</div>
</div>
<!-- 事件只触发一次 -->
<div id="demo" @click="showInfo">
<button @click.once="showInfo">点击触发事件</button>
</div>
<!-- 使用事件捕获模式 -->
<div class="box1" @click.="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
</div>
</div>
<!-- 使用事件捕获模式 -->
<div class="box1" @click.capture="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
</div>
</div>
<!-- 点击div1才触发 -->
<div class="box1" @click.self="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
</div>
</div>
<!-- 两种滑动滚轮的方式,scroll和wheel;
scoll默认事件和回调函数一起执行
wheel是执行回调函数后执行默认事件
-->
<ul class="ull" @scroll="move">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
property: 'value',
};
},
methods: {
a() {
alert('我可以跳转到百度')
},
showInfo(event) {
alert('Hello World ')
},
showMsg(number) {
alert('输出的值是' + number)
},
move() {
console.log('滚动了');
}
}
})
</script>
键盘事件
<div id="app">
<h1>开始练习</h1>
<input type="text" placeholder="按下回车提示输入信息" @keyup.enter="showInfo">//事件按键,只有按下回车键才会触发
</div>
<script>
new Vue({
el: '#app',
data() {
return {
property: 'value',
};
},
methods: {
showInfo(e) {
console.log(e.key, e.keyCode);
}
}
})
</script>
Vue中常见的按键别名:
回车(enter)
删除(delete)
退出(esc)
空格(space)
换行(tab)
上(up)
下(down)
左(left)
右(right)
计算属性
<div id="app">
<h1>开始练习</h1>
姓:<input type="text" v-model="fistName"><br/><br/> 名:
<input type="text" v-model="lastName"><br/><br/> 全名:
<span>{{fullName}}</span>
</div>
<script>
const vm = new Vue({
el: '#app',
data() { //只要data中的数据改变,vue一定会重新解析模板
return {
fistName: '张',
lastName: '三'
};
},
// 计算属性
computed: {
fullName: {
//get有什么用,当有人调用或者修改fullName中的属性时会调用
get() {
console.log('get被调用了');
return this.fistName + '-' + this.lastName;
},
//当修改fullName属性时,set方法被调用
set(value) {
console.log('set方法被调用');
let arr = value.split('-');
this.fistName = arr[0];
this.lastName = arr[1];
}
}
}
})
</script>
计算属性:
- 定义:要用的属性不存在,要通过已有的属性计算得来
- 原理:底层借助了Objcet.defineproperty方法提供的getter和setter
- get函数什么时候执行?
- 当读取时会执行一次
- 当依赖的数据发生改变时会被再次调用
- 优势:与methods相比,内部有缓存机制(复用),效率高,调试方便
- 备注:
- 计算属性终会出现在vm上,直接读取使用即可(不能读取其中的get方法)
- 如果计算属性要被修改,那必须写set函数去影响修改,且set中要引起计算时以来的数据发生改变
监视属性
<div id="app">
<h1>开始练习</h1>
<h2>今天天气很{{weather}}</h2>
<button @click="changWeather">点击我更改天气</button>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
isHot: true
}
},
computed: {
weather: function() {
return this.isHot ? '炎热' : '凉爽'
}
},
methods: {
changWeather() {
this.isHot = !this.isHot
}
},
//配置监视,完整形式
watch: {
//当isHot别修改时触发函数
isHot: {
immediate:true,//初始化时让handler调用一下
deep:true,//深度监视
handler() {
console.log('isHot被修改了');
}
}
}
//简写监视
watch: {
//如果配置项中只有handler,可以用简写
isHot(newValue,oldValue){
console.log('isHot被修改了');
}
}
})
</script>
监视属性watch:
- 当监视的属性发生变化时,回调函数自动调用,进行相关操作
- 监视的属性必须存在,才能进行监视!!
- 监视的两种写法:
- new Vue时传入watch配置
- 通过vm.$watch监视
深度监视
<div id="app">
<h1>开始练习</h1>
<h2>
a的值是:{{number.a}}
</h2>
<button @click="number.a++">点我让a++</button>
<h2>
b的值是:{{number.b}}
</h2>
<button @click="number.b++">点我让b++</button>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
number: {
a: 1,
b: 2
}
}
},
//配置监视
watch: {
//当isHot别修改时触发函数
'number.a': {
//监视多级结构中所有属性的变化
deep: true,
handler() {
console.log('a改变了');
}
}
}
})
</script>
深度监视:
- vue中watch默认不见时对象内部的改变(一层)
- 配置的deep:true可以监视对象内部值的改变
备注:
- vue自身可以监视对象内部值的改变,但Vue提供的watch默认不可以
- 使用warch时根据数据的具体结构,决定是否采用深度监视
computed 和 watch之间的区别:
- computed能完成的功能,watch都能够完成
- watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作
两个小原则:
- 所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或者组件实例对象
- 所用不被Vue所管理的函数(定时器的回调函数,ajax的回调函数等,Promise的回调函数),最好写成箭头函数,这样this的指针才能是vm或者组件实例对象
绑定样式
<div id="app">
<h1>开始练习</h1>
<input type="text" :value="fullName"><br>
<button @click="changMood">点击更换姓名</button>
<!--class绑定样式字符串法,适用于:样式的类名不确定,需要动态指定 -->
<div class="basic" :class="color" @click="changeColor">点击更换颜色</div>
<!-- class绑定样式数组法,适用于要绑定的个数不确定,名字也不确定 -->
<div class="basic" :class="arr" >更换颜色</div>
<!-- class绑定样式对象法,适用于要绑定的个数不确定,名字也不确定 -->
<div class="basic" :class="classObj" >更换颜色</div>
<!-- style绑定样式对象法,适用于要绑定的个数不确定,名字也不确定 -->
<div class="basic" :style="styleObj" >更换颜色</div>
</div>
<script>
const vm = new Vue({
el: '#app',
data() {
return {
fullName: '张三',
color: 'normal',
arr: ['style1', 'style2', 'style3'],
classObj: {
style1: false,
style2: false
},
styleObj: {
//根据系统的改变,系统的有font-size等
fontSize: '50px',
backgroundColor: 'yellow',
fontColor: 'gray'
}
}
},
methods: {
changMood() {
this.fullName = '王五'
},
changeColor() {
const arr = ['happy', 'sad', 'normal']
let index = Math.floor(Math.random() * 3)
this.color = arr[index];
},
}
})
</script>
条件渲染
<div id="app">
<h1>开始练习</h1>
<h2>a={{a}}</h2>
<button @click="a++">点击我实现a++</button>
<h2 v-show="false">我来自{{adress}}1</h2>
<!-- 中间结构不能够打断 -->
<h2 v-if="a==1">第一</h2>
<h2 v-else-if="a==2">第二</h2>
<h2 v-else-if="a==3">第三</h2>
<h2 v-else>第四</h2>
<!-- template只能和v-if配合使用 -->
<template v-if="n==1">
<h3>北京</h3>
<h3>上海</h3>
<h3>广州</h3>
</template>
</div>
<script>
const vm = new Vue({
el: '#app',
data() {
return {
adress: '河南省',
a: 0
}
},
})
</script>
- v-if
- v-if;v-else-if;v-else;中间不能够打断
- 适用于切换频率不高的场景
- 特点:不展示DOM元素(如果为false,页面没有)
- v-show
- 写法:v-show="“表达式”
- 适用于切换频率不高的场景
- 特点:不展示DOM元素,仅仅是使样式隐藏掉
react、vue、中的key什么用
-
虚拟DOM中key的作用
- key是DOM的对象标识,当数据发生改变时vue会根据【新数据】生成【新的虚拟DOM】
-
新虚拟DOM与旧虚拟DOM对比原则
- 旧的虚拟DOM找新虚拟DOM相同的key:
- 若虚拟DOM没有内容变化,直接使用之前的真实DOM
- 若虚拟DOM内容改变了,则生成新的真实DOM,随后替换页面中之前的真实DOM
- 旧的DOM未找到新虚拟DOM相同的key
- 创建新的真实DOM,让后渲染页面
- 旧的虚拟DOM找新虚拟DOM相同的key:
-
用index和key可能引发的问题
-
若对数据进行:逆序添加、逆序删除等破坏顺序的操作:
会产生没有必要的真实DOM更新==>界面效果没问题,但效率低
-
如果结构还包含输入类的DOM:
会产生错误DOM更新==》界面有问题
-
-
开发中如何选用key?
- 最好使用每条数据的唯一标识作为key,如id,手机号,身份证号码,学号等唯一标识
列表排序
<div id="app">
<h1>开始测试</h1>
<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="p in filPersons">
{{p.name}}--{{p.age}}
</li>
</ul>
</div>
<script>
new Vue({
el: '#app',
data() {
return {
keyWord: '',
sortType: 0,
persons: [
{id: '001',name: '周杰伦',age: 23},
{id: '002',name: '张望伦',age: 18},
{id: '003',name: '张三丰',age: 35},
{id: '003',name: '周找天',age: 19}
],
}
},
//computed实现
computed: {
filPersons() {
const arr = this.persons.filter((p) => {
return p.name.indexOf(this.keyWord) != -1
})
if (this.sortType) {
arr.sort((p1, p2) => {
return this.sortType == 2 ? p1.age - p2.age : p2.age - p1.age
})
}
return arr
}
},
})
</script>
Vue监测数据原理
数据更改==》set()调用,set里写了个调用重新解析模板==》生成新的虚拟DOM==》新旧虚拟DOM对比==》生成真实页面
Vue数据监视
-
vue会监视data中所有层次的数据
-
如何仅是对象中的数据
- 通过setter实现监视,要在 new Vue时加入监视的数据
- 对象中后追加的属性,Vue默认不做处理
- 如果给后添加的属性做响应式,使用API
- Vue.set(target, propertyName, value) Vue.set(this.student, ‘sex’, ‘男’)
- vm. s e t ( t a r g e t , p r o p e r t y N a m e , v a l u e ) t h i s . set(target, propertyName, value) this. set(target,propertyName,value)this.set(this.student, ‘sex’, ‘男’)
- 通过setter实现监视,要在 new Vue时加入监视的数据
-
如何检测数组中的数据
通过包裹数组更新元素的方式实现
- 调用原生对应的方法对数组进行更新
- 重新解析模板,进行更新页面
-
Vue中修改数组中某个元素一定用到如下方法:
API:push(),pop(),shift(),unshift(),splice(),sort(),reverse()
Vue.set()或者vm.$set()
收集表单数据
<div id="app">
<form @submit.prevent="demo">
<label for="account">账号</label><input type="text" id="account" v-model.trim="account">
<label for="ps">密码</label><input type="text" id="ps" v-model="password">
<label for="age">年龄</label><input type="number" id="age" v-model.number="age">
性别:
男<input type="radio" name="sex" value="male" v-model="sex">
女<input type="radio" name="sex" value="female" v-model="sex">
爱好:
学习<input type="checkbox" v-model="hobby" value="study">
打游戏<input type="checkbox" v-model="hobby" value="game">
吃饭<input type="checkbox" v-model="hobby" value="eat">
所属校区
<select v-model="city">
<option value="beijing" >北京</option>
<option value="shenzhen" >深圳</option>
<option value="wuhan" >武汉</option>
</select><br><br> 其他信息
<textarea v-model.lazy="other"></textarea>
<input type="checkbox" v-model="agree">
阅读并接受<a href="http://www.baidu.com">《用户协议》</a>
<button>提交</button>
</form>
</div>
<script>
const vm = new Vue({
el: '#app',
data() {
return {
account: '',
password: '',
age: '',
sex: '',
hobby: [],
city: 'beijing',
other: '',
agree: ''
}
},
methods: {
demo() {
console.log(JSON.stringify(this._data));
}
},
})
</script>
-
若: , 则v-model收 集的是value值,用户输入的就是value值。
-
若: , 则v-model收 集的是value值,且要给标签配置value值。
-
若:
1.没有配置input的value属性,那么收集的就是checked (勾选or未勾选,是布尔值)
2.配置input的value属性:
-
(1 )v - model的初始值是非数组,那么收集的就是checked (勾选or未勾选,是布尔值)
-
(2 )v- model的初始值是数组,那么收集的的就是value组成的数组
备注: v-model的 三个修饰符:
-
lazy:失去焦点再收集数据
-
number:输入字符串转为有效的数字
-
trim:输入首尾空格过
-
v-指令
v-once
-
v-once在初次动态渲染后就视为静态内容了
-
以后数据的改变不会引起v-once所在结构的更新
v-pre
-
v-pre可以跳过节点的编译过程
-
可以用它跳过:没用使用指令的语法,没用使用插值的语法节点,会加快编译
自定义指令
-
需求1:定义一个v-big指令, 和v-text功能类似,但会把绑定的数值放大10倍。
-
需求2:定义-一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
-
自定义指令总结:
定义语法:
-
局部指令:
new Vue({ directives:{指令名:配置对象} })//或者 new Vue({ directives:{指令名,回调函数} })//或者
2.全局指令:
Vue.directive(指令名,配置对象)或Vue . directive(指令名,回调函数)
-
-
配置对象中常用的3个回调:
- .bind:指令与元素成功绑定时调用。
- .inserted:指令所在元素被插入页面时调用。
- .update:指令所在模板结构被重新解析时调用。
-
备注:
- .指令定义时不加心,但使用时要)加Iv-;
- 指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
Vue生命周期
div id="app">
<h1>当前数字是:{{n}}</h1>
<button @click="n++"></button>
</div>
<script>
const vm = new Vue({
el: '#app',
//vue完成真实的解析并把真实的DOM元素放入页面之后,调用mounted
data() {
return {
n: 1,
}
},
beforeCreate() {
console.log('beforeCreate')
},
created() {
console.log('created')
},
beforeMount() {
console.log('beforeMount')
},
mounted() {
console.log('mounted', this);
},
//数据和页面未保持同步
beforeUpdate() {
console.log('beforeUpdate');
},
updated() {
console.log('updated');
},
//数据所做的所有操作不做更新
beforeDestroy() {
console.log('beforeDestroy');
},
destroyed() {
console.log('destroyed');
},
})
</script>
常用的生命周期函数
- mounted:发送ajax请求,启动定时器,绑定自定义事件,订阅消息等【初始化操作】
- beforeDestory:清除定时器,绑定自定义事件,取消订阅消息【收尾工作】
关于销毁Vue实例
- 销毁后借助Vue的开发工具不会有任何信息
- 销毁自定义事件会失效,但原生DOM事件依然有效
- 一般不会在beforeDestroy操作数据,但即使操作了,也不会触发更新流程
非单文件组件
基本使用
Vue中使用组件的三大步骤
- 定义组件
- 注册组件
- 使用组件
-
如何定义一个组件
- 使用Vue.extend(options)创建,其中options和 new Vue(options)时传入的那个options几乎一样,但也有点不同:
- el不要写,为什么?最终所有的组件都要经过一个vm管理,有vm中的el决定哪一个服务器
- data必须写成函数,为什么?避免组件被复用时,数据存在引用的关系
- 使用tmplate可以配置组件结构
- 使用Vue.extend(options)创建,其中options和 new Vue(options)时传入的那个options几乎一样,但也有点不同:
-
如何注册组件?
- 局部注册:靠new Vue的时候传入components选型
- 全局注册:靠Vue.component(‘组件名’,组件)
-
编写组件标签
<div id="app1"> <h1>{{msg}}</h1> <hr> //第三步,调用组件 <xuexiao></xuexiao> <hr> <div id="app2"> <hello></hello> </div> </div> <script> //第一步,定义组件 const school = Vue.extend({ template: ` <div> <h2>学校名称:{{schoolName}}</h2> <h2>学校地址:{{address}}</h2> <button @click="showName">惦记我提示学校名称</button> </div> `, data() { return { schoolName: '科技学院', address: '新乡', } }, }) //全局注册组件 Vue.component('hello', hello) new Vue({ el: '#app1', data() { return { msg: '你好啊' } }, components: { //第二步,配置组件 xuexiao: school, } }) </script>
组件注意事项
- 关于组件名称
- 一个单词写法
- 第一种首字母小写:school
- 第二种首字母大写:School
- 多个单词组成
- 第一种写法(kebab-case命名):my-school
- 第二种写法(CameCase命名):MySchool(需要用Vue脚手架支持)
- 备注
- 组件名尽可能回避HTML中已有的元素名称:例如H1,H2
- 可以使用name配置项指定组件在开发者工具中呈现的名字
- 一个单词写法
- 过于组件的标签
- 第一种写法:
- 第二种写法:
- 备注:不适用脚手架,会导致后续组件不能渲染
- 组件定义简写
组件的嵌套
<div id="app1">
<app></app>
</div>
<script>
const student = {
name: 'student',
template: `
<div>
<h2>学生姓名:{{studentName}}</h2>
</div>
`,
data() {
return {
studentName: '小明',
}
},
}
const school = Vue.extend({
template: `
<div>
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<hr>
<student></student>
</div>
`,
data() {
return {
schoolName: '科技学院',
address: '新乡',
}
},
components: {
student,
}
})
const app = Vue.extend({
template: `
<div>
<school></school>
</div>
`,
components: {
school
}
})
new Vue({
el: '#app1',
data() {
return {
msg: '你好啊'
}
},
components: {
//school:school
app
}
})
</script>
VueComponnet
-
school组件的本质时一个名为VueComponent的构造函数,且不是程序员定义的,时Vue.extend生成的
-
我们只需要写或者,Vue解析时会帮助我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)
-
特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!
-
关于this的指向
-
组件配置中:
data函数,methods中的函数,watch中的函数,computed中的函数 他们的this是VueComponent实例对象
-
new Vue()配置中
data函数,methods中的函数,watch中的函数,computed中的寒素,他们的this是Vue实例对象
-
-
vueComponent实例对象,简称vc
原型与原型链
class Student {
constructor(name, score) {
this.name = name;
this.score = score;
}
introduce() {
console.log(`我是${this.name},考了${this.score}分。`);
}
}
const student = new Student('张三', '99');
console.log(student.__proto__ === Student.prototype);
实例对象(student)的隐式原型对象 === 构造函数(Student)的显示原型对象
统统指向原型对象
一个重要的内置关系
vue.component.prototype.(proto)==Vue.prototype
结论:让VueComponent的实例对象(vc)可以使用Vue原型上的属性和方法
单文件组件
<template>
<div class="demo">
<!-- 组件的结构 -->
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showName">惦记我提示学校名称</button>
</div>
</template>
<script>
//组建的交互样式
//三种暴漏方式
/* 1,export--分别暴漏,前加 */
// const school = Vue.extend({
// data () {
// return {
// schoolName: '科技学院',
// address: '新乡',
// }
// },
// methods: {
// showName () {
// alert(this.schoolName)
// }
// },
// })
//export{}2,统一暴漏
/* 3,默认暴漏,多数使用 */
// export default school
export default {
name: 'School',
data () {
return {
schoolName: '科技学院',
address: '新乡',
}
},
methods: {
showName () {
alert(this.schoolName)
}
},
}
</script>
<style>
/* 样式的注释 */
.demo {
background-color: skyblue;
}
</style>
render函数
Vue.config.productionTip = false
//使用vue的插件
new Vue({
el: '#app',
render: h => h(App),
// render :q =>q('h1','你好啊')
// render :createElentment =>createElement('h1','你好啊')
// render :createElentment =>{
// return createElement('h1','你好啊')
// }
// render(createElement){
// return createElement('h1','你好啊')
// }
})
组件自定义事件
-
一种通信的方式:适用于子组件传给父组件
注意:父传子props最方便
-
使用场景:A是父组件,B是子组件,B想给A传数据那么需要在A中给B绑定自定义事件
-
绑定自定义事件:
-
第一种方式,父组件中:<Demo @haha=“test”>
-
第二种方式,在父组件中
<School ref="school" /> mounted () { this.$refs.school.$on('dizhi', this.sendSchoolAddress) },
-
若想让自定义事件只触发一次可以用once修饰符,或者$once方法
-
-
出发绑定事件:this.$emit(‘haha’,数据)
-
解除绑定自定义事件this.$off(‘haha’)
-
组件想使用原生的DOM事件(指原有的事件例如@click)需要使用native修饰符
全局事件总线
-
安装全局事件总线
//在main文件中 new Vue({ el: '#app', render: h => h(App), /* 在vue的实例对象对象上放置一个$bus来作为传输数据的对象 $bus书写规范 */ beforeCreate() { Vue.prototype.$bus = this; //在vue的实例对象对象上放置一个$bus来作为传输数据的对象 }, })
-
使用全局时间总线
//绑定这个时间 methods(){ this.$bus.$emit('changeTodo', id) } //使用这个时间 mounted(){ this.$bus.$on('changeTodo', this.demo) }
消息订阅与发布
-
安装第三方库 npm i pubsub-js
-
引入: import pubsub from ‘pubsub-js’
//发送数据 sendStudentAge () { pubsub.publish('hello', 666) }, //订阅(接受)数据 mounted () { pubsub.subscribe('hello', (a, b) => { console.log('我是订阅函数,它的数据是' + a, b); console.log(this); }) },
Vue动画
-
元素准备样式
-
元素进入
v-enter:进入的起点
v-enter-active:进入的过程
v-enter-to:进入的终点
-
元素的离开
v-leave:进入的起点
v-leave-active:进入的过程
v-leave-to:进入的终点
-
-
使用包裹过度的元素,并经行name配置
-
如果有多个元素需要过度,则需要用,且每哥元素需要用key指定
配置代理
在vue.config.js中添加如下配置
devServer: {
proxy: {
'/api': {//匹配有所以'/api'开头的路径
target: 'http://localhost:8081',//代理请求的端口
pathRewrite:{'^/api':''}//将第一个匹配的标识改为空
ws: true,
changeOrigin: true //告诉请求地址自己的路径,true代表和他的路径一样
},
'/foo': {
target: '<other_url>'
}
}
}
插槽
在标签内部放入内容(默认插槽)
//输入内容
<template>
<div class="contain">
//当需要指定位置的时候需要定义插槽标签
<Category solt="center" title="美食" :listData="foods">
<input type="text" value="我是小李子" />
</Category>
</div>
</template>
//告诉放置的位置,在Category中
<template>
<div class="card">
<h2>{{ title }}</h2>
<ul>
<li v-for="(item, index) in listData" :key="index">
{{ item }}
</li>
//定义插槽的名称,一一对应
<slot name="center"></slot>
</ul>
</div>
</template>
作用域插槽
在components中
<template>
<div class="card">
<h2>{{ title }}</h2>
<ul>
<li v-for="(item, index) in listData" :key="index">
{{ item }}
</li>
//从插槽中向调用插槽的传递数据
<slot :games="games"></slot>
</ul>
</div>
</template>
<script>
export default {
name: 'Category',
data() {
return {
games:['游戏1','游戏2','游戏3']
}
},
props: ['title', 'listData']
}
</script>
调用插槽者
<template>
<div class="contain">
<Category title="美食" :listData="foods">
<template scope='data'>//新版版为slot-scope
<ul>
<li v-for=" (g,index) in data.games" :key="index"></li>
</ul>
</template>
</Category>
</div>
</template>
创建Vue脚手架
- 下载node.js
- 配置淘宝镜像
##窗口执行
npm install -g @vue/cli
Vue中的配置对象(以pages举例)
module.exports = {
pages: {
index: {
// page 的入口
entry: 'src/index/main.js',
// 模板来源
template: 'public/index.html',
// 在 dist/index.html 的输出
filename: 'index.html',
// 当使用 title 选项时,
// template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title: 'Index Page',
// 在这个页面中包含的块,默认情况下会包含
// 提取出来的通用 chunk 和 vendor chunk。
chunks: ['chunk-vendors', 'chunk-common', 'index']
},
// 当使用只有入口的字符串格式时,
// 模板会被推导为 `public/subpage.html`
// 并且如果找不到的话,就回退到 `public/index.html`。
// 输出文件名会被推导为 `subpage.html`。
subpage: 'src/subpage/main.js'
}
}
ref属性
-
别用来给元素或子组件注册引用的信息(id的替换者)
-
应用在html标签上获取的真实DOM元素,应用在组件标签上的组件实例对象(vc)
-
使用方式
打标识:
…
或者…****获取:this.$refs.xxx
<template>
<div>
<h1 ref="title">点我展示上方元素</h1>
<button @click="showDom">展示上方元素</button>
<Add ref="add"></Add>
</div>
</template>
<script>
import Add from './components/Add'
export default {
name: 'App',
components: { Add },
methods: {
showDom () {
console.log(this.$refs.title);
console.log(this.$refs);
console.log(this.$refs.add);
}
},
}
</script>
props属性
//-------定义组件
<template>
<div>
<!-- 组件的结构 -->
<h1>我的个人信息是</h1>
<h2>学生名称:{{ name }}</h2>
<h2>学生年龄:{{ age }}</h2>
<h2>学生学校:{{ school }}</h2>
·
</div>
</template>
<script>
export default {
name: 'student-name',
// props: ['name', 'age', 'school'],第一种
/*第二种
props: {
name: String,
age: Number,
school: String
}, */
//对接受数据的同时对数据进行限制
props: {
name: {
type: String,//类型String
required: true,//必须要填写
},
age: {
type: Number,
default: 99
},
school: {
type: String,//类型String
required: true,//必须要填写
}
},
}
</script>
//----------使用组件
<template>
<div>
<student-name name="李华" :age="15" school="科技学院"></student-name>
</div>
</template>
<script>
import StudentName from './components/Student.vue'
export default {
name: 'App',
components: {
'student-name': StudentName
}
}
</script>
功能:让组件接受外部传入的数据
备注:props是只读属性,Vue底层会检测你对props的修改,如果进行了修改,就会发出警报,若业务需要对数据的修改,那么请复制props的内容一份送到data中,让后去修改data中的数据
mixin(混入)
-
功能:可以把多个组件共有的配置提供成一个混入对象
-
使用方式:
第一步定义混合 { data(){ }, methods:{ } } 第二步使用混入 (1)全局的混入,Vue.mixin(xx) (2)局部的混入,mixins:['xxx']
//定义 export const m = { methods: { showName() { alert(this.name) } }, mounted() { console.log('你好啊') }, }
//使用 <script> import { m,number } from "../mixin" export default { name: "xue-xiao", data () { return { // 传入的值不能修改 name: "科技学院", address: "新乡市", } }, mixins: [m,number] }; </script>
plugin(插件)
-
功能:用于增强Vue
-
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传入的数据。
定义插件:
export default { //shi'yong'hsi install(Vue, x) { console.log(x);//传入的参数,可以是多个 Vue.filter('mySlice', function(value) { return value.slice(0, 5) }) Vue.directive('fbind', { }) //Vue混入方法 Vue.mixin({ }) Vue.prototype.hello = () => { } } }
使用插件
scoped样式
- 多个模块中样式,当渲染时会进行汇总,此时如果模块中出现重复的样式名称则会冲突,代码采用就近原则按照后带入的为主
- 作用:让样式是在局部生效,防止冲突
- 写法>
vuex
概念:专门在Vue中实现集中式状态管理的一个Vue插件,对vue应用中多个组件的共享进行集中式的管理(读与写),依旧是一种通信的方式,且适用于任意组件间的通信
什么时候用(共享)
- 多组件依赖于同一个状态
- 来自不同组件的行为需要变更为同意状态
路由
-
使用路由
//在main.js中 import VueRouter from 'vue-router' import router from './router/index'//引入路由配置文件 Vue.use(VueRouter) new Vue({ el: '#app', render: (h) => h(App), router: router, //!!!!! beforeCreate() { Vue.prototype.$bus = this; } })
-
配置路由(也可以用懒加载的方式)
import VueRouter from 'vue-router' export default new VueRouter({ routes: [ {//路由重定向 path: '/', redirect: '/Login/User' }, { path: '/Login', name: 'Login', component: Login, children: [{//子路由 path: 'User', component: User }, { path: 'Register',//注意这里没有'/' component: Register }, ] }, { path: '/Todo/:name', name: 'Todo', component: Todo, }, ] })
-
路由标签
<router-link to="/Login/User" class="select" active-class="active">登录区</router-link\> //标签最后会被解析为a标签 //to为跳转的路径 //active-class为选中当前路径标签所具有的样式 <router-view></router-view> //可以展示选中标签中的nei'rong
-
传递参数
Params传参 //一、声明式 //子路由配置 { path: '/child/:id', component: Child } //父路由组件 <router-link :to="/child/123">进入Child路由</router-link> //二、编程式 //子路由配置 { path: '/child/:id', component: Child } //父路由编程式传参(一般通过事件触发) this.$router.push({ path:'/child/${id}',//这里是es6表达方式 }) //三、对象传递(这种方式地址中不显示参数) <router-link :to="{name:'Child',params:{id:123}}">进入Child路由</router-link> //获取 {{this.$route.params.id}}
query传参 //这种传参不需要更改路由配置 //一、声明式 { path: '/child', component: Child } <router-link :to="{path:'/child',query:{id:123}}">进入Child路由</router-link> //二、编程式 this.$router.push({ name:'Child', query:{ id:123 } }) //获取参数 {{this.$route.query.id}}
-
注意对象传参中path配query; name配params;!!!否则接收不到参数
-
即使用params参数时,若使用to对象写法,则不能使用path配置项,必须使用name配置
-
路由的两个钩子函数
//路由仅有的两个钩子 //当路由组件激活的时候触发(从没有到有) activated(){} //当路由组件失活的时候触发(从有到没有) deactivated(){}
路由器的两种工作模式
-
对于一个url来说什么是hash值?——#以及后必拿的内容时hash值
-
hash值不会包含在http请求中,即:hash值不会带给服务器
-
hash模式:
- 地址永远带着#号,不带美观
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
- 兼容性较好
-
history模式:
-
地址干净,美观
-
兼容性和hash模式相比略差
-
应用部署上线时需要后端人员支持,解决页面服务器404的问题
}, { path: '/Todo/:name', name: 'Todo', component: Todo, },
]
})
-
-
路由标签
<router-link to="/Login/User" class="select" active-class="active">登录区</router-link\> //标签最后会被解析为a标签 //to为跳转的路径 //active-class为选中当前路径标签所具有的样式 <router-view></router-view> //可以展示选中标签中的nei'rong
-
传递参数
Params传参 //一、声明式 //子路由配置 { path: '/child/:id', component: Child } //父路由组件 <router-link :to="/child/123">进入Child路由</router-link> //二、编程式 //子路由配置 { path: '/child/:id', component: Child } //父路由编程式传参(一般通过事件触发) this.$router.push({ path:'/child/${id}',//这里是es6表达方式 }) //三、对象传递(这种方式地址中不显示参数) <router-link :to="{name:'Child',params:{id:123}}">进入Child路由</router-link> //获取 {{this.$route.params.id}}
query传参 //这种传参不需要更改路由配置 //一、声明式 { path: '/child', component: Child } <router-link :to="{path:'/child',query:{id:123}}">进入Child路由</router-link> //二、编程式 this.$router.push({ name:'Child', query:{ id:123 } }) //获取参数 {{this.$route.query.id}}
-
注意对象传参中path配query; name配params;!!!否则接收不到参数
-
即使用params参数时,若使用to对象写法,则不能使用path配置项,必须使用name配置
-
路由的两个钩子函数
//路由仅有的两个钩子 //当路由组件激活的时候触发(从没有到有) activated(){} //当路由组件失活的时候触发(从有到没有) deactivated(){}
路由器的两种工作模式
- 对于一个url来说什么是hash值?——#以及后必拿的内容时hash值
- hash值不会包含在http请求中,即:hash值不会带给服务器
- hash模式:
- 地址永远带着#号,不带美观
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
- 兼容性较好
- history模式:
- 地址干净,美观
- 兼容性和hash模式相比略差
- 应用部署上线时需要后端人员支持,解决页面服务器404的问题