跳到主要内容

Methods

我在向组件实例添加方法时,所有的方法都会挂载在实例上。

<!-- `greet` 是上面定义过的方法名 -->
<button @click="greet">Greet</button>

data() {
return {
name: 'Vue.js'
}
},
methods: {
greet(event) {
// 方法中的 `this` 指向当前活跃的组件实例
alert(`Hello ${this.name}!`)
// `event` 是 DOM 原生事件
if (event) {
alert(event.target.tagName)
}
}
}

使用 methods

在创建 Vue 实例时,methods 会自动绑定当前实例的 this,确保在事件监听时,回调始终指向当前组件实例。

在定义 methods 时,应避免使用箭头函数,因为箭头函数会阻止 Vue 正确绑定组件实例。

例如,使用 @click="greet" 时,方法名后面的括号 () 并不是执行符号,而是用于传递参数的容器。以下是分解写法:

onClick = { () => changeTitle('This is your TITLE') }

在模板中直接调用方法时,应尽量避免副作用。这样可以确保组件的可预测性和可维护性。

直接绑定方法执行

<h2>{{ yourTitle() }}</h2>

methods: {
yourTitle () {
return 'This is your TITLE';
},
}

JS 工具库 Lodash

Lodash 使 JavaScript 开发更加简便,减少了处理数组、数字、对象和字符串等的复杂性。常用的功能如节流、防抖和时间过期等,Lodash 都有涵盖。

https://github.com/lodash/lodash

使用方法

以下是一个使用 Lodash 实现节流功能的示例:

const TeacherList = {
data() {
return {
teachers: [],
};
},
template: `
<div>
<table border="1">
<thead>
<tr>
<td>ID</td>
<td>姓名</td>
<td>学科</td>
</tr>
</thead>
<tbody v-if="teachers.length > 0">
<tr v-for="teacher in teachers" :key="teacher.id">
<td>{{ teacher.id }}</td>
<td>{{ teacher.name }}</td>
<td>{{ teacher.subject }}</td>
</tr>
</tbody>
<tbody v-else>
<tr>
<td colspan="3">暂无数据</td>
</tr>
</tbody>
</table>
<button @click="debouncedFetchTeachers">获取教师数据</button>
</div>
`,
created() {
// 使用 Lodash 的 debounce 方法防抖
this.debouncedFetchTeachers = _.debounce(this.fetchTeachers, 1000);
},
unmounted() {
// 组件卸载时取消防抖函数
this.debouncedFetchTeachers.cancel();
},
methods: {
async fetchTeachers() {
try {
const response = await axios.get('http://localhost:8081/getTeachers');
this.teachers = response.data;
} catch (error) {
console.error('获取教师数据失败:', error);
}
},
},
};

Vue.createApp(TeacherList).mount('#app');

实现 methods

下面是一个简单的 Vue 实现,展示了如何初始化数据和方法:

var Vue = (function () {
function Vue(options) {
this.$data = options.data();
this._methods = options.methods;

this._init(this);
}

Vue.prototype._init = function (vm) {
initializeData(vm);
initializeMethods(vm);
};

function initializeData(vm) {
for (var key in vm.$data) {
(function (key) {
Object.defineProperty(vm, key, {
get: function () {
return vm.$data[key];
},
set: function (newValue) {
vm.$data[key] = newValue;
},
});
})(key);
}
}

function initializeMethods(vm) {
for (var key in vm._methods) {
vm[key] = vm._methods[key].bind(vm);
}
}

return Vue;
})();

var vm = new Vue({
data() {
return {
countA: 1,
countB: 2,
};
},
methods: {
incrementA(amount) {
this.countA += amount;
},
incrementB(amount) {
this.countB += amount;
},
calculateTotal() {
console.log(this.countA + this.countB);
},
},
});

console.log(vm);

vm.incrementA(1);
vm.incrementA(1);
vm.incrementA(1);
vm.incrementA(1);
// countA 5

vm.incrementB(2);
vm.incrementB(2);
vm.incrementB(2);
vm.incrementB(2);
// countB 10

vm.calculateTotal(); // 15

在这个实现中,initializeData 函数通过 Object.defineProperty 将数据属性代理到实例上,使得可以直接通过 vm.countA 访问和修改数据。同时,initializeMethods 函数绑定了所有方法到实例,确保 this 指向正确的组件实例。