方法(methods)
<template>
<div>
<p>原始数据:{{message}}"</p>
<p>反转后的数据:"{{reverseMessage()}}"</p>
</div>
</template>
<script>
export default {
data(){
return {
message:"hello"
}
},
methods:{
reverseMessage:function(){
return this.message.split('').reverse().join('')
}
}
}
</script>
计算属性 (computed)
<template>
<div>
<p>原始数据:{{message}}"</p>
<p>反转后的数据:"{{reversedMessage}}"</p>
</div>
</template>
<script>
export default {
data(){
return {
message:"hello"
}
},
computed:{
reversedMessage:function(){
return this.message.split('').reverse().join('')
}
}
}
</script>
计算属性默认只有getter
。
本例中,计算属性computed.reversedMessage
的getter
就是
function(){ return this.message.split('').reverse().join('') }
。
当然,也可以将该函数直接写成getter
,像这样,
//也可以直接写成getter
computed:{
reversedMessage:{
get(){
return this.message.split('').reverse().join('')
}
}
}
有getter
,当然也可以提供setter
,如下,
//当然,也可以提供setter
computed:{
reversedMessage:{
get(){
return this.message.split('').reverse().join('')
},
set(val){
this.message = val+"hahaha";
}
}
},
呃,对比下,方法 和 计算属性 好像没啥区别,都实现了字符串反转。
别着急下定论,继续往下看。
方法 与 计算属性
<template>
<div>
<p>原始数据:{{message}}"</p>
<p>反转后的数据:"{{reverseMessage()}}"</p>
<p>反转后的数据:"{{reversedMessage}}"</p>
</div>
</template>
<script>
export default {
data(){
return {
message:"hello"
}
},
methods:{
reverseMessage:function(){
console.log("reversing message in methods at "+ new Date().toLocaleTimeString());
return this.message.split('').reverse().join('')
}
},
computed:{
reversedMessage:function(){
console.log("reversing message in computed at "+ new Date().toLocaleTimeString());
return this.message.split('').reverse().join('')
}
},
mounted:function(){
setTimeout(() => {
this.$forceUpdate();
},5000);
// setTimeout(() => {
// this.message = "world";
// },3000)
}
}
</script>
5秒后,强制组件重新渲染。
这时,方法中的函数reverseMessage
再次执行了,但 计算属性reversedMessage
的getter
函数没有被再次调用,因为 它被 缓存 了。
是的,计算属性会被缓存,且只有它依赖的数据发生变化时,计算属性才会更新。
数据监听
当一个数据依赖另一个数据时,要实现数据同步, 计算属性 是一个方法。
另一个方法就是 使用watch
监听数据。
<template>
<div>
<p>原始数据:{{message}}"</p>
<p>反转后的数据:"{{reversedMessage}}"</p>
</div>
</template>
<script>
export default {
data(){
return {
message:"",
reversedMessage:''
}
},
watch:{
message:function(newMessage){
this.reversedMessage = newMessage.split('').reverse().join('')
}
},
mounted:function(){
setTimeout(() => {
this.message = "hello";
},3000)
}
}
</script>
监听message
,当它发生变化时,同步更新reversedMessage
。
watch在异步中的应用
代码结构
服务端
- answers.json
{
"0":"Yes",
"1":"Yes",
"2":"No"
}
- server.js
const express = require("express");
const fs = require("fs");
const app = express();
app.use(express.static("../dist"));
app.get("/get/:id",(req,res) => {
fs.readFile('./answers.json','utf-8',(err,data)=>{
var data = JSON.parse(data);
const answer = data[req.params.id];
res.writeHead(200,"ok",{"Content-Type":"text/plain"});
res.end(answer);
})
})
app.listen(3000,()=>{
console.log("listening on *:3000");
})
客户端
- webpack.config.js
const path = require('path');
const VueLoaderPlugin = require("vue-loader/lib/plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
module.exports = {
mode:"development",
devtool:"cheap-source-map",
entry:{
"index":"./index.js"
},
output:{
filename:"[name].bundle.js",
path:path.resolve(__dirname,"dist")
},
module:{
rules:[
{
test:/\.vue$/,
loader:'vue-loader'
},
{
test:/\.css$/,
loader:[
'vue-style-loader',
'css-loader'
]
},
{
test:/\.js$/,
loader:'babel-loader'
}
]
},
plugins:[
new VueLoaderPlugin(),
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template:'./index.html'
})
]
}
- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>index</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
- index.js
import Vue from "vue";
import Helloworld from "./src/helloworld.vue";
const vm = new Vue({
render:(h) => h(Helloworld),
}).$mount("#root");
- helloworld.vue
npm install --save lodash axios
这里用到了防抖_.debounce(fn,delay)
,保证输入框输入完毕方发送请求。
<template>
<div>
<p><input type="text" v-model="question" /></p>
<p>{{answer}}</p>
</div>
</template>
<script>
import _ from "lodash";
import axios from "axios";
export default {
data(){
return {
question:"",
answer:"I cannot give u an answer util u ask a question!"
}
},
watch:{
question:function(newQuestion,oldQuestion){
this.answer = "waiting for u to stop typing...";
this.debounceGetAnswer();
}
},
created:function(){
this.debounceGetAnswer = _.debounce(this.getAnswer,500);
},
methods:{
getAnswer:function(){
const idx = parseInt(Math.random()*2);
const vm = this;
axios.get("/get/"+idx).then((response) => {
vm.answer = response.data;
}).catch(err => {
vm.answer = "An error occurred,cannot get answer";
})
}
}
}
</script>
node server.js
,启动服务端,
浏览器地址栏输入localhost:3000
,效果如下: