1. Computed --- vue计算属性
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护。例如:
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
在这个地方,模板不再是简单的声明式逻辑。你必须看一段时间才能意识到,这里是想要显示变量 message
的翻转字符串。当你想要在模板中多次引用此处的翻转字符串时,就会更加难以处理。
所以,对于任何复杂逻辑,你都应当使用计算属性。
基础例子
<div id="example">
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
结果:
- Original message: "Hello"
- Computed reversed message: "olleH"
这里我们声明了一个计算属性 reversedMessage
。我们提供的函数将用作属性 vm.reversedMessage
的 getter 函数:
console.log(vm.reversedMessage) // => 'olleH'
vm.message = 'Goodbye'
console.log(vm.reversedMessage) // => 'eybdooG'
你可以打开浏览器的控制台,自行修改例子中的 vm。vm.reversedMessage
的值始终取决于 vm.message
的值。
你可以像绑定普通属性一样在模板中绑定计算属性。Vue 知道 vm.reversedMessage
依赖于 vm.message
,因此当 vm.message
发生改变时,所有依赖 vm.reversedMessage
的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系:计算属性的 getter 函数是没有副作用 (side effect) 的,这使它更易于测试和理解。
完整案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>computed 从现有数据计算出新的数据</title>
</head>
<body>
<div id="app">
<h1>{{msg}}</h1>
<h1>{{rmsg}}</h1>
</div>
<script src="./js/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
msg:"hello,VUE"
},
computed:{
rmsg:function(){
return this.msg.split('').reverse().join('');
// 字符串分割数据 split
// 数组连接成字符串 join
// 翻转数组reverse()
}
}
})
</script>
</body>
</html>
2. 值类型与引用类型 --- 复习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>复习 值类型与引用类型</title>
</head>
<body>
<script>
/* var a = 15;
var b = a;
a = 20;
console.log(b);//15
// 值类型(简单数据类) 发生改变,不会影响,引用他的变量 */
/* var a = {age:15};
var b = a;
a.age = 20;
console.log(b.age);//20
// 引用类型(复杂数据类型)发生改变,也会影响,引用他的变量 */
/* var arr=[{age:18},{age:20}];
var p = {age:24};// 引用类型
arr.push(p);//arr最后一个元素引用了 p
p.age=35;
console.log(arr[2].age);//35
// 引用类型(复杂数据类型)发生改变,也会影响,引用他的变量 */
var arr=[{age:18},{age:20}];
var p = {age:24};// 引用类型
arr.push( {...p})
p.age = 50;
console.log(arr[2].age);
</script>
</body>
</html>
3. filter 过滤器
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式 (后者从 2.1.0+ 开始支持)。过滤器应该被添加在 JavaScript 表达式的尾部,由“管道”符号指示:
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
你可以在一个组件的选项中定义本地的过滤器:
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
或者在创建 Vue 实例之前全局定义过滤器:
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
new Vue({
// ...
})
当全局过滤器和局部过滤器重名时,会采用局部过滤器。
下面这个例子用到了 capitalize 过滤器:
john
过滤器函数总接收表达式的值 (之前的操作链的结果) 作为第一个参数。在上述例子中,capitalize 过滤器函数将会收到 message 的值作为第一个参数。
过滤器可以串联:
{{ message | filterA | filterB }}
在这个例子中,filterA 被定义为接收单个参数的过滤器函数,表达式 message 的值将作为参数传入到函数中。然后继续调用同样被定义为接收单个参数的过滤器函数 filterB,将 filterA 的结果传递到 filterB 中。
过滤器是 JavaScript 函数,因此可以接收参数:
{{ message | filterA('arg1', arg2) }}
这里,filterA 被定义为接收三个参数的过滤器函数。其中 message 的值作为第一个参数,普通字符串 'arg1' 作为第二个参数,表达式 arg2 的值作为第三个参数。
案例1-数字显示位数过滤
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>filter 过滤</title>
</head>
<body>
<div id="app">
<h1>{{price|fix}}</h1>
<h1>{{2.45975|fix}}</h1>
</div>
<script src="./js/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{price:135},
filters:{
fix(val){
return "¥"+val.toFixed(2);
// toFixed(2)保留2位小数 ES5的方法
}
}
})
</script>
</body>
</html>
结果:
- ¥135.00
- ¥2.46
案例2 - filter修改数据的显示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>filter 过滤</title>
</head>
<body>
<div id="app">
<h1> {{phone}}</h1>
<h1>{{phone | tel}}</h1>
<h1>{{phone | tel('-')}}</h1>
</div>
<script src="./js/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{phone:13598859747},
filters:{
tel(val,type=" "){
val+='';//转换为字符串
let s='';//最终返回的字符串
for(let i=0;i<val.length;i++){
s+=val[i];
// 在带三个和第7个元素后面加-
if(i==2||i==6){
s+=type;
}
}
return s;
}
}
})
</script>
</body>
</html>
结果:
- 13598859747
- 135 9885 9747
- 135-9885-9747
4. computed+filter -- 搜索过滤案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>computed 从现有数据计算出新的数据</title>
</head>
<body>
<div id="app">
<input type="text" v-model.number="name">
{{name|glq}}
<input type="text" v-model="keyword">
<div v-for="(item,index) in flist" :key="index">{{item}}</div>
</div>
<script src="./js/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
list:['vue','react','angular','jquery'],
// 列表显示 带e的元素
keyword:'',//搜索的关键字
name:1,
},
computed:{
flist:function(){
if(this.keyword==''){
return this.list;
//如果没有关键字 返回所有数据
}else{
return this.list.filter(item=>item.includes(this.keyword));
}
}
},
filters:{
glq:(val,arg=2,type="¥")=>{
if(isNaN(val)||val==""){return val}else{
return type+val.toFixed(arg);
}
}
}
})
</script>
</body>
</html>
![](https://img.haomeiwen.com/i15480045/174b44cdede9ddc0.png)
![](https://img.haomeiwen.com/i15480045/a6ac95e6777998b8.png)
4. text
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>computed 从现有数据计算出新的数据</title>
<style>
.box{ width:180px;height:320px; float: left; }
.red{color:red}
.big{font-size: 48px;}
.em{font-style: italic;}
</style>
</head>
<body>
<div id="app">
<p :style="obj"> this is line</p>
<input type="text" v-model.number="name">
{{name|fix}}
<h1 >{{name|fix2}}</h1>
<h1 >{{name|tel}}</h1>
<input type="text" v-model="keyword">
<div v-for="(item,index) in flist" :key="index">姓名:{{item.name}}----年龄:{{item.age}}</div>
<br>
<br>
<br>
<div v-img="pics[0]" class="box" ref="box"></div>
<br>
<br>
<br>
<div v-img="pics[1]" class="box" ref="box"></div>
<br>
<br>
<br>
<div v-img="pics[2]" class="box" ref="box"></div>
<br>
<br>
<br>
<br>
</div>
<script src="./js/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
list:[{name:"vue",age:18},{name:"jquery",age:24},{name:"react",age:33}],
// 列表显示 带e的元素
keyword:'',//搜索的关键字
name:1,
flag:true,
pics:["http://images.entgroup.cn/group2/M00/02/96/wKgAS13gt0WAS3CjAABoTRx_PZ8927.jpg","http://images.entgroup.cn/group1/M00/05/2C/wKgASV34PqSAQliYAABmxNg1oI0829.jpg","http://images.entgroup.cn/group2/M00/02/93/wKgAS12lOvCAP93oAACEwKNAR90206.jpg"],
obj:{"font-size":"48px",color:"green"}
},
mounted() {
boxs = document.querySelectorAll("div[v-img]");
boxs = Array.from(boxs);
window.scrollTo(0,1);
window.onscroll = function(){
for(let i=0;i<boxs.length;i++){
let box = boxs[i];
let {top,bottom,height} = box.getBoundingClientRect();
let wh = window.innerHeight;
if(top+height>0&&bottom<(wh+height)){
box.style.backgroundImage=`url(${box.getAttribute("v-img")})`;
boxs.split(i,1);
break;
}
console.log(boxs[2].getBoundingClientRect())
}
}
},
directives:{
img:{
inserted(el,binding){
// console.log(el,binding);
el.style.backgroundColor="#"+Math.floor(Math.random()*1000000);
var img = new Image();
img.src= binding.value;
el.setAttribute("v-img",binding.value)
// img.onload=()=>{
// el.style.backgroundImage=`url(${binding.value})`;
// }
}
}
},
computed:{
flist:function(){
if(this.keyword==''){
return this.list;
//如果没有关键字 返回所有数据
}else{
if(isNaN(this.keyword)){
if(this.keyword[0]==">"){
return this.list.filter(item=>(item.age)>=parseInt(this.keyword.substring(1)));
}else if(this.keyword[0]=="<"){
return this.list.filter(item=>(item.age)<=parseInt(this.keyword.substring(1)));
}else{
return this.list.filter(item=>item.name.includes(this.keyword));
}
}else{
return this.list.filter(item=>(item.age+"").includes(this.keyword));
}
}
}
},
filters:{
fix:(val,arg=2,type="¥")=>{
if(isNaN(val)||val==""){return val}else{
let num = val.toFixed(arg);
let po = num.lastIndexOf(".");
let int = num.substring(0,po);
let ext = num.substring(po);
let arr = int.split("").reverse();
var s=[]
for(let i=0;i<arr.length;i++){
// 超过了3的倍数才在前面加逗号
//12345678 //123,456,678
if(i!==0&&i%3==0){
s.push(",")
console.log(arr[i],i)
}
s.push(arr[i]);
}
s.reverse().join('');
return type+s.join('')+ext;
}
},
fix2:(val,arg=2,type="¥")=>{
if(isNaN(val)||val==""){return val}else{
return type+val.toFixed(arg);
}
},
tel:(val,type=" ")=>{
var s=[];
var arr = val+''.split("");
for(var i=0;i<arr.length;i++){
s.push(arr[i]);
// 135 9885 9747
// 012 3456 78910
if(i==2||(i-2)%4==0&&i!=arr.length-1){
s.push(type)
}
}
return s.join('');
}
},
})
</script>
</body>
</html>
![](https://img.haomeiwen.com/i15480045/90fd87518f00b903.png)
5. watch 侦听器 (监听数据的变化)
watch:{
"obj":{
handler:function(val){
//当obj发生任何变化时都会触发handler函数
},
deep:true
//深层次监听(obj的属性发生变化时也会触发handler函数)
} }
单词
- deep 深的
- handler 处理器
- watch 监听
- computed 计算
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch
选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
例如:
<div id="watch-example">
<p>
Ask a yes/no question:
<input v-model="question">
</p>
<p>{{ answer }}</p>
</div>
<!-- 因为 AJAX 库和通用工具的生态已经相当丰富,Vue 核心代码没有重复 -->
<!-- 提供这些功能以保持精简。这也可以让你自由选择自己更熟悉的工具。 -->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!'
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
created: function () {
// `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
// 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
// AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
// `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
// 请参考:https://lodash.com/docs#debounce
this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
},
methods: {
getAnswer: function () {
if (this.question.indexOf('?') === -1) {
this.answer = 'Questions usually contain a question mark. ;-)'
return
}
this.answer = 'Thinking...'
var vm = this
axios.get('https://yesno.wtf/api')
.then(function (response) {
vm.answer = _.capitalize(response.data.answer)
})
.catch(function (error) {
vm.answer = 'Error! Could not reach the API. ' + error
})
}
}
})
</script>
结果:
Ask a yes/no question: <input>
I cannot give you an answer until you ask a question!
在这个示例中,使用 watch
选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
除了 watch
选项之外,您还可以使用命令式的 vm.$watch API。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch时刻监听数据变化</title>
</head>
<body>
<div id="app">
<button @click="num++">{{num}}</button>
<button @click="num+=2">{{num}}</button>
</div>
<script src="./js/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
num:1
},
watch:{
num:function(nval,oval){
console.log(`num的数由${oval}变化为${nval}`)
}
}
})
</script>
</body>
</html>
6. watch监听-对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>watch时刻监听数据变化</title>
</head>
<body>
<div id="app">
<button @click="obj.num++">{{obj.num}}</button>
<button @click="obj.num+=2">{{obj.num}}</button>
</div>
<script src="./js/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
obj:{num:1}
},
watch:{
obj:{
handler:function(val){
console.log(val,"数据发生变化")
},
deep:true,//监听对象的属性变化
}
}
})
</script>
</body>
</html>
7. 计算器案例-自动
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算器案例</title>
</head>
<body>
<div id="app">
<input type="text" v-model.number="obj.v1">
<select name="" id="" v-model="obj.type">
<option value="+">+</option>
<option value="-">-</option>
<option value="x">x</option>
<option value="÷">÷</option>
</select>
<input type="text" v-model.number="obj.v2">
= {{obj.v3}}
</div>
<script src="./js/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
obj:{v1:0,v2:0,v3:0,type:'+' }
},
methods:{
cal(){
if(this.obj.type=="+"){
this.obj.v3 = this.obj.v1+this.obj.v2
}
if(this.obj.type=="-"){
this.obj.v3 = this.obj.v1-this.obj.v2
}
if(this.obj.type=="x"){
this.obj.v3 = this.obj.v1*this.obj.v2
}
if(this.obj.type=="÷"){
this.obj.v3 = this.obj.v1/this.obj.v2
}
}
},
// 当obj的任意属性发生变化是 执行 cal这个方法 计算结果
// 监听 obj 执行cal
watch:{
"obj":{
handler:function(){
this.cal();
// 只要obj的数据发送变化就会值handler对应的函数
// 也就会执行 cal方法计算结果
},
deep:true
}
}
})
</script>
</body>
</html>
8. 搜索对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>computed 从现有数据计算出新的数据</title>
<style>
</style>
</head>
<body>
<div id="app">
<input type="text" v-model="keyword">
<table border="1">
<tr>
<td>名称</td>
<td>性别</td>
<td>年龄</td>
<td>电话</td>
</tr>
<tr v-for="(item,index) in flist" :key="index">
<td>{{item.name}}</td>
<td>{{item.sex}}</td>
<td>{{item.age}}</td>
<td>{{item.phone}}</td>
</tr>
</table>
</div>
<script src="./js/vue.js"></script>
<script>
new Vue({
el:"#app",
computed:{
flist:function(){
// 是否为空
if(this.keyword===''){
return this.list;
}else{
if(isNaN(this.keyword)){
// 如果是非数字
if(this.keyword[0]==">"){
//如果第一个符号是>
let num =this.keyword.substring(1);
return this.list.filter(item=>item.age>=num*1);
}else if(this.keyword[0]=="<"){
//如果第一个符号是< num*1转字符串为数字
let num =this.keyword.substring(1);
return this.list.filter(item=>item.age<=num*1);
}else{
// 非数字默认按名称搜索
return this.list.filter(item=>item.name.includes(this.keyword))
}
}else{
// 如果是数字
return this.list.filter(item=>(item.age+'').includes(this.keyword))
// (item.age+'') 转数字为字符串
}
}
// 1.如果为空 2.如果是数字
// 3. 字符串 4. > <
}
},
data:{
keyword:'',
list:[
{name: '张三', sex: '女', age: 19, phone: '18921212121'},
{name: '李四', sex: '男', age: 29, phone: '18921221121'},
{name: '王五', sex: '女', age: 39, phone: '18921788721'},
{name: '赵六', sex: '男', age: 49, phone: '18921556121'},
{name: '李四', sex: '男', age: 29, phone: '18921221121'},
{name: '王五', sex: '女', age: 39, phone: '18921788721'},
{name: '李四', sex: '男', age: 29, phone: '18921221121'},
{name: '王五', sex: '女', age: 39, phone: '18921788721'},
{name: '王五', sex: '女', age: 39, phone: '18921788721'},
{name: '赵六', sex: '男', age: 49, phone: '18921556121'},
{name: '李思思', sex: '男', age: 29, phone: '18921221121'},
{name: '张三', sex: '女', age: 19, phone: '18921212121'},
{name: '李四', sex: '男', age: 29, phone: '18921221121'},
{name: '王五', sex: '女', age: 39, phone: '18921788721'},
{name: '赵六', sex: '男', age: 49, phone: '18921556121'},
{name: '李四', sex: '男', age: 29, phone: '18921221121'},
{name: '王五', sex: '女', age: 39, phone: '18921788721'},
{name: '李四', sex: '男', age: 29, phone: '18921221121'},
{name: '王五', sex: '女', age: 39, phone: '18921788721'},
{name: '王五', sex: '女', age: 39, phone: '18921788721'},
{name: '赵六', sex: '男', age: 49, phone: '18921556121'},
{name: '李五五', sex: '男', age: 29, phone: '18921221121'}]
},
})
</script>
</body>
</html>
网友评论