如何在一个文件中写多个Vue组件(译-有删改)

本文探讨了在Vue中如何在一个文件内编写多个组件,包括使用render函数、Vue.component与template、仅使用template以及利用JSX的方法。详细介绍了每种方式的实现,并提到了在Vue的不同构建版本中可能遇到的问题及其解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址 Writing multiple Vue components in a single file

在一个文件中编写多个组件是React的模式,其中一些文件包含多个组件。

走开发过程中,有些组件对文件/导出组件是“私有的”,因为没有其他组件需要使用它们。这个时候我们倾向于把它们写到一个文件中。


我们将使用vue-cli脚手架项目中的默认“Hello World”组件作为示例。

默认情况下,有两个文件,App和HelloWorld,HelloWorld接收msg属性并呈现它。

要将它们写在单个文件中,如果用React实现的话一般如下所示:

const HelloWorld = ({ msg }) => (<div>
  <h1>Hello world</h1>
  <div>{msg}</div>
</div>);

const App = () => (<div id="app">
  <HelloWorld msg="Welcome to Your React App" />
</div>);

export default App;

由于React代码实际上就是普通的JavaScript,因此您可以在一个文件中定义多个组件。

在Vue中,它仍然是可能的,但它有点复杂,有多种方法可以实现:


示例仓库 vue-multiple-components-in-sfc

一. 使用render函数

<template>
  <div id="app">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
<script>
// inline component
const HelloWorld = {
  props: ['msg'],
  render(h) {
    return h('div', [
      h('h1', 'Hello world'),
      h('div', this.msg)
    ])
  }
};
export default {
  name: 'app',
  components: {
    HelloWorld
  }
}
</script>
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

二. 使用Vue.component和template

<template>
  <div id="app">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
<script>
import Vue from 'vue';
// inline component with template string 👍
const HelloWorld = Vue.component('hello-world', {
  props: ['msg'],
  template: `<div>
    <h1>Hello world</h1>
    <div>{{ this.msg }}</div>
  </div>`
});
export default {
  name: 'app',
  components: {
    HelloWorld
  }
}
</script>
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

但是这种方式不能在Vue Runtime-only构建版本上生效,会有如下的错误提示
在这里插入图片描述关于Vue几种不同构建版本的区别可以参考:Explanation of Different Builds

上面的问题可以使用带compiler的Vue构建版本来修复

例如:

//Webpack
module.exports = {
  // ...
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js' // 'vue/dist/vue.common.js' for webpack 1
    }
  }
}
JavaScriptCopy

或者vue.config.js中添加:

module.exports = {
  runtimeCompiler: true
};

三. 仅使用template而不使用Vue.component

<template>
  <div id="app">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
<script>
// inline component with template string 👍
const HelloWorld = {
  props: ['msg'],
  template: `<div>
    <h1>Hello world</h1>
    <div>{{ this.msg }}</div>
  </div>`
};
export default {
  name: 'app',
  components: {
    HelloWorld
  }
}
</script>
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

这个方法也需要带compiler的Vue构建版本

四.使用JSX(编译为渲染函数)

我们可以用JSX重写我们的初始渲染函数示例 App.js:

<template>
  <div id="app">
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>
<script>
// inline component with JSX
const HelloWorld = {
  props: ['msg'],
  render() {
    return (<div>
      <h1>Hello world</h1>
      <div>{this.msg}</div>
    </div>);
  } 
};

export default {
  name: 'app',
  components: {
    HelloWorld
  }
}
</script>
<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

Vue CLI 3+已经配置了babel-plugin-transform-vue-jsx

### 使用 `vue-table-with-tree-grid` 实现增删改操作 #### 安装与引入组件 为了使用 `vue-table-with-tree-grid` 组件并实现数据的增删改功能,首先需要按照官方文档完成安装和基本配置。 通过 npm 安装该组件包: ```bash npm install vue-table-with-tree-grid --save ``` 接着,在项目的入口文件(通常是 main.js 或 app.js)中全局注册这个插件[^3]: ```javascript import Vue from &#39;vue&#39;; import ZkTable from &#39;vue-table-with-tree-grid&#39;; Vue.use(ZkTable); ``` #### 数据模型定义 对于树形表格来说,每一项记录都应该有一个唯一的标识符以及表示父关系的关键字段。通常情况下会包含如下几个重要属性: - id (唯一键) - parentId (父节点ID, 如果是最顶级则为空或0) - name/title/label (显示名称) 这些信息用于构建层次化的视图结构,并支持后续的操作逻辑处理。 #### 创建带有 CRUD 功能的方法 ##### 添加新行方法 当用户点击新增按钮时触发此函数来向列表里追加一条新的级项目,默认设置其为展开状态以便立即编辑输入框内的内容[^4]: ```javascript addNewRow(parentId) { const newRow = {id: this.generateUUID(), parentId, title: &#39;&#39;, _expanded: true}; if (!parentId) { this.tableData.push(newRow); // 若无指定父级,则作为根节点加入数组末端 } else { let parentIndex = this.findParentIndexById(parentId); if (parentIndex !== -1 && Array.isArray(this.tableData[parentIndex].children)) { this.$set(this.tableData[parentIndex], "children", [...this.tableData[parentIndex].children, newRow]); } } } ``` ##### 删除选中行方法 移除当前被选中的那一行及其所有的后代节点,确保不会留下孤立的数据片段[^5]: ```javascript deleteSelectedRows() { function removeChildren(data, idsToDelete) { data.forEach((item, index) => { if (idsToDelete.includes(item.id)) { data.splice(index, 1); } else if (Array.isArray(item.children)) { item.children = removeChildren(item.children, idsToDelete).filter(Boolean); } }); return data; } let selectedIds = this.selectedItems.map(({id})=>id); this.tableData = removeChildren([...this.tableData], selectedIds); } ``` ##### 更新现有条目方法 允许修改已存在的某一行的信息,这里假设我们只更改了title这一列的内容[^2]: ```javascript updateExistingItem(updatedItem){ function updateItemRecursively(data, updatedItemId, newValue){ for(let i=0; i<data.length;i++){ if(data[i].id === updatedItemId){ Object.assign(data[i],newValue); break; }else if(Array.isArray(data[i].children)){ updateItemRecursively(data[i].children,updatedItemId,newValue); } } } updateItemRecursively(this.tableData, updatedItem.id,{...updatedItem}); } ``` 以上就是基于 `vue-table-with-tree-grid` 的一些基础CRUD操作方式介绍。实际应用过程中可能还需要考虑更多细节问题比如验证规则、异步加载等特性集成进去以满足具体业务场景的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值