Vue常用特性
一: 表单基本操作
- 获取单选框中的值
- 通过v-model
<!--
1、 两个单选框需要同时通过v-model 双向绑定 一个值
2、 每一个单选框必须要有value属性 且value 值不能一样
3、 当某一个单选框选中的时候 v-model 会将当前的 value值 改变 data 中的 数据
gender 的值就是选中的值,我们只需要实时监控他的值就可以了
-->
<input type="radio" id="male" value="1" v-model='gender'>
<label for="male">男</label>
<input type="radio" id="female" value="2" v-model='gender'>
<label for="female">女</label>
<script>
new Vue({
data: {
// 默认会让当前的 value 值为 2 的单选框选中
gender: 2,
},
})
</script>
- 获取复选框中的值
- 通过v-model
- 和获取单选框中的值一样
- 复选框
checkbox
这种的组合时 data 中的 hobby 我们要定义成数组 否则无法实现多选
<!--
1、 复选框需要同时通过v-model 双向绑定 一个值
2、 每一个复选框必须要有value属性 且value 值不能一样
3、 当某一个单选框选中的时候 v-model 会将当前的 value值 改变 data 中的 数据
hobby 的值就是选中的值,我们只需要实时监控他的值就可以了
-->
<div>
<span>爱好:</span>
<input type="checkbox" id="ball" value="1" v-model='hobby'>
<label for="ball">篮球</label>
<input type="checkbox" id="sing" value="2" v-model='hobby'>
<label for="sing">唱歌</label>
<input type="checkbox" id="code" value="3" v-model='hobby'>
<label for="code">写代码</label>
</div>
<script>
new Vue({
data: {
// 默认会让当前的 value 值为 2 和 3 的复选框选中
hobby: ['2', '3'],
},
})
</script>
- 获取下拉框和文本框中的值
- 通过v-model
<div>
<span>职业:</span>
<!--
1、 需要给select 通过v-model 双向绑定 一个值
2、 每一个option 必须要有value属性 且value 值不能一样
3、 当某一个option选中的时候 v-model 会将当前的 value值 改变 data 中的 数据
occupation 的值就是选中的值,我们只需要实时监控他的值就可以了
-->
<!-- multiple 多选 -->
<select v-model='occupation' multiple>
<option value="0">请选择职业...</option>
<option value="1">教师</option>
<option value="2">软件工程师</option>
<option value="3">律师</option>
</select>
<!-- textarea 是 一个双标签 不需要绑定value 属性的 -->
<textarea v-model='desc'></textarea>
</div>
<script>
new Vue({
data: {
// 默认会让当前的 value 值为 2 和 3 的下拉框选中
occupation: ['2', '3'],
desc: 'nihao'
},
})
</script>
二:表单域修饰符
- .number 转换为数值
- 注意点:
- 当开始输入非数字的字符串时,因为Vue无法将字符串转换成数值
- 所以属性值将实时更新成相同的字符串。即使后面输入数字,也将被视作字符串。
<div id="app">
<!-- 值为字符串拼接 -->
<!-- <input type="text" v-model="num1">
<input type="text" v-model="num2"> -->
<!-- 只为数值相加 -->
<input type="text" v-model.number="num1">
<input type="text" v-model.number="num2">
<button @click="add">相加</button>
<span v-text="num"></span>
</div>
<script src="../vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
num1: '',
num2: '',
num: ''
},
methods: {
add: function() {
this.num = this.num1 + this.num2
}
}
});
</script>
- .trim 自动过滤用户输入的首尾空白字符(打印出长度)
- 只能去掉首尾的 不能去除中间的空格
<div id="app">
<!-- 无法去除开始和结尾空格 -->
<input type="text" v-model="myLength">
<!-- 去除开始和结尾空格,无法去除中间空格 -->
<input type="text" v-model.trim="myLength1">
<button @click="handle">长度</button>
</div>
<script src="../vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
myLength: '',
myLength1: ''
},
methods: {
handle: function() {
console.log(this.myLength.length);
console.log(this.myLength1.length);
}
}
});
</script>
- .lazy 将input事件切换成change事件
- .lazy 修饰符延迟了同步更新属性值的时机。即将原本绑定在 input 事件的同步逻辑转变为绑定在 change 事件上
- 在失去焦点 或者 按下回车键时才更新
<div id="app">
<!-- 立即触发,即写即显示 -->
<input type="text" v-model="msg">
<i v-text="msg"></i>
<!-- 变为change事件,失去焦点后再变化 -->
<input type="text" v-model.lazy="msg1">
<i v-text="msg1"></i>
</div>
<script src="../vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: '大哥很酷',
msg1: '失去焦点再说'
}
});
</script>
三:自定义指令
- 内置指令不能满足我们特殊的需求
- Vue允许我们自定义指令
Vue.directive 注册全局指令
<div id="app">
<input type="text" v-focus>
</div>
<script src="../vue.js"></script>
<script>
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
inserted: function(el) {
//获取元素焦点
el.focus();
}
})
var vm = new Vue({
el: '#app'
});
</script>
Vue.directive 注册全局指令 带参数
<div id="app">
<input type="text" v-color="msg">
</div>
<script src="../vue.js"></script>
<script>
// 给input缓背景
Vue.directive('color', {
//此处inserted和bind用法一致
// bind生命周期, 只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置
// el 为当前自定义指令的DOM元素
// binding 为自定义的函数形参 通过自定义属性传递过来的值 存在 binding.value 里面
bind: function(el, binding) {
//根据指令参数设置背景颜色
el.style.backgroundColor = binding.value.color;
}
})
var vm = new Vue({
el: '#app',
data: {
msg: {
color: 'red'
}
}
});
</script>
自定义指令局部指令
- 局部指令,需要定义在 directives 的选项 用法和全局用法一样
- 局部指令只能在当前组件里面使用
- 当全局指令和局部指令同名时以局部指令为准
<div id="app">
<input type="text" v-focus v-color="msg">
</div>
<script src="../vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: {
color: 'red'
}
},
// 创建局部指令
directives: {
focus: {
inserted: function(el) {
el.focus();
}
},
color: {
inserted: function(el, binding) {
el.style.backgroundColor = binding.value.color;
}
}
}
});
</script>
四:计算属性 computed
- 模板中放入太多的逻辑会让模板过重且难以维护 使用计算属性可以让模板更加的简洁
- 计算属性是基于它们的响应式依赖进行缓存的
- computed比较适合对多个变量或者对象进行处理后返回一个结果值,也就是数多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化
<div id="app">
<input type="text" v-model="msg">
<span>{{msg}}</span>
<!-- 字符串倒置 -->
<span>{{reversedMessage}}</span>
<span>{{reversedThis()}}</span>
</div>
<script src="../vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: 'hellovue'
},
methods: {
reversedThis: function() {
//方法不存在缓存(在插值表达式中调用要加())
return this.msg.split('').reverse().join('');
}
},
computed: {
reversedMessage: function() {
//让字符串倒置
//split()字符串变数组,reverse()数组倒置,join()数组边字符串,用空格隔开,默认为逗号
//存在缓存(根据data数据需要)
return this.msg.split('').reverse().join('');
}
}
});
</script>
五:侦听器 watch
- 使用watch来响应数据的变化
- 一般用于异步或者开销较大的操作
- watch 中的属性 一定是data 中 已经存在的数据
- 当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听
<div id="app">
<input type="text" v-model="firstNum">
<input type="text" v-model="lastNum">
<span>{{num}}</span>
<div>
方法实现拼接:
<span>{{handle()}}</span>
</div>
<div>
侦听器实现拼接:
<span>{{num}}</span>
</div>
</div>
<script src="../vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
firstNum: 'chen',
lastNum: 'wen',
num: 'chen wen'
},
methods: {
handle: function() {
//用方法完成
return this.firstNum + ' ' + this.lastNum;
}
},
watch: {
//数据变化时执行异步或开销较大的操作
//函数名必须与属性名一致
firstNum: function(val) {
this.num = val + this.lastNum;
},
lastNum: function(val) {
this.num = this.firstNum + val;
}
}
});
</script>
侦听器案例
<div id="app">
<input type="text" v-model.lazy="msg">
<span>{{tip}}</span>
</div>
<script src="../vue.js"></script>
<script>
// 侦听器
// 1,采用侦听器监听用户名变化
// 2,调用后台接口进行验证
// 3,根据验证结果调整提示信息
var vm = new Vue({
el: '#app',
data: {
msg: '',
tip: ''
},
methods: {
checkName: function(msg) {
var that = this;
//调用接口,但是可以使用定时任务的方式模拟接口
setTimeout(function() {
//模拟接口调用
if (that.msg == 'admin') {
that.tip = '用户名已存在,请更改'
} else {
that.tip = '注册成功'
}
}, 2000)
}
},
watch: {
msg: function(val) {
//调用后台接口验证用户名的合法性
this.checkName(val);
//修改提示信息
this.tip = '请稍等···';
}
}
});
</script>
六:过滤器
- Vue.js允许自定义过滤器,可被用于一些常见的文本格式化。
- 过滤器可以用在两个地方:双花括号插值和v-bind表达式。
- 过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示
- 支持级联操作
- 过滤器不改变真正的
data
,而只是改变渲染的结果,并返回过滤后的版本 - 全局注册时是filter,没有s的。而局部过滤器是filters,是有s的
<div id="app">
<input type="text" v-model="msg">
<!-- 首字母大写 -->
<span>{{ msg | upper}}</span>
<!-- 先切换大写再切换小写 -->
<span>{{ msg | upper | tolow}}</span>
<!-- 给表单添加属性 -->
<span :adc="msg | capitalize"></span>
</div>
<script src="../vue.js"></script>
<script>
//添加过滤器
Vue.filter('upper', function(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
});
Vue.filter('tolow', function(value) {
return value.charAt(0).toLowerCase() + value.slice(1);
});
var vm = new Vue({
el: '#app',
data: {
msg: ''
},
//局部过滤器(范围跟局部指令一致)
filters: {
capitalize: function(value) {
return value.charAt(0).toUpperCase() + value.slice(1);
}
}
});
</script>
过滤器中传递参数
<div id="box">
<!--
filterA 被定义为接收三个参数的过滤器函数。
其中 message 的值作为第一个参数,
普通字符串 'arg1' 作为第二个参数,表达式 arg2 的值作为第三个参数。
-->
{{ message | filterA('arg1', 'arg2') }}
</div>
<script>
// 在过滤器中 第一个参数 对应的是 管道符前面的数据 n 此时对应 message
// 第2个参数 a 对应 实参 arg1 字符串
// 第3个参数 b 对应 实参 arg2 字符串
Vue.filter('filterA',function(n,a,b){
if(n<10){
return n+a;
}else{
return n+b;
}
});
new Vue({
el:"#box",
data:{
message: "哈哈哈"
}
})
</script>
带参数过滤器案例
<div id="app">
<span>{{dateTime}}</span>
<div>{{dateTime | format('yyyy-MM-dd')}}</div>
</div>
<script src="../vue.js"></script>
<script>
//简洁逻辑版
// Vue.filter('format', function(value, arg) {
// //value就是过滤器传递过来的参数
// if (arg == 'yyyy-MM-dd') {
// var ret = '';
// ret += value.getFullYear() + '-' + (value.getMonth() + 1) + '-' + value.getDate();
// return ret;
// } else {
// return value;
// }
// });
//终极版日期格式处理过滤器(正则表达核心)
Vue.filter('format', function(value, arg) {
function dateFormat(date, format) {
if (typeof date === "string") {
var mts = date.match(/(\/Date\((\d+)\)\/)/);
if (mts && mts.length >= 3) {
date = parseInt(mts[2]);
}
}
date = new Date(date);
if (!date || date.toUTCString() == "Invalid Date") {
return "";
}
var map = {
"M": date.getMonth() + 1, //月份
"d": date.getDate(), //日
"h": date.getHours(), //小时
"m": date.getMinutes(), //分
"s": date.getSeconds(), //秒
"q": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
format = format.replace(/([yMdhmsqS])+/g, function(all, t) {
var v = map[t];
if (v !== undefined) {
if (all.length > 1) {
v = '0' + v;
v = v.substr(v.length - 2);
}
return v;
} else if (t === 'y') {
return (date.getFullYear() + '').substr(4 - all.length);
}
return all;
});
return format;
}
return dateFormat(value, arg);
});
var vm = new Vue({
el: '#app',
data: {
dateTime: new Date()
}
});
</script>
七:生命周期
- 事物从出生到死亡的过程
- Vue实例从创建 到销毁的过程 ,这些过程中会伴随着一些函数的自调用。我们称这些函数为钩子函数
常用的 钩子函数
beforeCreate | 在实例初始化之后,数据观测和事件配置之前被调用 此时data 和 methods 以及页面的DOM结构都没有初始化 什么都做不了 |
---|---|
created | 在实例创建完成后被立即调用此时data 和 methods已经可以使用 但是页面还没有渲染出来 |
beforeMount | 在挂载开始之前被调用 此时页面上还看不到真实数据 只是一个模板页面而已 |
mounted | el被新创建的vm.$el替换,并挂载到实例上去之后调用该钩子。 数据已经真实渲染到页面上 在这个钩子函数里面我们可以使用一些第三方的插件 |
beforeUpdate | 数据更新时调用,发生在虚拟DOM打补丁之前。 页面上数据还是旧的 |
updated | 由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。 页面上数据已经替换成最新的 |
beforeDestroy | 实例销毁之前调用 |
destroyed | 实例销毁后调用 |
数组变异方法
- 在 Vue 中,直接修改对象属性的值无法触发响应式。当你直接修改了对象属性的值,你会发现,只有数据改了,但是页面内容并没有改变
- 变异数组方法即保持数组方法原有功能不变的前提下对其进行功能拓展
push() | 往数组最后面添加一个元素,成功返回当前数组的长度 |
---|---|
pop() | 删除数组的最后一个元素,成功返回删除元素的值 |
shift() | 删除数组的第一个元素,成功返回删除元素的值 |
unshift() | 往数组最前面添加一个元素,成功返回当前数组的长度 |
splice() | 有三个参数,第一个是想要删除的元素的下标(必选),第二个是想要删除的个数(必选),第三个是删除 后想要在原位置替换的值 |
sort() | sort() 使数组按照字符编码默认从小到大排序,成功返回排序后的数组 |
reverse() | reverse() 将数组倒序,成功返回倒序后的数组 |
替换数组
- 不会改变原始数组,但总是返回一个新数组
filter | filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。 |
---|---|
concat | concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组 |
slice | slice() 方法可从已有的数组中返回选定的元素。该方法并不会修改数组,而是返回一个子数组 |
举个栗子(变异方法:响应式变换;替换数组:生成新数组)
<div id="app">
<input type="text" v-model="fruit">
<!--cwen 变异方法(响应式变化,修改原有数据) -->
<button @click="addFruit">添加</button>
<button @click="delFruit">删除</button>
<!--cwen 替换数组,生成新的数组,并渲染(旧数组仍在) -->
<button @click="swFruit">转换</button>
<ul>
<li :key="item.index" v-for="(item,index) in fruits">{{item}}</li>
</ul>
</div>
<script src="../vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
fruits: ['apple', 'banana', 'orange'],
fruit: ''
},
methods: {
//无需赋值,默认为响应式
addFruit: function() {
this.fruits.push(this.fruit);
},
delFruit: function() {
this.fruits.pop();
},
swFruit: function() {
//替换数组需要重新给原始数组赋值
this.fruits = this.fruits.slice(0, 2);
}
}
});
</script>
动态数组响应式数据
- Vue.set(a,b,c) 让 触发视图重新更新一遍,数据动态起来
- a是要更改的数据 、 b是数据的第几项、 c是更改后的数据
<div id="app">
<ul>
<li :key="item.index" v-for="(item,index) in fruits">{{item}}</li>
</ul>
<div>{{infor.name}}</div>
<div>{{infor.age}}</div>
<div>{{infor.gender}}</div>
</div>
<script src="../vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
fruits: ['apple', 'banana', 'orange'],
infor: {
name: '张三',
age: 15
}
},
});
// 两个API既可处理数组索引,也可处理对象属性
//索引修改不具有响应式功能
// vm.fruits[1] = 'lemon';
//Vue方式处理数据具有响应式
Vue.set(vm.fruits, 2, 'lemon');
vm.$set(vm.fruits, 1, 'lemon');
//不具有响应式
// vm.infor.gender = 'male';
//具有响应式的功能
Vue.set(vm.infor, 'gender', 'female');
</script>
last:综合案例(图书管理)
图书列表案例
- 静态列表效果
- 基于数据实现模板效果
- 处理每行的操作按钮
1、 提供的静态数据
- 数据存放在vue 中 data 属性中
2、 把提供好的数据渲染到页面上
- 利用 v-for循环 遍历 books 将每一项数据渲染到对应的数据中
3、 添加图书
- 通过双向绑定获取到输入框中的输入内容
- 给按钮添加点击事件
- 把输入框中的数据存储到 data 中的 books 里面
4 修改图书-上
- 点击修改按钮的时候 获取到要修改的书籍名单
- 4.1 给修改按钮添加点击事件, 需要把当前的图书的id 传递过去 这样才知道需要修改的是哪一本书籍
- 把需要修改的书籍名单填充到表单里面
- 4.2 根据传递过来的id 查出books 中 对应书籍的详细信息
- 4.3 把获取到的信息填充到表单
5 修改图书-下
- 5.1 定义一个标识符, 主要是控制 编辑状态下当前编辑书籍的id 不能被修改 即 处于编辑状态下 当前控制书籍编号的输入框禁用
- 5.2 通过属性绑定给书籍编号的 绑定 disabled 的属性 flag 为 true 即为禁用
- 5.3 flag 默认值为false 处于编辑状态 要把 flag 改为true 即当前表单为禁用
- 5.4 复用添加方法 用户点击提交的时候依然执行 handle 中的逻辑如果 flag为true 即 表单处于不可输入状态 此时执行的用户编辑数据数据
6 删除图书
- 6.1 给删除按钮添加事件 把当前需要删除的书籍id 传递过来
- 6.2 根据id从数组中查找元素的索引
- 6.3 根据索引删除数组元素
实例
页面
代码(注释含细节)
<style type="text/css">
* {
margin: 0;
padding: 0;
}
#app {
width: 500px;
margin: 0 auto;
text-align: center;
}
table {
width: 100%;
border-collapse: collapse;
}
table thead th {
background-color: red;
height: 35px;
}
.book {
background-color: red;
height: 35px;
}
table tr td {
height: 35px;
line-height: 35px;
border: 1px dashed red;
}
.total {
height: 30px;
line-height: 30px;
background-color: red;
border: 1px dashed skyblue;
text-align: center;
}
</style>
</head>
<body>
<div id="app">
<div>
<h1>图书管理</h1>
</div>
<div class="book">
编号:<input type="text" v-model="id" :disabled="flag" v-focus> 名称:
<input type="text" v-model="name">
<button @click="addBook" :disabled="nameFlag">提交</button>
</div>
<div class="total">
<span>图书总数:</span>
<span>{{countTotal}}</span>
</div>
<table>
<thead>
<tr>
<th>编号</th>
<th>名称</th>
<th>时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr :key="item.id" v-for="(item,index) in books">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.time | format('yyyy-MM-dd')}}</td>
<td>
<a href="" @click.prevent="modifyBook(item.id)">修改</a>
<span>|</span>
<a href="" @click.prevent="delBook(item.id)">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
<script src="../vue.js"></script>
<script>
//自定义指令焦点聚集
Vue.directive('focus', {
inserted: function(el) {
el.focus();
}
})
//终极版日期格式处理过滤器
Vue.filter('format', function(value, arg) {
function dateFormat(date, format) {
if (typeof date === "string") {
var mts = date.match(/(\/Date\((\d+)\)\/)/);
if (mts && mts.length >= 3) {
date = parseInt(mts[2]);
}
}
date = new Date(date);
if (!date || date.toUTCString() == "Invalid Date") {
return "";
}
var map = {
"M": date.getMonth() + 1, //月份
"d": date.getDate(), //日
"h": date.getHours(), //小时
"m": date.getMinutes(), //分
"s": date.getSeconds(), //秒
"q": Math.floor((date.getMonth() + 3) / 3), //季度
"S": date.getMilliseconds() //毫秒
};
format = format.replace(/([yMdhmsqS])+/g, function(all, t) {
var v = map[t];
if (v !== undefined) {
if (all.length > 1) {
v = '0' + v;
v = v.substr(v.length - 2);
}
return v;
} else if (t === 'y') {
return (date.getFullYear() + '').substr(4 - all.length);
}
return all;
});
return format;
}
return dateFormat(value, arg);
});
var vm = new Vue({
el: '#app',
data: {
id: '',
name: '',
newObj: {},
flag: false,
nameFlag: false,
books: ''
},
methods: {
addBook: function() {
if (this.flag) {
//修改
//根据当前的id去更新数组中对应的数据
this.books.some((item) => {
if (item.id == this.id) {
item.name = this.name;
return true;
}
});
this.flag = false;
} else {
//提交
//表单数据封装至对象,再把对象添加至数组
this.newObj = {
id: this.id,
name: this.name,
time: ''
};
this.books.push(this.newObj);
}
//清空表单
this.id = '';
this.name = ''
},
modifyBook: function(id) {
//进制修改id
this.flag = true;
//遍历数组找到点的哪一个
// for (var i = 0; i < this.books.length; i++) {
// if (id == this.books[i].id) {
// console.log(this.books[i]);
// }
// }
//把数据填充至表单
//根据id查询要编辑的数据(数组API找到点的哪一个)
var book = this.books.filter(function(item) {
return item.id == id;
});
//把获取的信息填充到表单
this.id = book[0].id;
this.name = book[0].name;
},
delBook: function(id) {
//删除图书
//方法一
//根据id从数组找查找元素的索引
// var index = this.books.findIndex(function(item) {
// return item.id == id;
// });
// this.books.splice(index, 1);
// 方法二
//通过filter遍历过滤
this.books = this.books.filter(function(item) {
return item.id != id;
})
}
},
computed: {
countTotal: function() {
return this.books.length;
}
},
watch: {
name: function(val) {
//验证图书名称是否已存在
var flag = this.books.some(function(item) {
return item.name == val;
});
if (flag) {
this.nameFlag = true;
} else {
this.nameFlag = false;
}
}
},
//生命周期
mounted: function() {
//该钩子函数被触发的时候,模板已经可以使用
//一般此时用于获取后台数据,把数据填充到模板
//此处放些""假数据"用于模拟
var data = [{
id: 0,
name: '三国演义',
time: new Date()
}, {
id: 1,
name: '水浒传',
time: new Date()
}, {
id: 2,
name: '红楼梦',
time: new Date()
}, {
id: 3,
name: '西游记',
time: new Date()
}, {
id: 4,
name: '三体',
time: new Date()
}];
this.books = data;
}
});
</script>
冲冲冲
下一篇:Vue组件化开发