Vue3入门(1)简单的用户列表页
使用 CDN 开发 Vue3
使用 CDN 是入门 Vue 的好方法之一,适用于小型项目或简单页面增强、渐进式增强传统网站、修改老项目、教育和学习目的。
这种方式不需要复杂的构建工具配置,减少了环境搭建的时间,使得开发者可以迅速开始编码。
简单的用户列表页
用户列表页一般有 搜索、列表、分页 等部分。
假设已有获取用户列表的 路由 与 控制器:
Route::get('getUserList', "UserController@getUserList");public function getUserList(Request $request){$query = User::query();if ($request->has('nickname') && !empty($request->input('nickname'))) {$query->where('nickname', 'like', '%' . $request->input('nickname') . '%');}if ($request->has('status') && !empty($request->input('status'))) {$query->where('status', $request->input('status'));}$users = $query->orderBy('id', 'desc')->paginate(5);return response()->json($users);
}
页面 list.blade.php:
<!-- 导入Vue3文件 -->
<script src="{{asset('/js/vue.global.js')}}"></script><!-- 防止闪烁现象 -->
<style type="text/css">[v-cloak] {display: none;}
</style><div id="app" v-cloak><!-- 搜索部分 --><!-- @submit:Vue中用于监听HTML表单提交事件的简写形式(原生javascript里的onsubmit)。当用户点击提交按钮或者按下回车键时触发该事件。--><!--.prevent 是一个事件修饰符,它会调用事件对象的 event.preventDefault()方法。这意味着它可以阻止元素的默认行为。对于表单来说,默认行为通常是页面刷新并尝试将数据发送到服务器(基于表单的action属性)。如果你正在构建一个单页应用(SPA),你可能不希望这种行为发生,而是希望通过AJAX请求来处理表单提交。--><form @submit.prevent="searchUsers">昵称:<input type="text" class="form-control" v-model="search.nickname">状态:<select class="form-select" v-model="search.status"><option value=""></option><option value="1">正常</option><option value="2">锁定</option></select><button type="submit" class="btn btn-primary">搜索</button></form><!-- 列表渲染 --><!-- 加载状态 --><div v-if="loading">正在加载数据...</div><!-- 错误提示 --><div v-else-if="error">@{{ error }}</div><table class="table" v-else><thead><tr><th scope="col">昵称</th><th scope="col">状态</th></tr></thead><tbody><tr v-for="user in users" :key="user.id"><td>@{{user.nickname}}</td><td v-html="user.status === 1 ? badgeHtml('bg-success', '正常') : badgeHtml('bg-secondary', '锁定')"></td></tr></tbody></table><!-- 分页部分 --><nav v-if="!loading && users.length"><ul class="pagination"><li class="page-item"><!-- 在Vue.js中,:是v-bind的简写形式,用于动态绑定HTML属性或组件prop到Vue实例的数据。当你看到:disabled="current_page === 1"这样的用法时,它实际上是在利用Vue的响应式系统来动态地设置HTML元素的disabled属性。任何合法的HTML属性或自定义属性都可以通过 v-bind来动态绑定。比如常用的有 :class,:style,:href,:src,:alt,:value,:checked,:selected--><a class="page-link" href="javascript:;" @click="goToPage(current_page - 1)" :disabled="current_page === 1">上一页</a></li><li class="page-item" v-for="page in pages" :key="page" :class="{ active: current_page === page }"><a class="page-link" href="javascript:;" @click="goToPage(page)">@{{ page }}</a></li><li class="page-item"><a class="page-link" href="javascript:;" @click="goToPage(current_page + 1)" :disabled="current_page === last_page">下一页</a></li></ul></nav>
</div><script type="module">const { createApp, ref, onMounted, computed } = Vueconst app = createApp({// 更改默认插值符号,防止与blade模板的{{}}冲突delimiters: ['@{{', '}}'],setup() {// 用户列表const users = ref([]);// 列表渲染前先显示加载中const loading = ref(true);// 网络请求出错时显示错误信息const error = ref(null);// 分页部分const current_page = ref(1);// 当前页码const last_page = ref(1); // 总页数const visiblePagesCount = 5;// 要显示的页码数量(比如上一页与下一页之间的那块儿)// 搜索条件const search = ref({nickname: '', status: ''});// 获取用户列表const fetchData = async (page = 1) => {try {let queryParams = new URLSearchParams();// 添加页码queryParams.append('page', page);// 添加搜索条件if (search.value.nickname) queryParams.append('nickname', search.value.nickname);if (search.value.status) queryParams.append('status', search.value.status);// 获取数据const res = await fetch(`getUserList?${queryParams.toString()}`);if (!res.ok) throw new Error('网络错误');const data = await res.json();// laravel返回分页格式的数据对象,因此再.datausers.value = data.data;// 设置分页参数last_page.value = data.last_page;current_page.value = data.current_page;}catch(err){// 显示错误信息error.value = err.message;}finally {// 不管成功或失败,都把页面的“加载中”去掉loading.value = false;}}// 计算属性:上一页与下一页之间的那块儿const pages = computed(() => {const total = last_page.value;const currentPage = current_page.value;const pageCount = visiblePagesCount;let start = Math.max(1, currentPage - Math.floor(pageCount / 2));let end = start + pageCount - 1;if (end > total) {end = total;start = Math.max(1, end - pageCount + 1);}const result = [];for (let i = start; i <= end; i++) {result.push(i);}return result;})// 去第N页const goToPage = (page) => {if (page >= 1 && page <= last_page.value) {fetchData(page);}};// 点击搜索按钮提交时const searchUsers = () => {current_page.value = 1; // 重置当前页为第一页fetchData(); // 根据新的搜索条件重新获取数据};// 如果使用bootstraps之类的,由于vue的{{}}只能是js表达式,因此不能写html代码。此时可以用v-html来绑定使用const badgeHtml = (className, text) => {return `<span class="badge ${className}">${text}</span>`;};// 页面加载时获取数据onMounted(() => {fetchData();});return {users,loading,error,current_page,last_page,goToPage,pages,search,searchUsers,badgeHtml};}})// 告诉Vue忽略'content'标签app.config.compilerOptions.isCustomElement = tag => tag === 'content'; app.mount('#app')
</script>