zoukankan      html  css  js  c++  java
  • Vue3手册译稿

    计算属性

    模板内表达式是非常方便的,但它们是为简单操作设计的。太多的逻辑会造成模板臃肿难以维护。例如,有一个嵌套数组:

    Vue.createApp({
      data() {
        return {
          author: {
            name: '小明',
            books: [
              'Vue 2 - 高级手册',
              'Vue 3 - 基础手册',
              'Vue 4 - 神秘之旅'
            ]
          }
        }
      }
    })
    

    在作者是否有books时想展示不同的内容:

    <div id="computed-basics">
      <p>他的出版物::</p>
      <span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
    </div>
    

    这种情况下模板不再简单可读,你需要仔细阅读几秒钟才能意思到展示内容是依赖于author.books。如果在模板中想包含这个计算多次会导致更多的问题。
    这就是为什么响应式数据里含有复杂逻辑时就需要使用计算属性。

    基础示例

    <!DOCTYPE html>
    <html lang="en-US">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <title>vue demo4</title>
    	<script src="https://unpkg.com/vue@next"></script>
       </head>
       <body>
    		<div id="app">
    			<p>他的出版物:</p>
    			<span>{{ publishedBooksMessage }}
    		</div>
       </body>
       <script type="text/javascript">
    	const app = {
    		data() {
    			return {
    			  author: {
    				name: '小明',
    				books: [
    				  'Vue 2 - 高级手册',
    				  'Vue 3 - 基础手册',
    				  'Vue 4 - 神秘之旅'
    				]
    			  }
    			}
    		 },
    		 computed: {
    				// 计算属性寄存器
    				publishedBooksMessage() {
    					return this.author.books.length>0? 'Yes':'No'
    				}
    		}
    	}
    	Vue.createApp(app).mount("#app")
       </script>
    </html>
    

    我们定义了一个计算属性publishedBooksMessage。试着更改data中的books数组,publishedBooksMessage也会相应的发生改变。
    你可以在模板中像普通属性一样绑定计算属性,Vue会知道vm.publishedBooksMessage依赖于vm.author.books,所以会连动变化。最妙的是我们已声明式的创建了它们之间的依赖关系:计算属性寄存器函数没有副作用,反而更加容易测试和理解。

    计算属性缓存 VS 方法

    你可能注意到了,我们可以通过方法来实现一样的功能:

    <p>{{ calculateBooksMessage() }}
    
    // 组件实例中
    methods: {
      calculateBooksMessage() {
        return this.author.books.length > 0 ? 'Yes' : 'No'
      }
    }
    

    计算属性和方法也确实得到了相同的结果。不同点是计算属性缓存响应式依赖关系。依赖数据源不变化,多次调用计算属性直接返回前面缓存的计算结果。就是说author.books没有发生变化,调用publishedBooksMessage会立即返回前面缓存的计算结果而不需要重新运行函数。

    下面这个计算属性永远不会更新,因为Date.now()不是响应式依赖:

    computed: {
        now()  {
            return Date.now()
        }
    }
    

    相对而言,调用方法不管有没有重新渲染都会重复执行。


    为什么要缓存计算属性?相像一下,有一个非常耗费资源的list属性,在计算属性中需要遍历这个大型数组,而且有其他的计算属性依赖于list,如果不缓存我们就会没有必要的反复耗费资源来读取list。如果不想缓存就用方法来代替。

    计算属性 Setter

    计算属性默认是只读的,但如果需要你也可以进行set:

    <!DOCTYPE html>
    <html lang="en-US">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <title>vue demo6</title>
    	<script src="https://unpkg.com/vue@next"></script>
       </head>
       <body>
    		<div id="app">
    			
    		</div>
       </body>
       <script type="text/javascript">
    	const app = {
    		data() {
    			return {
    			  firstName : 'zhou',
    			  lastName : 'yu'
    			}
    		 },
    		 computed: {
    		  fullName: {
    			// getter
    			get() {
    			  return this.firstName + ' ' + this.lastName
    			},
    			// setter
    			set(newValue) {
    			  const names = newValue.split(' ')
    			  this.firstName = names[0]
    			  this.lastName = names[names.length - 1]
    			}
    		  }
    		}
    	}
    	const vm = Vue.createApp(app).mount("#app")
    	// get
    	console.log(vm.fullName)
    	// set 
    	vm.fullName = 'John Doe'
    	console.log(vm.fullName)
       </script>
    </html>
    

    现在你执行vm.fullName = 'John Doe',set方法会更新vm.firstNamevm.lastName

    监听器

    计算属性适用于大部分案例,是时候定制一个监听器了。Vue提供了很多通用的途径通过监听观察数据的变化。这在执行异步和耗时操作时监听返回数据变化时非常有用:

    <!DOCTYPE html>
    <html lang="en-US">
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <title>vue demo7</title>
    	<script src="https://unpkg.com/vue@next"></script>
    	<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
       </head>
       <body>
    		<div id="app">
    			对/错提问:
    			<input v-model="question" />
    			<p>{{ answer }}</p>
    			<p v-if="question_img">
    				<img :src="question_img" />
    			</p>
    		</div>
       </body>
       <script type="text/javascript">
    	const app = {
    		data() {
    		  return {
    			question: '',
    			answer: '问题一般以问号结束哦. ;-)',
    			question_img: '',
    			count: 0
    		  }
    		},
    		watch: {
    		  // 无论问题是否变化,这个函数都会执行
    		  question(newQuestion, oldQuestion) {
    			console.log("执行" + (++this.count) + "次")
    			if (newQuestion.indexOf('?') > -1 || newQuestion.indexOf("?")>0) {
    			  this.getAnswer()
    			}
    		  }
    		},
    		methods: {
    		  getAnswer() {
    			this.answer = '思考中...'
    			axios
    			  .get('https://yesno.wtf/api')
    			  .then(response => {
    				this.answer = response.data.answer
    				this.question_img = response.data.image
    			  })
    			  .catch(error => {
    				this.answer = '错误! 网络访问失败. ' + error
    			  })
    		  }
    		}
    	}
    	Vue.createApp(app).mount('#app')
       </script>
    </html>
    

    输入一个问题,以问号结束,执行结果:

    上面这个示例,使用watch选项演示了一个异步操作(网络访问API)。computed实现不了。

    计算属性 VS 监听属性,

    Vue提供了一个更加通用的方法实现当前活动实例的数据响应和监听:监听属性,如果有些数据依据其他数据的变化而变化,会导致滥用watch -- 特别是你有AngularJS背景。但是,很多时候使用计算属性比使用watch回调更好。看下面的例子:

    <div id="demo">{{ fullName }}</div>
    
    const vm = Vue.createApp({
      data() {
        return {
          firstName: 'Foo',
          lastName: 'Bar',
          fullName: 'Foo Bar'
        }
      },
      watch: {
        firstName(val) {
          this.fullName = val + ' ' + this.lastName
        },
        lastName(val) {
          this.fullName = this.firstName + ' ' + val
        }
      }
    }).mount('#demo')
    

    上面这些代码是命令式且重复的,与计算属性比较下:

    const vm = Vue.createApp({
      data() {
        return {
          firstName: 'Foo',
          lastName: 'Bar'
        }
      },
      computed: {
        fullName() {
          return this.firstName + ' ' + this.lastName
        }
      }
    }).mount('#demo')
    

    是不是好多了?

  • 相关阅读:
    docker出现如下错误:Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
    docker 常用的命令
    postman的使用大全
    plsql连接数据库出现乱码
    mybatis从mapper接口跳转到相应的xml文件的eclipse插件
    PWC6345: There is an error in invoking javac. A full JDK (not just JRE) is required
    解决java compiler level does not match the version of the installed java project facet【转载】
    使用maven时出现Failure to transfer 错误的解决方法
    QT5 网络通讯
    c/c++ 贪吃蛇控制台版
  • 原文地址:https://www.cnblogs.com/zhouyu629/p/14469810.html
Copyright © 2011-2022 走看看