如何在Laravel的Blade视图中调用ajax.php文件加载题库内容?
在Laravel Blade视图中正确调用AJAX题目接口的解决方案
问题的核心在于Laravel的架构和原生PHP环境不同:它依赖路由系统处理所有请求,直接放置在根目录的ajax.php无法被正确解析,而且Blade模板不会直接执行外部PHP文件的代码。我们需要把原有逻辑迁移到Laravel的MVC结构中,具体步骤如下:
1. 创建路由映射
首先在routes/web.php中添加一条POST路由,指向我们即将创建的控制器方法:
use App\Http\Controllers\QuizController; Route::post('/quiz/fetch-question', [QuizController::class, 'fetchQuestion'])->name('quiz.fetch'); Route::post('/quiz/check-answer', [QuizController::class, 'checkAnswer'])->name('quiz.check'); // 用于验证答案更新分数
2. 迁移业务逻辑到控制器
生成QuizController并将原ajax.php的逻辑重构为Laravel风格(注意修复SQL注入风险、使用Laravel封装的数据库和Session):
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Session; class QuizController extends Controller { public function fetchQuestion(Request $request) { // 验证传入参数 $request->validate([ 'next_id' => 'required|integer|min:0' ]); $nextId = $request->input('next_id'); // 重置分数逻辑 if ($nextId === 0) { Session::put('correct_score', 0); Session::put('not_correct_score', 0); } $totalQuestions = DB::table('questions')->count(); // 检测是否完成所有题目 if ($nextId >= $totalQuestions) { return view('quiz.results', [ 'correct' => Session::get('correct_score', 0), 'wrong' => Session::get('not_correct_score', 0) ]); } // 安全获取下一题(参数化查询避免注入) $question = DB::table('questions') ->where('id', '>', $nextId) ->orderBy('id', 'asc') ->first(); // 返回题目视图片段 return view('quiz.question', compact('question', 'nextId')); } // 新增:验证答案并更新分数的方法 public function checkAnswer(Request $request) { $request->validate([ 'question_id' => 'required|integer', 'selected_answer' => 'required|integer|between:1,4' ]); $question = DB::table('questions')->find($request->question_id); if ($question->correct_answer == $request->selected_answer) { Session::increment('correct_score'); return response()->json(['status' => 'correct']); } else { Session::increment('not_correct_score'); return response()->json(['status' => 'wrong']); } } }
3. 创建Blade视图片段
题目视图(resources/views/quiz/question.blade.php)
把原HTML改成Blade语法,修正单选按钮的name属性(确保同一题只能选一个选项):
<div id="question_{{ $question->id }}" class='question' data-next-question="{{ $question->id }}"> <h2>{{ $question->id . '.' . $question->question_name }}</h2> <div class='align'> <input type="radio" value="1" id='radio1' name='answer'> <label id='ans1' for='radio1'>{{ $question->answer1 }}</label> <br/> <input type="radio" value="2" id='radio2' name='answer'> <label id='ans2' for='radio2'>{{ $question->answer2 }}</label> <br/> <input type="radio" value="3" id='radio3' name='answer'> <label id='ans3' for='radio3'>{{ $question->answer3 }}</label> <br/> <input type="radio" value="4" id='radio4' name='answer'> <label id='ans4' for='radio4'>{{ $question->answer4 }}</label> </div> <br/> <button class='butt'>Next!</button> </div>
结果视图(resources/views/quiz/results.blade.php)
<div> <h2>Results:</h2> <p>Correct answers: {{ $correct }}</p> <p>Wrong answers: {{ $wrong }}</p> <button id="restart-quiz" class='butt'>Restart Quiz</button> </div>
4. 在主Blade视图中编写AJAX逻辑
比如在resources/views/quiz/main.blade.php中,使用jQuery发送请求并渲染内容:
<div id="quiz-container"></div> <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> <script> $(document).ready(function() { // 初始化加载第一题 loadQuestion(0); // 绑定Next按钮点击事件 $(document).on('click', '.butt', function() { let nextId = $(this).closest('.question')?.data('next-question') || 0; // 处理重新开始按钮 if ($(this).attr('id') === 'restart-quiz') nextId = 0; loadQuestion(nextId); }); // 绑定单选按钮选择事件(验证答案) $(document).on('change', 'input[name="answer"]', function() { let questionId = $(this).closest('.question').attr('id').split('_')[1]; let selectedAnswer = $(this).val(); $.post("{{ route('quiz.check') }}", { question_id: questionId, selected_answer: selectedAnswer, _token: "{{ csrf_token() }}" }, function(res) { // 可选:给用户反馈,比如高亮正确/错误选项 }); }); // 通用加载题目函数 function loadQuestion(nextId) { $.post("{{ route('quiz.fetch') }}", { next_id: nextId, _token: "{{ csrf_token() }}" }, function(html) { $('#quiz-container').html(html); }); } }); </script>
关键注意事项
- CSRF保护:Laravel默认启用CSRF保护,所有POST请求必须携带
_token参数,否则会被拦截。 - SQL注入防护:原代码直接拼接SQL存在注入风险,Laravel的查询构建器会自动处理参数绑定,一定要使用这种方式。
- Session管理:Laravel已经封装了Session,无需手动调用
session_start()。 - 单选按钮name属性:原代码中每个单选按钮的name不同,会导致用户可以多选同一题的多个选项,统一改为
name="answer"即可修复。
内容的提问来源于stack exchange,提问作者Zubair Nazer Oliyat
相关产品推荐
相关产品推荐

