对应模式:MVVM(以异步通信为主) : Model, View, ViewModel。
Vue:采用插值语法。
Vue对应的cdn为下:
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
内置指令
v-pre:使Vue跳过解析。
v-once:只会读取一次数据,且v-once没有值。
v-cloak: 当网速过慢时,可以使未经解析的模板不显示在页面上。
[v-cloak]{
display: none;
}
<p v-cloak>{{data}}</p>
v-html:类似v-text,但是v-html支持结构的解析,也就是可以解析标签字符串。
v-text:向其所在的标签插入文本。(会替换掉标签中的内容,所以在标签中写内容是无效的)
v-bind:title : 可以将vue中的值显示在对应的字体上。(鼠标悬停在字体上时显示数据)
v-if ,v-else : 判断。
v-for : v-for="(item, index) in item"。(类似python的循环, item表示遍历到的项,index表示下标),且必须给每个item配置一个:key,如果没有写key的话,v-for会将遍历时的index作为:key的值。(类似SQL中的主键)
v-bind:"data" : 表示动态绑定,value为""中data的运行结果。
key的作用:
使用:key时的特殊例子:
使用数组的index作为唯一标识时,使用头插法的话会打乱原本的顺序,从而影响效果。
而在使用id作为唯一标识时,就不会影响效果了。
v-model :实现双向绑定。(此方法只适用于表单元素上,也就是只适用于输入类元素上)
:style:绑定style,且对应的值是对象形式的。
v-show:条件渲染。(true表示显示,false表示不显示),且v-show不能配合template使用。
双向绑定<input type="text" v-model:value="name"/>
双向绑定<input type="text" v-model="name"/>
//两者是等价的,可以省略绑定的参数名
el:的替代写法为下:
var v = new Vue();
v.$mount("#id");
data:的替代写法为下:
data: function(){
return {
name: value
}
}
自定义指令
例子为下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/dayjs/1.10.6/dayjs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
</head>
<body>
<div id="root">
<p>{{n}}</p>
<button @click="add">n++</button>
<p v-big="n"></p>
</div>
</body>
<script>
var vm = new Vue({
el: '#root',
data: {
n: 0
},
methods: {
add(){
this.n++
}
},
directives:{
big(el, binding){
//el表示标签,binging表示绑定的值对象
el.innerText = binding.value * 10
}
}
})
</script>
</html>
自定义指令被调用的情况:
- 指令与元素成功绑定时。
- 指令所在的模板重新被解析时。
自定义局部指令的格式为下:
directives:{
fbind: {
//指令和元素绑定成功时调用
//默认时就表示以个bind函数
bind(el, binding){
el.value = binding.value
},
//指令所在元素被插入页面时调用
inserted(el, binding){
el.focus()
},
//指令所在的模板被重新解析时调用
update(el, binding){
el.value = binding.value
}
}
}
如果使用简写方式的话就等于只写了bind()和update()。
自定义全局指令的格式为下:
Vue.directive('指令名',{
//函数体
bind(){
}
inserted(){
}
update(){
}
})
注意点:
Vue主键
对应的例子为下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--v-bind:data="item":将item绑定给data,就是传递数据-->
<div id="app">
<hfw v-for="item in item" v-bind:data="item"></hfw>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
<!--组件定义-->
Vue.component("hfw",{
//data表示对应的参数名,不要使用驼峰命名法,会报错,hfw表示对应的标签名
props: ['data'],
template: '<li>{{data}}</li>'
});
var vm = new Vue({
el: "#app",
data: {
item: ["java", "c++", "python"]
}
});
</script>
</body>
</html>
<hfw v-for="item in item" v-bind:data="item"></hfw>类似中间商。
template:表示模板,且在代码执行时会脱去。
defineProprety()
作用:个对象添加新的属性。(新添加的属性不会参与遍历)
例子为下:
var data = {
name: '张三',
sex: '男',
}
Object.defineProperty(data, 'age',{
value: 19
//想要被枚举的话就加下面的条件
enumerable: true;
//想要可以修改的话,就加下面的条件
writable: true;
//可以属性是否可以被删除
configurable: true;
});
console.log(data);
为了让Vue中的数据得到数据代理,所以我们不能直接使用defineProperty(),而是用Vue.set(target, key, value)或者使用vm.$set(target, key, value)。
重点: Vue.set(target, key, value)和vm.$set(target, key, value)中的target不允许为vm或vm.data,只能是vm.data中的对象。
事件修饰符(修饰符可以连续写)
计算属性
computed : 储存计算属性,且在计算属性中的get()方法存在缓存机制。
get()的调用机制:初次调用计算属性时会调用get(),在所依赖数据发生改变时会再次调用。
在计算属性确定不会被更改时,我们可以采用简写的方式。
computed: {
data: function{
//此函数就为get();
}
}
set():不是必须的,但是如果此消息在后续会被更改的话,就必须写set方法。
计算属性例子:列表过滤
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
</head>
<body>
<div id="root">
请输入名字: <input type="text" v-model="keyword"/>
<button @click="sortData = 1">年龄升序</button>
<button @click="sortData = 2">年龄降序</button>
<button @click="sortData = 0">年龄原顺序</button>
<ul>
<li v-for="person in filterpersons" :key="person.id">
{{person.name}}--{{person.age}}--{{person.sex}}
</li>
</ul>
</div>
</body>
<script>
new Vue({
el: '#root',
data: {
keyword: '',
sortData:0,
persons: [
{id: 001, name: '黄飞武',age: 18, sex: '男'},
{id: 002, name: '黄武',age: 13, sex: '女'},
{id: 003, name: '黄飞',age: 49, sex: '女'},
{id: 004, name: '飞武',age: 11, sex: '男'}
]
},
computed: {
filterpersons(){
var arr = this.persons.filter((p)=>{
return p.name.indexOf(this.keyword) !== -1
})
//a,b表示数组项
if(this.sortData == 1){
arr.sort((a, b)=>{//递增
return a.age - b.age
})
}else if(this.sortData == 2){
arr.sort((a, b)=>{//递减
return b.age - a.age
})
}
return arr
}
}
})
</script>
</html>
监视属性
watch: 用于监视数据。
methods: {
watch: {
ishot: {
//初始化时就让handler调用一下
immediate: true
//当ishot发生改变时就会调用
handler(newValue, oldValue){
}
}
}
}
//方法二
vm.$watch('ishost', {
ishot: {
immediate: true
//当ishot发生改变时就会调用
handler(newValue, oldValue){
}
}
})
注意点:
- 监视的属性必须存在,才能进行相关的操作。
- 当监视的属性发生变化时,回调函数自动调用,进行相关的操作。
- 监视的两种方法:new Vue时传入watch配置,通过vm.$watch监视。
深度监视 : 监视多级结构中某个属性的变化。(使用方法为下)
//在对应的监视器上加上此代码
deep: true
深度监视注意点:
- Vue中的watch默认不监测对象内部中值的改变(一层)
- 配置deep: true可以监测对象内部值的变化。
- Vue自身可以监测对象内部的值的改变,但Vue提供的watch默认不可以。
- 使用watch时根据数据的具体结构,决定是否采用深度监视。
监视属性的简写方法为下:
watch: {
dataName(newValue, oldValue){
//方法体
}
}
此简化方法的使用情况:只适用于修改对应属性值时。
监视属性和计算属性的区别: 监视属性可以开启异步任务,而计算属性不可以开启异步任务。(如:setTimeout)
计算属性必须返回值,而异步任务不能使数据return给外部的同步函数,所以计算属性不能使用异步操作。
区别:
- computed能完成的功能,watch都可以完成。
- watch能完成的功能,computed不一定可以完成,例如:watch可以进行异步操作。
- 所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象。
- 所有不被Vue所管理的函数(定时器的回调函数,ajax的回调函数等),最好写成箭头函数。
- 这样this的指向才是vm或组件实例对象。
setTimeout的this是window。
数据监视
收集表单数据
注意点:
过滤器
过滤器中存放对应的函数。
过滤器的格式为下:
{{对应参数 | 对应的过滤器函数}}
过滤器在Vue中的创建:
var vm = new Vue({
filters: {
timeFormater(value){
return dayjs(value).format('YYYY-MM-DD HH:mm:ss')
}
}
})
过滤器函数的第一个参数为管道符前面的参数 ,即使你没有写参数,它也会传管道符前面的参数给过滤器对应的函数。
过滤器函数的特点: 过滤器函数可以进行串联使用,且函数之间用管道符间隔,作用顺序为从前往后传递。
注册全局过滤器格式为下:
Vue.filter('对应的过滤器函数名',function(){
//对应的函数体
})
且全局过滤器必须写在new Vue()的前面。
网络通信(Axios异步通信)
Axios的特性:
- 从浏览器中创建 xmlHttpRequest。
- 从 node.js创建http请求。
- 支持Promise API [js中链式编程]
- 转换请求数据和响应数据。
- 取消请求。
- 自动转换为JSON数据。
- 客户端支持防御XSRF(跨站请求伪造)
Axios对应的cdn为下:
<script src="http://unpkg.com/axios/dist/axios.min.js"></script>
Axios例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div>{{info.name}}</div>
<div>{{info.address}}</div>
<a v-bind:href="info.url">点我</a>
</div>
<script src="http://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el: "#app",
data(){
return{
info:{
name: null,
address: {
street: null,
city: null,
country: null
},
url: null
}
}
},
mounted(){//钩子函数,链式编程,程序执行时插入执行
axios.get("../data.json").then(response=>(this.info=response.data));
}
});
</script>
</body>
</html>
对一个的data.json为下:
{
"name":"java",
"url": "http://baidu.com",
"page": 1,
"isNonProfit":true,
"address": {
" street": "含光门",
"city":"陕西西安",
"country": "中国"
},
" links": [
{
" name":" B站",
"url":" https://www.bilibili.com/"
},
{
"name": 4399,
"url": "https://www.4399.com/"
},
{
"name": "百度",
"url": "https://www.baidu.com/"
}
]
}
计算属性
computed:在其中编写对应的函数,该函数在调用时不需要加括号,而methods中定义的方法,在调用函数时需要加上括号。
计算属性的特点: 类似缓存方法,如果对应的参数不变的话,且调用过对应的函数时,就会返回上次计算出的结果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<body>
<!--view层,模板-->
<div id="vue">
<todo>
<todo-title slot="todo-title" v-bind:title="title"></todo-title>
<!--<todo-items slot="todo-items" v-for="{item,index} in todoItems" v-bind:item="item"></todo-items>-->
<!--如下为简写-->
<todo-items slot="todo-items" v-for="item in todoItems" :item="item" ></todo-items>
</todo>
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
Vue.component('todo',{
template:'<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
Vue.component('todo-title',{
props:['title'],
template:'<div>{{title}}</div>'
});
//这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
Vue.component("todo-items",{
props:["item"],
template:"<li>{{item}}<button>删除</button></li>"
});
var vm = new Vue({
el:"#vue",
data:{
title:"cvzhanshi study java",
todoItems:['test1','test2','test3']
}
});
</script>
</body>
</html>
slot对应的name表示插槽对应的名字。
点击事件
@click : 用于按钮的触发事件,且@click可以等于一个完整的函数也可以是一个简单的语句。(@click只会在vm中查找对应的函数,并不会在window中查找)
生命周期
mounted:表示挂载,且在把真实的dom放入页面后(完成挂载),会去调用mounted中的函数。
生命周期视图:https://cn.vuejs.org/images/lifecycle.png
注意点:
组件
cv的__proto__不是指向object,而是指向Vue,这是Vue强制指向的,所以在cv中查找某个属性时,不存在时就会到Vue中查找,最后在通过Vue的__proto__再找到Object。(vueComponent.prototype.__proto === Vue.prototype的值为true)
.Vue文件的格式
<template>
<!-- 组件的结构 -->
</template>
<script>
// 脚本
</script>
<style>
/* 组件的样式 */
</style>
在编写完.vue文件后,我们要将文件进行暴露。
暴露方法有: 分别暴露(直接将数据分别暴露),统一暴露(export{数据,数据,数据}),默认暴露(export default 数据)
脚手架
配置步骤:
render: 渲染功能,使app放入到对应的容器中。
脚手架中的规则:
props
props:表示组件中存在的参数,可以通过标签来赋值。(传入的属性值不可修改)
格式为下:
props: ['name', 'address'],//简单写法
props:{//完整写法
name: String,
age: Number,
address: String
}
props: {//最完整写法
name: {
type: String,
required: true//是否必要
},
age: {
type: Number,
default: 99//默认值
},
address: {
type: String,
required: false
}
}
mixin
mixin:表示多个组件共用一个配置。(mixin的配置文件使用js编写)
目的: 提高代码的复用性。
如果原来就存在某个键,而混合又传入了个相同名字的键,我们就以原来的键为最后结果,但是如果是生命周期的钩子函数,那么就会全部执行。
格式为下:
mixins: [.., .., ..]
mixins:要用数组表示,因为其可能存在多个。
nanoid
nanoid:用于创建唯一的id。
下载方式为下:
npm i nanoid
Confirm()
Confirm的用法:会显示一个弹窗,此弹窗会有确定和取消按钮,分别返回ture和false。
Todo-List(练习)
对应的Todo-List为下链接:
http://链接:https://pan.baidu.com/s/1131bPmPc4BYZMOnom6EOFg
提取码:6666
浏览器本地存储
localStorage
方法:通过window.localStorage,调用setItem(添加数据,参数为key), getItem(查询数据),removeItem(删除对应的数据,参数为key),clear(清空全部的数据)
特点: 在浏览器关闭后,localStorage还会存在,localStorage会存在缓存中,只有当用户主动清空缓存后才会消失。
sessionStorage
方法: 和localStorage的方法相同。
特点:在浏览器关闭后,sessionStorage会马上消失。
自定义事件
通过v-on 绑定对应的事件,而被绑定事件的主键上,我们可以通过this.对应的事件,来获取自定义事件,为了能够触发事件,我们就可以使用this.$emit('自定义事件',传递对应的参数)来触发自定义事件。(传递对应的参数是可选项,传递对应的参数会传递给自定义事件中对应的函数)
第二种写法:在对应的标签中使用ref,通过this.$refs.对应的子组件从而获取对象,通过者对象进行绑定事件($on('对应的事件名',对应的函数), this为触发事件的组件)。
解除绑定: this.$off('对应的事件名'),如果是解绑多个事件的话,我们就可以将$off()中的参数用数组表示。
在组件中使用原生的事件,需要在@原生事件后加上 .native。(例子: @click.native="")
过度效果
例子为下:
<template>
<div>
<button @click="isShow=!isShow">显示/隐藏</button>
<transition>
<h1 v-show="isShow" >你好!</h1>
</transition>
</div>
</template>
<script>
export default {
name: 'test',
data(){
return {
isShow: true
}
},
}
</script>
<style scoped>
h1{
background-color: orange;
}
.v-enter-active{
animation: hfw 1s;
}
.v-leave-active{
animation: hfw 1s reverse;
}
@keyframes hfw {
from{
transform: translateX(-100%);
}
to{
transform: translateX(0px);
}
}
</style>
如果用实现多个过度动画的话,我们就想要为<transition>的name赋值。
如果进行了此操作我们就需要将进/出类更新名字。
格式: .(对应的新名字)-enter-active,.(对应的新名字)-leave-active。
appear:此属性为<transition>中的属性,:appear="true"表示出现时有过度动画,:appear="false"表示出现时没有过度动画。
如果要实现两个相同的过度效果就需要使用<transition-group>,且每个项都要有key值。
animate的使用
对应的下载方法
npm install animate.css --save
引入方式:
import 'animate.css'
例子为下:
<template>
<div>
<button @click="isShow=!isShow">显示/隐藏</button>
<transition-group
name="animate__animated animate__bounce"
appear
enter-active-class="animate__jello"
leave-active-class="animate__backOutRight">
<h1 v-show="isShow" :key="1">你好!</h1>
<h1 v-show="!isShow" :key="2">你不好!</h1>
</transition-group>
</div>
</template>
<script>
import 'animate.css'
export default {
name: 'test',
data(){
return {
isShow: true
}
},
}
</script>
<style scoped>
h1{
background-color: orange;
}
</style>
axios的引用
下载axios库
npm i axios
axios的格式为下:
axios.get('www.4399.com').then(
response => {
console.log("请求成功!", response.data)
},
error => {
console("请求失败了", error。message)
}
)
//获取的数据需要使用,否则会爆红
跨域问题: 用于获取的数据源的端口号为5000(例子),而ajax的请求为8080(例子),两者的端口号不相同,从而引起跨域。
解决方法:
方法1:
使用 vue.CLI(代理服务器)
在vue.config.js中配置。
module.exports = {
devServer: {
proxy: 'http://localhost:4000'
//4000表示对应的数据源端口
}
}
且在ajax中的请求端口为发起请求的前端端口。
缓存机制: 如果在vue中public文件夹中存在请求所需要的数据,那请求请求就不会继续执行了,其会直接返回public文件夹中对应的数据。
缺点:在vue.config,js中只能配置一个端口号,其用于缓存机制会导致无法请求得到真正的数据。
方法2:
module.exports = {
devServer: {
proxy: {
'对应的前缀名,跟在端口号后面,这样就可以控制是否走代理服务器,就不会受到缓存的影响':{
target:"www.4399.com",
pathRewrite:{'^/atguigu':''},//此属性表示代理服务器传给后端时的url不回带有/atguigu
ws: true,//Websocket
changeOrigin: true // 是否对应后端服务器撒谎,true为撒谎,false为实话实说
},
'对应的前缀名2,跟在端口号后面,这样就可以控制是否走代理服务器,就不会受到缓存的影响':{
target:"www.4399.com",
pathRewrite:{'^/atguigu':''},//此属性表示代理服务器传给后端时的url不回带有/atguigu
ws: true,//Websocket
changeOrigin: true // 是否对应后端服务器撒谎,true为撒谎,false为实话实说
}
}
}
}
此方法弥补了方法一的缺陷。