Vue结合Symfony项目无法从Ajax返回结果加载动态组件求助
解决方案
核心问题原因
你通过原生innerHTML接口插入的<gamecard>自定义标签,不会被已初始化的Vue实例自动编译。Vue只会在实例初始化挂载阶段编译一次对应挂载节点下的DOM,后续手动插入的自定义组件标签无法被识别渲染,仅会作为普通未知标签存在。此外你当前代码中重复注册了Gamecard组件,同步导入+异步导入的写法属于冗余逻辑,可删除其中一种。
方案1:推荐实现(Vue统一管理列表渲染,性能最优)
该方案完全由Vue控制组件渲染逻辑,避免混用原生DOM操作和Vue响应式逻辑。
1. 修改控制器AJAX响应
不再返回渲染后的Twig HTML片段,直接返回游戏数据的JSON数组:
if ($request->isXMLHttpRequest()) { $gameData = array_map(function($game) { return [ 'id' => $game->getId(), 'name' => $game->getName(), 'description' => $game->getDescription(), 'tourneyscount' => count($game->getTourneys()) . ' active tourneys' ]; }, $gameList); return new JsonResponse( [ 'code' => Response::HTTP_OK, 'games' => $gameData ] ); } return $this->render('home/index.html.twig', [ 'games' => $gameList ]);
2. 修改Twig模板,注入初始数据
在home/index.html.twig中注入初始游戏数据供Vue读取:
<div id="game-card"> <gamecard v-for="game in games" :key="game.id" :name="game.name" :description="game.description" :tourneyscount="game.tourneyscount" ></gamecard> </div> <script> window.initialGames = {{ games|json_encode(constant('JSON_HEX_TAG'))|raw }} </script>
3. 调整Vue实例逻辑
import Vue from 'vue'; import Gamecard from './../../components/Gamecard' new Vue({ el: '#game-card', components: { Gamecard }, data() { return { games: window.initialGames || [], page: 1, canLoad: true } }, mounted() { // 绑定你原有的滚动监听逻辑 window.addEventListener('scroll', this.handleScroll) }, methods: { handleScroll() { // 替换为你原有的滚动到底部判断逻辑 const scrollBottom = window.innerHeight + window.scrollY >= document.body.offsetHeight - 100 if (scrollBottom && this.canLoad) { this.loadMore() } }, async loadMore() { this.canLoad = false try { const res = await fetch(`?page=${this.page + 1}`, { headers: {"X-Requested-With": "XMLHttpRequest"} }) const data = await res.json() if (data.code === 200 && data.games.length) { this.games = [...this.games, ...data.games] this.page += 1 this.canLoad = true } else { this.canLoad = false } } catch (e) { this.canLoad = false } } } })
方案2:兼容现有代码的快速修复
如果你不想改动现有Twig渲染逻辑,可手动编译新插入的DOM节点,修改你的AJAX请求逻辑即可:
fetch('?page=' + page, { headers: { "X-Requested-With": "XMLHttpRequest" } }) .then(response => response.json()) .then(function (response) { if (response.code === 200) { const container = document.getElementById('game-card') const tempNode = document.createElement('div') tempNode.innerHTML = response.cards // 逐个插入新节点并编译组件 Array.from(tempNode.children).forEach(child => { const mountedNode = container.appendChild(child) new Vue({ el: mountedNode, components: { Gamecard } }) }) canLoad = true; } else { canLoad = false; } });
内容的提问来源于stack exchange,提问作者Nitharandis
相关产品推荐
相关产品推荐

