目录
11、resetFields和clearValidate区别
1、过滤器详解
replace()
定义和用法
replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
语法
stringObject.replace(regexp/substr,replacement)
参数 | 描述 |
---|---|
regexp/substr | 必需。规定子字符串或要替换的模式的 RegExp 对象。 请注意,如果该值是一个字符串,则将它作为要检索的直接量文本模式,而不是首先被转换为 RegExp 对象。 |
replacement | 必需。一个字符串值。规定了替换文本或生成替换文本的函数。 |
返回值
一个新的字符串,是用 replacement 替换了 regexp 的第一次匹配或所有匹配之后得到的。
说明
字符串 stringObject 的 replace() 方法执行的是查找并替换的操作。它将在 stringObject 中查找与 regexp 相匹配的子字符串,然后用 replacement 来替换这些子串。如果 regexp 具有全局标志 g,那么 replace() 方法将替换所有匹配的子串。否则,它只替换第一个匹配子串。
replacement 可以是字符串,也可以是函数。如果它是字符串,那么每个匹配都将由字符串替换。但是 replacement 中的 $ 字符具有特定的含义。如下表所示,它说明从模式匹配得到的字符串将用于替换。
字符 | 替换文本 |
---|---|
$1、$2、...、$99 | 与 regexp 中的第 1 到第 99 个子表达式相匹配的文本。 |
$& | 与 regexp 相匹配的子串。 |
$` | 位于匹配子串左侧的文本。 |
$' | 位于匹配子串右侧的文本。 |
$$ | 直接量符号。 |
注意:ECMAScript v3 规定,replace() 方法的参数 replacement 可以是函数而不是字符串。在这种情况下,每个匹配都调用该函数,它返回的字符串将作为替换文本使用。
该函数的①第一个参数是匹配模式的字符串。
②接下来的参数是与模式中的子表达式匹配的字符串,可以有 0 个或多个这样的参数。
③接下来的参数是一个整数,声明了匹配在 stringObject 中出现的位置。
④最后一个参数是 stringObject 本身。
<div id="app">
<p>{{ msg | msgFormat('疯狂+1', '123') | test }}</p>
</div>
<script>
// 定义一个 Vue 全局的过滤器,名字叫做 msgFormat
Vue.filter('msgFormat', function (msg, arg, arg2) {
// 字符串的 replace 方法,第一个参数,除了可写一个 字符串之外,还可以定义一个正则
return msg.replace(/单纯/g, arg + arg2)
})
Vue.filter('test', function (msg) {
return msg + '========'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
msg: '曾经,我也是一个单纯的少年,单纯的我,傻傻的问,谁是世界上最单纯的男人'
},
methods: {}
});
</script>
2、vue的生命周期
<input type="button" value="修改msg" @click="msg='No'">
<h3 id="h3">{{ msg }}</h3>
这是我们遇到的第一个生命周期函数beforeCreate() ,
表示实例完全被创建出来之前,会执行它。
在 生命周期函数执行的时候,data 和 methods 中的 数据都还没有没初始化。
beforeCreate() { // 这是我们遇到的第一个生命周期函数,表示实例完全被创建出来之前,会执行它
console.log(this.msg)
this.show()
// 注意: 在 beforeCreate 生命周期函数执行的时候,data 和 methods 中的 数据都还没有没初始化
}
beforeCreate()由于是在实例被创建之前执行的this还没有,在 beforeCreate 生命周期函数执行的时候,data 和 methods 中的 数据都还没有没初始化,所以会报错。
这是遇到的第二个生命周期函数 created()
在 created 中,data 和 methods 都已经被初始化好了!执行代码不会报错。
如果要调用 methods 中的方法,或者操作 data 中的数据,最早,只能在 created 中操作。
created() { // 这是遇到的第二个生命周期函数
console.log(this.msg)
this.show()
// 在 created 中,data 和 methods 都已经被初始化好了!
// 如果要调用 methods 中的方法,或者操作 data 中的数据,最早,只能在 created 中操作
},
控制台输出:
这是遇到的第3个生命周期函数beforeMount()
表示 模板已经在内存中编辑完成了,但是尚未把 模板渲染到 页面中,会在模板渲染到页面之前执行
在 beforeMount 执行的时候,页面中的元素,还没有被真正替换过来,只是之前写的一些模板字符串
beforeMount() {
console.log(document.getElementById('h3').innerText)
// 在 beforeMount 执行的时候,页面中的元素,还没有被真正替换过来,只是之前写的一些模板字符串
},
这是遇到的第4个生命周期函数mounted(),
表示,内存中的模板,已经真实的挂载到了页面中,用户已经可以看到渲染好的页面了
mounted 是 实例创建期间的最后一个生命周期函数,当执行完 mounted 就表示,实例已经被完全创建好了,此时,如果没有其它操作的话,这个实例,就静静的躺在我们的内存中,一动不动
mounted() {
console.log(document.getElementById('h3').innerText)
// 注意: mounted 是 实例创建期间的最后一个生命周期函数,当执行完 mounted 就表示,实例已经被完全创建好了,此时,如果没有其它操作的话,这个实例,就静静的 躺在我们的内存中,一动不动
}
接下来的是运行中的两个事件:是事件触发了更改以后才会被执行的两个函数。
beforeUpdate():这时候,表示 我们的界面还没有被更新【数据被更新了吗? 数据肯定被更新了】
得出结论: 当执行 beforeUpdate 的时候,页面中的显示的数据,还是旧的,此时 data 数据是最新的,但是页面的内容尚未和最新的数据同步所以页面上的h3里还是显示旧数据。
beforeUpdate() { // 这时候,表示 我们的界面还没有被更新【数据被更新了吗? 数据肯定被更新了】
console.log('界面上元素的内容:' + document.getElementById('h3').innerText)
console.log('data 中的 msg 数据是:' + this.msg)
// 得出结论: 当执行 beforeUpdate 的时候,页面中的显示的数据,还是旧的,此时 data 数据是最新的,页面尚未和 最新的数据保持同步
}
updated():updated 事件执行的时候,页面和 data 数据已经保持同步了,都是最新的
updated() {
console.log('界面上元素的内容:' + document.getElementById('h3').innerText)
console.log('data 中的 msg 数据是:' + this.msg)
// updated 事件执行的时候,页面和 data 数据已经保持同步了,都是最新的
}
3、发送请求
<div id="app">
<input type="button" value="get请求" @click="getInfo">
<input type="button" value="post请求" @click="postInfo">
<input type="button" value="jsonp请求" @click="jsonpInfo">
</div>
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {
getInfo() { // 发起get请求
// 当发起get请求之后, 通过 .then 来设置成功的回调函数
this.$http.get('http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1').then(function (result) {
// 通过 result.body 拿到服务器返回的成功的数据
console.log(result.body)
})
},
postInfo() { // 发起 post 请求 application/x-wwww-form-urlencoded
// 手动发起的 Post 请求,默认没有表单格式,所以,有的服务器处理不了
// 通过 post 方法的第三个参数, { emulateJSON: true } 设置 提交的内容类型 为 普通表单数据格式
this.$http.post('http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1', {}, { emulateJSON: true }).then(result => {
console.log(result.body)
})
},
jsonpInfo() { // 发起JSONP 请求
this.$http.jsonp('http://www.phonegap100.com/appapi.php?a=getPortalList&catid=20&page=1').then(result => {
console.log(result.body)
})
}
}
});
</script>
4、动画详解-过渡
transition:
v-enter 【这是一个时间点】 是进入之前,元素的起始状态,此时还没有开始进入
v-leave-to 【这是一个时间点】 是动画离开之后,离开的终止状态,此时动画已经结束了
v-enter-active 【入场动画的动作】
v-leave-active 【离场动画的动作】
/* v-enter 【这是一个时间点】 是进入之前,元素的起始状态,此时还没有开始进入 */
/* v-leave-to 【这是一个时间点】 是动画离开之后,离开的终止状态,此时动画已经结束了 */
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(150px);
}
/* v-enter-active 【入场动画的动作】 */
/* v-leave-active 【离场动画的动作】 */
.v-enter-active,
.v-leave-active{
/* 设置动画过渡:过度所有属性,时间0.8秒,过渡方式 */
transition: all 0.8s ease;
}
当transition没有设置name属性的时候,默认是以v-作为前缀的
我们可以给 transition 设置name属性来自定义过渡类名前缀
<!-- 当transition没有设置name属性的时候,默认是以v-作为前缀的 -->
<!-- 我们可以给 transition 设置name属性来自定义过渡类名前缀 -->
<transition name="my">
<h6 v-if="flag2">这是一个H6</h6>
</transition>
使用第三方类
<link rel="stylesheet" href="./lib/animate.css">
<!-- 入场 bounceIn 离场 bounceOut -->
class的前缀必须是animated才行。
duration是设置动画时长的。
分开设置两个不一样是时间也行。
使用钩子函数
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter">
<div class="ball" v-show="flag"></div>
</transition>
methods: {
// 注意: 动画钩子函数的第一个参数:el,表示 要执行动画的那个DOM元素,是个原生的 JS DOM对象
// 大家可以认为 , el 是通过 document.getElementById('') 方式获取到的原生JS DOM对象
beforeEnter(el){
// beforeEnter 表示动画入场之前,此时,动画尚未开始,可以 在 beforeEnter 中,设置元素开始动画之前的起始样式
// 设置小球开始动画之前的,起始位置
el.style.transform = "translate(0, 0)"
},
enter(el, done){
// 这句话,没有实际的作用,但是,如果不写,出不来动画效果;可以认为 el.offsetWidth 会强制动画刷新
el.offsetWidth
// enter函数 可以设置小球完成动画之后的结束状态及动画的过渡过程
el.style.transform = "translate(150px, 450px)"
el.style.transition = 'all 1s ease'
// 这里的 done, 其实就是 afterEnter 这个函数,也就是说:done 是 afterEnter 函数的引用
done()
},
afterEnter(el){
// 动画完成之后,会调用 afterEnter
// console.log('ok')
this.flag = !this.flag
}
}
注意: 动画钩子函数的第一个参数:el,表示 要执行动画的那个DOM元素,是个原生的 JS DOM对象
大家可以认为 , el 是通过 document.getElementById('') 方式获取到的原生JS DOM对象
1、beforeEnter 表示动画入场之前,此时,动画尚未开始,可以 在 beforeEnter 中,设置元素开始动画之前的起始样式
设置小球开始动画之前的,起始位置
2、enter函数 可以设置小球完成动画之后的结束状态及动画的过渡过程
这句话,没有实际的作用,但是,如果不写,出不来动画效果;可以认为 el.offsetWidth 会强制动画刷新
el.offsetWidth
这里的 done(), 其实就是 afterEnter 这个函数,也就是说:done 是 afterEnter 函数的引用
如果没有done的话,小球会等一段时间才会隐藏,动画不连贯。执行完enter里函数,调用done会立即执行afterEnter函数,
就不用迟钝。
3、afterEnter(el)
动画完成之后,会调用 afterEnter
列表动画
<ul>
<!-- 在实现列表过渡的时候,如果需要过渡的元素,是通过 v-for 循环渲染出来的,使用 transition 包裹是无效的,需要使用 transition-group -->
<!-- 如果要为 v-for 循环创建的元素设置动画,必须为元素设置 :key 属性 -->
<!-- 可以通过 appear 属性设置节点初始渲染的过渡动画 -->
<!-- 通过 为 transition-group 元素设置 tag 属性,指定 transition-group 渲染为指定的元素,如果不指定 tag 属性,默认会渲染为 span 标签 -->
<transition-group >
<li v-for="(item, i) in list" :key="item.id" @click="del(i)">
{{item.id}} --- {{item.name}}
</li>
</transition-group>
</ul>
在实现列表过渡的时候,如果需要过渡的元素,是通过 v-for 循环渲染出来的,使用 transition 包裹是无效的,需要使用 transition-group
如果要为 v-for 循环创建的元素设置动画,必须为元素设置 :key 属性
可以通过 appear 属性设置节点初始渲染的过渡动画,就是刚打开的时候,列表的动画
通过 为 transition-group 元素设置 tag 属性,指定 transition-group 渲染为指定的元素,如果不指定 tag 属性,默认会渲染为 span 标签,就是把 transition-group这个标签渲染成span标签了。
li:hover {
background-color: hotpink;
transition: all 0.8s ease;
}
在0.8秒内把列表的一行渲染成粉色
下面的 .v-move 和 .v-leave-active 配合使用,能够实现删除的时候列表后续的元素,浮上来的效果。不用等被删除元素完全退场才开始上浮。
.v-move {
transition: all 0.6s ease;
}
.v-leave-active {
position: absolute;
}
把transition-group 的tag属性指定为ul 就不用另外在外层包裹ul标签了,渲染的时候会自动 把transition-group渲染为ul标签。
5、组件创建方式
<div id="app">
<!-- 如果要使用组件,直接把组件的名称,以 HTML 标签的形式,引入到页面中即可 -->
<!-- <my-com1></my-com1> -->
<mycom1></mycom1>
</div>
1.1 使用 Vue.extend 来创建全局的Vue组件模板对象,通过 template 属性,指定了组件要展示的HTML内容
// 1.1 使用 Vue.extend 来创建全局的Vue组件模板对象,通过 template 属性,指定了组件要展示的HTML内容
var com1 = Vue.extend({
template: '<h3>这是使用 Vue.extend 创建的组件</h3>'
})
template指定了html要显示的内容
1.2 使用 Vue.component('组件的名称', 创建出来的组件模板对象) 来定义组件
使用 Vue.component 定义全局组件的时候,如果组件名称使用了驼峰命名,则在引用组件的时候,需要把大写的驼峰改为小写的字母,同时,两个单词之前,使用 - 链接;
所以应该全部使用-命名法比较好。
如果不使用驼峰,则直接拿名称来使用即可;
Vue.component('mycom1', com1)
简化方式一:
Vue.component 第一个参数:组件的名称
第二个参数: Vue.extend 创建的组件
Vue.component('mycom1', Vue.extend({
template: '<h3>这是使用 Vue.extend 创建的组件</h3>'
}))
创建方式二:
直接这样其实也可。
template有且只有一个根元素。不可以有兄弟。
创建方式三:
在 被控制的 #app 外面,使用 template 元素,定义组件的HTML模板结构
<!-- 在 被控制的 #app 外面,使用 template 元素,定义组件的HTML模板结构 -->
<template id="tmpl">
<div>
<h1>这是通过 template 元素,在外部定义的组件结构,这个方式,有代码的只能提示和高亮</h1>
<h4>好用,不错!</h4>
</div>
</template>
<template id="tmpl2">
<h1>这是私有的 login 组件</h1>
</template>
Vue.component('mycom3', {
template: '#tmpl'
})
var vm = new Vue({
el: '#app'
});
var vm2 = new Vue({
el: '#app2',
components: { // 定义实例内部私有组件的
login: {
template: '#tmpl2'
}
}
})
<div id="app">
<mycom3></mycom3>
<!-- <login></login> -->
</div>
<hr>
<div id="app2">
<mycom3></mycom3>
<login></login>
</div>
6、组件中的data
// 1. 组件可以有自己的 data 数据
// 2. 组件的 data 和 实例的 data 有点不一样,实例中的 data 可以为一个对象,但是 组件中的 data 必须是一个方法
// 3. 组件中的 data 除了必须为一个方法之外,还必须返回一个对象才行;
// 4. 组件中 的data 数据,使用方式,和实例中的 data 使用方式完全一样!!!
Vue.component('mycom1', {
template: '<h1>这是全局组件 --- {{msg}}</h1>',
data: function () {
return {
msg: '我是组件中data定义的数据'
}
}
})
var vm = new Vue({
el: '#app'
});
7、组件切换方式
<body>
<div id="app">
<a href="" @click.prevent="flag=true">登录</a>
<a href="" @click.prevent="flag=false">注册</a>
<login v-if="flag"></login>
<register v-else></register>
</div>
<script>
// 定义两个组件
Vue.component('login', {
template: '<h3>登录组件</h3>'
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
// 创建 Vue 实例
var vm = new Vue({
el: '#app',
data: {
flag: false
}
});
</script>
</body>
更便捷:
<body>
<div id="app">
<a href="" @click.prevent="comName='login'">登录</a>
<a href="" @click.prevent="comName='register'">注册</a>
<!-- Vue提供了 component ,来展示对应名称的组件 -->
<!-- component 是一个占位符, :is 属性,可以用来指定要展示的组件的名称 -->
<component :is="comName"></component>
</div>
<script>
// 组件名称是 字符串
Vue.component('login', {
template: '<h3>登录组件</h3>'
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
comName: 'login' // 当前 component 中的 :is 绑定的组件的名称
}
});
</script>
</body>
切换动画:
<body>
<div id="app">
<a href="" @click.prevent="comName='login'">登录</a>
<a href="" @click.prevent="comName='register'">注册</a>
<!-- 通过 transition 的 mode 属性设置组件切换时候的 模式 -->
<transition mode="out-in">
<component :is="comName"></component>
</transition>
</div>
<script>
// 组件名称是 字符串
Vue.component('login', {
template: '<h3>登录组件</h3>'
})
Vue.component('register', {
template: '<h3>注册组件</h3>'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
comName: 'login' // 初始 component 中的 :is 绑定的组件的名称
}
});
</script>
</body>
Vue文档中的过渡模式是建立在多组件切换的基础上的,也就是动态组件切换,并且当两个被切换的元素是同种标签的内容时(比如这里都是button),需要给每个元素加key用以区分元素。
否则由于Vue机制的原因,为了性能会使用同一个元素。也就是说你切换时并不会更换掉整个元素,而是替换掉该元素中的内容的值,以此来切换,所以在这里需要添加key
8、模板定义方式
<body>
<div id="app">
<mylogin></mylogin>
<login></login>
</div>
<script>
// 通过 对象 字面量的形式, 定义了一个 组件模板对象
var login = {
template: '<h1>1234555</h1>'
}
// 通过 Vue.component 把组件模板对象,注册为一个全局的Vue组件,同时为这个组件
// 起了一个名称,可以让我们通过标签形式,在页面中直接引入这个组件
全局:
Vue.component('mylogin', login)
// 创建 Vue 实例,得到 ViewModel
局部:
var vm = new Vue({
el: '#app',
components: { // 定义的私有组件
'mylogin': login // '组件的名称': 组件的模板对象->
// <mylogin></mylogin>
等价于
login // 注意在 ES2015+ 中,在对象中放一个类似 login 的变量名其实是 login: login 的缩写
// <login></login>
}
});
</script>
</body>
9、父组件向子组件传值
父组件相当于vue实例,子组件相当于com1
父组件可以在引用子组件的时候, 通过属性绑定(v-bind:) 的形式,
把需要传递给子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用。
子组件中,默认无法访问到 父组件中的 data 上的数据 和 methods 中的方法。
子组件中的 data 数据是子组件自身私有的,比如子组件通过 Ajax 请求回来的数据。
注意: 组件中 props 的所有数据,都是通过父组件传递给子组件的,且数据都是只读的,无法重新赋值。
把父组件传递过来的 parentmsg 属性定义在 props 数组中才能使用这个数据。
<div id="app">
父组件可以在引用子组件的时候, 通过属性绑定(v-bind:) 的形式,
把需要传递给子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用
<com1 :parentmsg="msg"></com1>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: '我是父组件中的数据'
},
components: {
子组件中,默认无法访问到 父组件中的 data 上的数据 和 methods 中的方法
com1: {
data() {
子组件中的 data 数据是子组件自身私有的,比如子组件通过 Ajax 请求回来的数据
return {
title: '123',
content: 'qqq'
}
},
template: '<h1>这是子组件 --- {{ parentmsg }}</h1>',
注意: 组件中 props 的所有数据,都是通过父组件传递给子组件的,且数据都是只读的,无法重新赋值
props: ['parentmsg'],
把父组件传递过来的 parentmsg 属性定义在 props 数组中才能使用这个数据
}
}
});
</script>
10、父组件向子组件传方法
此处的父组件是vue实例,要传递方法show绑定在com2的func上,子组件相当于com2
父组件向子组件传递方法,使用的是事件绑定机制:v-on, 当我们自定义了一个事件属性之后,那么子组件就能够通过某些方式来调用传递进去的这个方法了
当点击子组件的按钮的时候,拿到父组件传递过来的 func 方法,并调用这个方法
emit 英文原意: 是触发,调用、发射的意思
this.$emit('func', this.sonmsg)
this->子组件
$emit('func', this.sonmsg)->子组件调用父组件传来的方法func并传回一个自己的参数sonmsg
show(data)里调用的就是this.sonmsg的值
<div id="app">
<!-- 父组件向子组件传递方法,使用的是事件绑定机制:v-on, 当我们自定义了一个事件属性之后,那么子组件就能够通过某些方式来调用传递进去的这个方法了 -->
<com2 @func="show"></com2>
</div>
<template id="tmpl">
<div>
<h1>这是子组件</h1>
<input type="button" value="这是子组件中的按钮 - 点击它,触发父组件传递过来的 func 方法" @click="myclick">
</div>
</template>
<script>
// 定义了一个字面量类型的组件对象
var com2 = {
template: '#tmpl', // 通过指定的Id加载指定的 template 元素中的内容当作组件的HTML结构
data() {
return {
sonmsg: { name: '小头儿子', age: 6 }
}
},
methods: {
myclick() {
// 当点击子组件的按钮的时候,拿到父组件传递过来的 func 方法,并调用这个方法
// emit 英文原意: 是触发,调用、发射的意思
this.$emit('func', this.sonmsg)
}
}
}
var vm = new Vue({
el: '#app',
data: {
datamsgFormSon: null
},
methods: {
show(data) {
// 获取子组件方法传入参数的值
console.log('调用了父组件身上的 show 方法')
console.log(data)
this.datamsgFormSon = data
}
},
components: {
com2 // com2: com2
}
});
</script>
11、
resetFields和clearValidate区别
在使用element ui 进行表单校验的时候。混用了resetFields和clearValidate造成了个莫名奇妙的bug
this.$refs.form.resetFields(); //移除校验结果并重置字段值
this.$refs.form.clearValidate(); //移除校验结果
// 二者都能清除验证,但是resetFields()会重置字段值,而在vue中大量用到的数据的绑定,很可能出现
// 同一个数据绑定在多处的情况,如果滥用resetFields很可能造成界面上出现莫名的bug
// 下图为我项目中的bug
image.png
左边的树和右边的表单用了绑定了相同的数据,点击左边树的每个节点可以在右边进行编辑,右边点击保存
会对数据进行校验,左边树结构每次点击不同节点都要重置校验,我误用了resetFields,造成了会去重置仓库> 大楼数据为空,然后再次左边树结构的数据消失,变为空白。