美文网首页
3-vue计算 过滤 监听

3-vue计算 过滤 监听

作者: Daeeman | 来源:发表于2020-03-17 20:39 被阅读0次

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>
a.png b.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>
c.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>

相关文章

网友评论

      本文标题:3-vue计算 过滤 监听

      本文链接:https://www.haomeiwen.com/subject/ogyxyhtx.html