概念:Vue.js 允许你自定义过滤器,可被用作一些常见的文本格式化。过滤器可以用在两个地方:mustache 插值和 v-bind 表达式。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符指示;
https://cn.vuejs.org/v2/guide/filters.html#ad
|
第一个命令的输出作为第二个命令的输入过滤器可以用在两个地方:双花括号插值和 v-bind
表达式
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
全局过滤器的定义
// 过滤器的定义语法
Vue.filter('过滤器的名称', function(){})
// 过滤器中的 function ,第一个参数,已经被规定死了,永远都是 过滤器 管道符前面 传递过来的数据
Vue.filter('过滤器的名称', (data)=>{
return data + '123';
})
过滤器的使用示例
<div id="app">
<!-- 格式化为年月日 -->
<p>{{ new Date() | dateFormat() }}</p>
<!-- 给金额前加上¥货币符号 -->
<p>{{ 399 | moneyFormat }}</p>
<p>{{ 399 | moneyFormat('$')}}</p>
<!-- 敏感词过滤 将其中单纯替换为** -->
<p>{{ '曾经,我也是一个单纯的少年,单纯的我,傻傻的问,谁是世界上最单纯的男人!' | msgFormat('--') }}</p>
</div>
Vue.filter定义全局过滤器
// 时间过滤器
Vue.filter('dateFormat', (data) => {
const date = new Date(data)
// 获取年月日
const year = date.getFullYear()
const month = date.getMonth()
const day = date.getDate()
return `${year} 年 ${month} 月 ${day} 日`
});
// 金额过滤器
Vue.filter('moneyFormat',(data,sign="¥")=>{
return sign+data;
});
// 过滤单纯敏感词
Vue.filter('msgFormat', function(data, arg = "***") {
return data.replace(/单纯/g, arg);
});
HTML元素:
<div id="app">
<p>{{ new Date() | dataFormat}}</p> <!-- 2021-05-05 18:26:25 -->
<p>{{ new Date() | dataFormat('yyyy-mm-dd')}}</p> <!-- 2021-05-05 -->
</div>
私有过滤器 filters
定义方式:
// 全局过滤器
Vue.filter('dateFormat', (data) => {
const date = new Date(data)
// 获取年月日
const year = date.getFullYear()
const month = date.getMonth()
const day = date.getDate()
return `${year} 年 ${month} 月 ${day} 日~~`
});
var vm = new Vue({
el: '#app',
data: {
},
methods: {
},
filters: { // 私有局部过滤器,只能在 当前 VM 对象所控制的 View 区域进行使用
dataFormat(data, pattern = "") { // 在参数列表中 通过 pattern="" 来指定形参默认值,防止报错
var dt = new Date(data);
// 获取年月日
var y = dt.getFullYear();
var m = (dt.getMonth() + 1).toString().padStart(2, '0');
var d = dt.getDate().toString().padStart(2, '0');
// 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日
// 否则,就返回 年-月-日 时:分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-${d}`;
} else {
// 获取时分秒
var hh = dt.getHours().toString().padStart(2, '0');
var mm = dt.getMinutes().toString().padStart(2, '0');
var ss = dt.getSeconds().toString().padStart(2, '0');
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
}
}
}
});
// 使用ES6中的字符串新方法 String.prototype.padStart(maxLength, fillString='') 或 String.prototype.padEnd(maxLength, fillString='')来填充字符串长度;
注意:当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,即:局部过滤器优先于全局过滤器被调用!
过滤器可以串联多个,前一个过滤器的返回值作为后一个的参数
给定一个状态 status ,值为 1、2、3
1:待付款 2:待发货 3:待收货
分别设置:红色、灰色、绿色
<style>
.no-pay {
background-color: #ccc;
padding: 10px;
}
.no-shipments {
background-color: orange;
padding: 10px;
}
.yes-shipments {
background-color: green;
padding: 10px;
}
.take-delivery {
background-color: red;
padding: 10px;
}
</style>
<div id="app">
<span v-bind:class="1 | getStatus | setStatusColor">{{ 1 | getStatus }}</span>
<span v-bind:class="2 | getStatus | setStatusColor">{{ 2 | getStatus }}</span>
<span v-bind:class="3 | getStatus | setStatusColor">{{ 3 | getStatus }}</span>
<span v-bind:class="4 | getStatus | setStatusColor">{{ 4 | getStatus }}</span>
</div>
filters定义局部过滤器
filters: {
// 判断是什么状态
getStatus(data) {
switch(data) {
case 1:
return '待付款'
case 2:
return '待发货'
case 3:
return '已发货'
case 4:
return '待收货'
}
},
// 设置状态文字颜色
setStatusColor(data) {
switch(data) {
case '待付款':
return 'no-pay'
case '待发货':
return 'no-shipments'
case '已发货':
return 'yes-shipments'
case '待收货':
return 'take-delivery'
}
}
}
官方文档地址:https://cn.vuejs.org/v2/guide/custom-directive.html
使用directive定义全局的指令,directives定义局部的指令。其中在定义的时候,指令的名称前不需要加v-前缀。
// 使用 Vue.directive() 定义全局的指令 v-focus
// 其中:参数1 : 指令的名称,注意,在定义的时候,指令的名称前面,不需要加 v- 前缀,
// 但是: 在调用的时候,必须 在指令名称前 加上 v- 前缀来进行调用
// 参数2: 是一个对象,这个对象身上,有一些指令相关的函数,这些函数可以在特定的阶段,执行相关的操作
Vue.directive('focus', {
bind: function(el) { // 每当指令绑定到元素上的时候,会立即执行这个 bind 函数,只执行一次
// 注意: 在每个 函数中,第一个参数,永远是 el ,表示 被绑定了指令的那个元素,这个 el 参数,是一个原生的JS对象
// 在元素 刚绑定了指令的时候,还没有 插入到 DOM中去,这时候,调用 focus 方法没有作用
// 因为,一个元素,只有插入DOM之后,才能获取焦点
// el.focus()
},
inserted: function(el) { // inserted 表示元素 插入到DOM中的时候,会执行 inserted 函数【触发1次】
el.focus()
// 和JS行为有关的操作,最好在 inserted 中去执行
},
updated: function(el) { // 当VNode更新的时候,会执行 updated, 可能会触发多次
}
})
// 自定义一个 设置字体颜色的 指令
Vue.directive('color', {
// 样式,只要通过指令绑定给了元素,不管这个元素有没有被插入到页面中去,这个元素肯定有了一个内联的样式
// 将来元素肯定会显示到页面中,这时候,浏览器的渲染引擎必然会解析样式,应用给这个元素
bind: function(el, binding) {
// el.style.color = 'red'
// console.log(binding.name)
// 和样式相关的操作,一般都可以在 bind 执行
// console.log(binding.value)
// console.log(binding.expression)
el.style.color = binding.value
}
})
// 自定义局部指令 v-color 和 v-font-weight,为绑定的元素设置指定的字体颜色 和 字体粗细:
new Vue({
el: '#app',
data:{},
methods:{},
filters:{},
directives: {
focus: {
// 指令的定义 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
el.focus()
}
},
color: { // 为元素设置指定的字体颜色
bind(el, binding) {
el.style.color = binding.value;
}
},
'font-weight': function (el, binding2) {
// 自定义指令的简写形式,等同于定义了 bind 和 update 两个钩子函数
el.style.fontWeight = binding2.value;
}
'fontsize': function(el,binding){
el.style.fontSize = parseInt(binding.value) + 'px';
}
}
});
在很多时候,你可能想在 bind
和 update
时触发相同行为,而不关心其它的钩子。比如这样写:
Vue.directive('color-swatch', function (el, binding) {
el.style.backgroundColor = binding.value
})
调用自定义指令时,需要在指令名称前加上v-前缀调用自定义指令。
<input type="text" v-model="searchName" v-focus v-color="'red'" v-font-weight="900" fontsize='36'>
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
bind
:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted
:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。update
:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
componentUpdated
:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind
:只调用一次,指令与元素解绑时调用。指令钩子函数会被传入以下参数:
el
:指令所绑定的元素,可以用来直接操作 DOM。binding
:一个对象,包含以下 property:name
:指令名,不包括 v-
前缀。value
:指令的绑定值,例如:v-my-directive="1 + 1"
中,绑定值为 2
。oldValue
:指令绑定的前一个值,仅在 update
和 componentUpdated
钩子中可用。无论值是否改变都可用。expression
:字符串形式的指令表达式。例如 v-my-directive="1 + 1"
中,表达式为 "1 + 1"
。arg
:传给指令的参数,可选。例如 v-my-directive:foo
中,参数为 "foo"
。modifiers
:一个包含修饰符的对象。例如:v-my-directive.foo.bar
中,修饰符对象为 { foo: true, bar: true }
。vnode
:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。oldVnode
:上一个虚拟节点,仅在 update
和 componentUpdated
钩子中可用。
<div id="directive" v-demo:foo.a.b="message"></div>
Vue.directive('demo', {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
}
});
new Vue({
el: '#directive',
data: {
message: 'hello!'
}
});
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
你可以直接将 KeyboardEvent.key
暴露的任意有效按键名转换为 kebab-case 来作为修饰符。
<input v-on:keyup.page-down="onPageDown">
在上述示例中,处理函数只会在 $event.key
等于 PageDown
时被调用。
Vue 提供了绝大多数常用的按键码的别名
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
使用按键码别名可以做到兼容:
有一些按键 (.esc
以及所有的方向键) 在 IE9 中有不同的key
值, 如果你想支持 IE9,这些内置的别名应该是首选。
Vue.directive('on').keyCodes.f2 = 113;
Vue.config.keyCodes.名称 = 按键值
来自定义案件修饰符的别名:
Vue.config.keyCodes.f2 = 113;
<input type="text" v-model="name" @keyup.f2="add">
这张图对于Vue的生命周期和钩子函数说的非常的明白。下面我们看一张关于Vue生命周期中出现的钩子函数示意图。
Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、销毁等一系列过程,我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程,就是生命周期。
Vue应用程序中有4个主要事件(8个主要钩子)。主要的生命周期函数分类:
<!DOCTYPE html>
<html>
<head>
<title>生命周期全过程</title>
<script type="text/javascript" src="https://cdn.jsdelivr.net/vue/2.1.3/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{ message }}</p>
</div>
<script type="text/javascript">
var app = new Vue({
el: '#app',
data: {
message : "hello world!"
},
beforeCreate: function () {
console.group('beforeCreate 创建前状态===============》');
console.log("%c%s", "color:red" , "el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //undefined
console.log("%c%s", "color:red","message: " + this.message) //undefined
},
created: function () {
console.group('created 创建完毕状态===============》');
console.log("%c%s", "color:red","el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeMount: function () {
console.group('beforeMount 挂载前状态===============》');
console.log("%c%s", "color:red","el : " + (this.$el)); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
mounted: function () {
console.group('mounted 挂载结束状态===============》');
console.log("%c%s", "color:red","el : " + this.$el); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeUpdate: function () {
console.group('beforeUpdate 更新前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(document.querySelector('#app').innerHTML);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
updated: function () {
console.group('updated 更新完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(document.querySelector('#app').innerHTML);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
beforeDestroy: function () {
console.group('beforeDestroy 销毁前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
destroyed: function () {
console.group('destroyed 销毁完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message)
}
})
</script>
</body>
</html>
每一个组件或者实例都会经历一个完整的生命周期,总共分为三个阶段:初始化、运行中、销毁。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>完整的生命周期</title>
</head>
<body>
<div id="app">
<my-template></my-template>
</div>
<template id="myTemplate">
<div>
<p class="myp">A组件</p>
<button @click="destroy">destroy</button>
<input type="text" v-model="msg">
<p>msg:{{msg}}</p>
</div>
</template>
</body>
<script type="text/javascript" src="https://cdn.jsdelivr.net/vue/2.1.3/vue.js"></script>
<script>
//生命周期:初始化阶段 运行中阶段 销毁阶段
Vue.component("myTemplate",{
template:"#myTemplate",
data:function(){
return {msg:'hello'}
},
timer:null,
methods:{
destroy:function(){
this.$destroy(); // 断点 销毁组件
}
},
beforeCreate:function(){
console.group('beforeCreate 创建前状态===============》');
console.log('beforeCreate:刚刚new Vue()之后,这个时候,数据还没有挂载呢,只是一个空壳')
console.log(this.msg)//undefined
console.log(document.getElementsByClassName("myp")[0])//undefined
},
created:function(){
console.group('created 创建完毕状态===============》');
console.log('created:这个时候已经可以使用到数据,也可以更改数据,在这里更改数据不会触发updated函数')
this.msg+='!!!'
console.log('在这里可以在渲染前倒数第二次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取')
console.log('接下来开始找实例或者组件对应的模板,编译模板为虚拟dom放入到render函数中准备渲染')
},
beforeMount:function(){
console.group('beforeMount 挂载前状态===============》');
console.log('beforeMount:虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated')
this.msg+='@@@@';
console.log('在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取')
console.log(document.getElementsByClassName("myp")[0])//undefined
console.log('接下来开始render,渲染出真实dom')
},
// render:function(createElement){
// console.log('render')
// return createElement('div','hahaha')
// },
mounted:function(){
console.group('beforeMount 挂载结束状态===============》');
console.log('mounted:此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了')
console.log(document.getElementsByClassName("myp")[0])
console.log('可以在这里操作真实dom等事情...')
// this.$options.timer = setInterval(function () {
// console.log('setInterval')
// this.msg+='!'
// }.bind(this),500)
},
beforeUpdate:function(){
console.group('updated 更新前状态===============》');
//这里不能更改数据,否则会陷入死循环
console.log('beforeUpdate:重新渲染之前触发')
console.log('然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染')
},
updated:function(){
console.group('updated 更新完成状态===============》');
//这里不能更改数据,否则会陷入死循环
console.log('updated:数据已经更改完成,dom也重新render完成')
},
beforeDestroy:function(){
console.group('destroyed 销毁前状态===============》');
console.log('beforeDestory:销毁前执行($destroy方法被调用的时候就会执行),一般在这里善后:清除计时器、清除非指令绑定的事件等等...')
// clearInterval(this.$options.timer)
},
destroyed:function(){
console.group('destroyed 销毁完成状态===============》');
console.log('destroyed:组件的数据绑定、监听...都去掉了,只剩下dom空壳,这里也可以善后')
}
})
const vm = new Vue({
}).$mount('#app')
</script>
</html>
这么多钩子函数,我们怎么用呢,我想大家可能有这样的疑问吧,我也有,哈哈哈。
为什么要有动画:动画能够提高用户的体验,帮助用户更好的理解页面中的功能;
<div id="app">
<input type="button" value="动起来" @click="myAnimate">
<!-- 使用 transition 将需要过渡的元素包裹起来 -->
<transition name="fade">
<div v-show="isshow">动画哦</div>
</transition>
</div>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
isshow: false
},
methods: {
myAnimate() {
this.isshow = !this.isshow;
}
}
});
/* 定义进入和离开时候的过渡状态 */
.fade-enter-active,
.fade-leave-active {
transition: all 0.2s ease;
position: absolute;
}
/* 定义进入过渡的开始状态 和 离开过渡的结束状态 */
.fade-enter,
.fade-leave-to {
opacity: 0;
transform: translateX(100px);
}
<link rel="stylesheet" type="text/css" href="./lib/animate.css">
<transition
enter-active-class="fadeInRight"
leave-active-class="fadeOutRight"
:duration="{ enter: 500, leave: 800 }">
<div class="animated" v-show="isshow">动画哦</div>
</transition>
<div id="app">
<input type="button" value="切换动画" @click="isshow = !isshow">
<transition
@before-enter="beforeEnter"
@enter="enter"
@after-enter="afterEnter">
<div v-if="isshow" class="show">OK</div>
</transition>
</div>
methods: {
beforeEnter(el) { // 动画进入之前的回调
el.style.transform = 'translateX(500px)';
},
enter(el, done) { // 动画进入完成时候的回调
el.offsetWidth;
el.style.transform = 'translateX(0px)';
done();
},
afterEnter(el) { // 动画进入完成之后的回调
this.isshow = !this.isshow;
}
}
.show{
transition: all 0.4s ease;
}
<style>
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateY(10px);
}
.list-enter-active,
.list-leave-active {
transition: all 0.3s ease;
}
</style>
<div id="app">
<input type="text" v-model="txt" @keyup.enter="add">
<transition-group tag="ul" name="list">
<li v-for="(item, i) in list" :key="i">{{item}}</li>
</transition-group>
</div>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
txt: '',
list: [1, 2, 3, 4]
},
methods: {
add() {
this.list.push(this.txt);
this.txt = '';
}
}
});
<transition-group>
组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的 v-move
特性,它会在元素的改变定位的过程中应用。
v-move
和 v-leave-active
结合使用,能够让列表的过渡更加平缓柔和:
.v-move{
transition: all 0.8s ease;
}
.v-leave-active{
position: absolute;
}
什么是组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可;
组件化和模块化的不同:
<html>
一样
var com1 = Vue.extend({
template: '<h2>第一种方式</h2>',
data(){
return{
}
}
});
Vue.component('mycom1', com1);
Vue.component('mycom2', {
template: '<h4>第一种方式的最终简写</h4>',
data(){
return {
}
}
});
<script id="tmpl" type="template">
<div>
<a href="#">{{msg.login}}</a> | <a href="#">{{msg.register}}</a>
</div>
</script>
Vue.component('account', {
template: '#tmpl',
data(){
return{
msg: {login: '登录',register: '注册'}
}
}
});
<template>
中定义 HTML 结构
<template id="tmp">
<div>
<h2>第二种方式</h2>
<h3 v-text="msg"></h3>
</div>
</template>
使用 Vue.component 中 template 属性 进行调用
Vue.component('myCom3', {
template: '#tmp',
data(){
return{
msg: '好耶~'
}
}
});
new Vue({
el: '#app',
data: {},
methods:{},
filters:{},
directives:{},
components: {
myLogin: {
template: `<div>
<h1>login 组件</h1>
<p>私有组件</p>
</div>`,
data(){
return{
}
}
}
},
beforeCreate(){},
created(){},
beforeMount(){},
Mounted(){},
beforeUpdate(){},
updated(){},
beforeDestroy(){},
destroyed(){}
});
注意: 组件中的DOM结构,有且只能有唯一的根元素(Root Element)来进行包裹!
分离私有组件的定义,将组件模板对象分开定义
const myLogin = {
template: `<div>
<h1>login 组件</h1>
<p>私有组件</p>
</div>`,
data(){
return{
}
}
}
new Vue({
el: '#app',
data: {},
methods:{},
components: {
// 组件名称:组件的模板对象
// myLogin: myLogin
myLogin,
}
});
我们的子组件是可以多级嵌套的,子组件中还可以在声明子组件。
<div id="app">
<account></account>
</div>
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
components: {
account: {
template: `<div>
<h1>这是Account组件{{name}}</h1>
<login></login>
<register></register>
</div>`,
data(){
return {
name: 'hello world!'
}
},
components: {
login: {
template: "<h3>这是登录组件</h3>"
},
register: {
template: '<h3>这是注册组件</h3>'
}
}
}
}
});
</script>
<div id="app">
<mycom1></mycom1>
<mycom2></mycom2>
<my-com3></my-com3>
<my-login></my-login>
</div>
因为组件需要被重用,为了让每个组件有自己的私有作用域,data需要为函数并且返回一个对象
在组件中,data
需要被定义为一个方法
通过计数器案例演示
<div id="app">
<myCount></myCount><hr>
<myCount></myCount><hr>
<myCount></myCount><hr>
</div>
<template id="tmp">
<input type="button" value="+1" @click="increment">
<h3 v-text="count"></h3>
</template>
<script>
Vue.component('myCount',{
template: '#tmp',
data: function (){
return {
count: 0
}
},
methods:{
increment(){
this.count++;
}
}
});
new Vue({
el:'#app',
data:{ },
methods:{ }
})
</script>
<div id="app">
<a href="" @click.prevent="flag = true">登录</a>
<a href="" @click.prevent="flag = false">注册</a>
<transition mode="out-in">
<login v-if="flag"></login>
<register v-else="flag"></register>
</transition>
</div>
<script>
Vue.component('login',{
template: '<h3>登录组件</h3>'
})
Vue.component('register',{
template: '<h3>注册组件</h3>'
})
new Vue({
el: '#app',
data:{
flag: true,
},
methods:{
}
})
</script>
<component>
进行切换:is
指定要显示的组件名称
<style>
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(150px);
}
.v-enter-active,
.v-leave-active {
transition: all .5s ease;
}
</style>
<div id="app">
<a href="" @click.prevent="comName = 'login'">登录</a>
<a href="" @click.prevent="comName = 'register'">注册</a>
<a href="" @click.prevent="comName = 'forget'">忘记密码</a>
<!-- 通过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.component('forget',{
template: '<h3>忘记密码组件</h3>'
})
new Vue({
el: '#app',
data:{
comName: 'login'
},
methods:{
}
})
</script>
注意:一定要使用props
属性来定义父组件传递过来的数据,由于 props 默认是单向绑定,即父组件的属性发生改变,子组件也会改变。反之则不会。props中数据是只读的
使用v-bind
或简化指令:,将数据传递到子组件中
<div id="app">
<!-- 父组件可以在引用子组件的时候,通过属性绑定的形式 ,把需要传递给子组件的数据,以属性绑定的形式传递到子组件内部供使用-->
<my-component v-bind:parentmsg="msg" :msg="message"></my-component>
</div>
<script>
Vue.component('myComponent', {
template: '<span>{{ parentmsg }}--{{msg}}</span>',
// props:声明待接收的父组件数据
// props中数据都是只读的,无法重新赋值
props: ['parentmsg', 'msg'],
// 把父组件传递过来的parentmsg和msg属性,现在props数组中定义一下,这样才能使用父组件传递过来的数据
data() {
return {
// 子组件中也可以有自己的数据在data中
}
}
})
var vm = new Vue({
el: '#app',
data: {
msg: 'hello 子组件',
message: 'hello world'
}
})
</script>
<div id="app">
<!-- 默认 单向绑定 -->
<my-component :msg="message"></my-component>
<!-- 双向绑定 -->
<my-component :msg.sync="message"></my-component>
<!-- 单向绑定 -->
<my-component :msg.once="message"></my-component>
</div>
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
getMsg
是父组件中methods
中定义的方法名称,func
是子组件调用传递过来方法时候的方法名称
<son v-on:func="show"></son>
this.$emit('方法名', 要传递的数据)
方式,来调用父组件中的方法,同时把数据传递给父组件使用
<div id="app">
<h1>{{msg}}</h1>
<!-- 父组件向子组件传递方法,使用的是事件绑定机制 -->
<!-- v-on,当我们自定义了一个事件属性之后,那么子组件就能够通过某种方式来调用 -->
<son @func="getMsg"></son>
</div>
<!-- 组件模板定义 -->
<template id="son">
<div>
<h1>这是子组件</h1>
<input type="button" value="向父组件传值" @click="sendMsg" />
</div>
</template>
<script>
const son = {
template: '#son', // 组件模板Id
data(){
return {
msg: "我是子组件传递过来的数据"
}
},
methods: {
sendMsg() { // 按钮的点击事件
// 我们可以通过调用父组件传递过来的方法,将子组件数据通过参数形式传递给父组件中
this.$emit('func', this.msg); // 调用父组件传递过来的方法,同时把数据传递出去
}
}
}
// 子组件的定义方式
Vue.component('son',son);
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {
msg: "父组件"
},
methods: {
getMsg(val){ // 子组件中,通过 this.$emit() 实际调用的方法,在此进行定义
this.msg = val;
console.log("调用了父组件身上的getMsg方法");
alert(val);
}
}
});
</script>
ref
属性,然后赋予一个优雅的名字
<h3 ref="myh3">我是H3</h3>
<!-- login组件 -->
<login ref="login"></login>
$refs
来获取DOM
getElement() { console.log(this.$refs.myh3); console.log(this.$refs.login.$el.innerText);}
<style>
.pagination {
display: flex;
list-style: none;
}
.page-item {
width: 25px;
height: 25px;
line-height: 25px;
text-align: center;
border: 1px solid #ccc;
}
.page-item.active {
background-color: skyblue;
}
</style>
<div id="app">
<page-component :total="total"></page-component>
</div>
<template id="page-component">
<ul class="pagination">
<li :class="p == page ? 'page-item active' : 'page-item'" v-for="p in pagecount">
<a href="#" class="page-link" @click.prevent="page = p">{{ p }}</a>
</li>
</ul>
</template>
<script>
const pageComponent = {
template: '#page-component',
name: 'PageComponent',
props: ['total'],
data: function() {
return {
page: 1, // 当前页码
pagesize: 10 // 每页显示条数
}
},
computed: {
pagecount: function() {
// 总页码数
return Math.ceil(this.total / this.pagesize)
}
}
}
var vm = new Vue({
el: '#app',
data: {
total: 35
},
components: {
pageComponent
}
})
</script>
<div id="app">
<div v-for="goods in goodslist">
<p>商品名称:{{ goods.name }}</p>
<p>单价:{{ goods.price }}</p>
<cart-component v-model="goods.count"></cart-component>
<hr>
</div>
<div>
订单总金额:{{ amount }} 元
</div>
</div>
<template id="cart-component">
<div class="cart">
<button @click="count--; updateCount();">-</button>
<input type="text" v-model="count" style="width: 50%;" @input="updateCount()">
<button @click="count++; updateCount();">+</button>
</div>
</template>
<script>
const cartComponent = {
name: 'Cart',
template: '#cart-component',
// 在组件中不允许直接修改 props 中的数据
props: ['value'],
data: function() {
return {
count: this.value
}
},
methods: {
// v-model 指令双向数据绑定,修改父组件内容
updateCount: function() {
// 触发 input 事件
this.$emit('input', this.count)
}
}
}
const app = new Vue({
el: '#app',
data: {
goodslist: [
{
name: 'iphone 8 plus',
price: 5888,
count: 0
},
{
name: 'iphone x',
price: 7222,
count: 0
}
]
},
computed: {
// 当前订单总金额
amount: function() {
var money = 0;
this.goodslist.forEach(goods => {
money += parseInt(goods.count) * parseInt(goods.price)
})
return money;
}
},
components: {
cartComponent
}
})
</script>
<div id="app">
<cmt-box @loadcomments="loadComments"></cmt-box>
<ul class="list-group">
<li class="list-group-item" v-for="item in list" :key="item.id">
<span class="badge">评论人:{{item.user}}</span> {{item.content}}
</li>
</ul>
</div>
<template id="temp">
<div>
<div class="form-group">
<label for="">评论人:</label>
<input type="text" class="form-control" v-model="user">
</div>
<div class="form-group">
<label for="">评论内容:</label>
<textarea class="form-control" v-model="content"></textarea>
</div>
<div class="form-group">
<input type="button" value="发表评论" @click="postComment">
</div>
</div>
</template>
<script>
const vm = new Vue({
el: '#app',
data: {
list: []
},
methods: {
loadComments() {
const list = JSON.parse(localStorage.getItem('cmts') || '[]');
this.list = list;
console.log(6666);
}
},
created() {
this.loadComments();
},
components: {
'cmt-box': {
template: '#temp',
data() {
return {
user: '',
content: ''
}
},
methods: {
postComment() {
const comment = {
id: Date.now(),
user: this.user,
content: this.content
};
// 从localStorage中获取所有的评论
const list = JSON.parse(localStorage.getItem('cmts') || '[]');
list.unshift(comment);
// 保存最新的评论数据
localStorage.setItem('cmts', JSON.stringify(list));
this.user = this.content = '';
this.$emit('loadcomments');
}
},
}
}
});
</script>