当前位置:   article > 正文

超详细的前后端实战项目(Spring系列加上vue3)前端篇(二)(一步步实现+源码)_vue+spring

vue+spring

好了,兄弟们,继昨天的项目之后,开始继续敲前端代码,完成前端部分

昨天完成了全局页面的代码,和登录页面的代码,不过昨天的代码还有一些需要补充的,这里添加一下

内容补充:在调用登录接口之后进行一个页面的跳转

先介绍一下router路由的使用吧(知道的兄弟们可以跳过哦)

页面的路由:1.安装vue-router :npm install vue-router @4 (在终端输入命令即可)。2.在index.js中创建路由器并导出。3.main.js中使用,4.<router-view>中展示

(这里因为刚开始创建项目的时候点击了vue Router,脚手架已经帮我们生成好了,那就不用管了,前三步自动完成,我们只管使用就好了)

这里在Login页面中添加

  1. import {useRouter} from 'vue-router'
  2. const router = useRouter()
  3. const login = async()=>{
  4. let result = await userLoginService(loginData.value);
  5. renderIcon(result.msg?result.msg:'登录成功');
  6. router.push('/')
  7. }

添加完这几行代码就OK了,这里我们可以试一下能不能跳转,

emmmm,因为暂时没有进行后端的开发,如果要测试的话,此时要么把调用后端的函数给注释了,要么使用接口测试工具(感觉好麻烦)

  1. <script setup>
  2. // import { h } from 'vue';
  3. // import { IconExclamationCircleFill } from '@arco-design/web-vue/es/icon';
  4. import { ref } from "vue";
  5. // import {userLoginService} from '../api/user'
  6. import {useRouter} from 'vue-router'
  7. const router = useRouter()
  8. const loginData = ref({
  9. username: "",
  10. password: "",
  11. isRead: false,
  12. });
  13. const rules = [
  14. {
  15. validator: (value, cb) => {
  16. return new Promise((resolve) => {
  17. window.setTimeout(() => {
  18. if (value !== " ") {
  19. cb("content not empty");
  20. }
  21. resolve();
  22. }, 1000);
  23. });
  24. },
  25. },
  26. ];
  27. // const renderIcon = () => h(IconExclamationCircleFill);
  28. const login = async()=>{
  29. // let result = await userLoginService(loginData.value);
  30. // renderIcon(result.msg?result.msg:'登录成功');
  31. router.push('/')
  32. }
  33. </script>

方便起见,还是用注释吧。

OK,我们来运行一下代码

在点击了Submit之后,成功跳转到了主页面,(记得把函数的注释去掉)

内容补充,GlobalPage.vue的样式修改(改了一下布局,现在能全局了)

  1. <style scoped>
  2. .global{
  3. height: 100vh;
  4. }
  5. .layout-demo :deep(.arco-layout-header),
  6. .layout-demo :deep(.arco-layout-footer),
  7. .layout-demo :deep(.arco-layout-sider-children),
  8. .layout-demo :deep(.arco-layout-content) {
  9. display: flex;
  10. flex-direction: column;
  11. justify-content: center;
  12. color: var(--color-white);
  13. font-size: 16px;
  14. font-stretch: condensed;
  15. text-align: center;
  16. }
  17. .layout-demo :deep(.arco-layout-header),
  18. .layout-demo :deep(.arco-layout-footer) {
  19. height: 64px;
  20. background-color: var(--color-primary-light-4);
  21. }
  22. .layout-demo :deep(.arco-layout-sider) {
  23. width: 206px;
  24. background-color: var(--color-primary-light-3);
  25. }
  26. .layout-demo :deep(.arco-layout-content) {
  27. background-color: rgb(var(--arcoblue-6));
  28. }
  29. .footer {
  30. background-color: aliceblue;
  31. padding: 16px;
  32. position: sticky;
  33. bottom: 0;
  34. left: 0;
  35. right: 0;
  36. text-align: center;
  37. letter-spacing: 3px;
  38. }
  39. </style>

内容补充: 在登录页补充开发一下注册页面。

之前只写了登录页面,当然也得有注册页面,来打造一个

其实只要有了登录页面,对于注册页面也就不难了,

  1. <div class="login-box" v-if="!isLogin">
  2. <a-form
  3. :model="loginData"
  4. :style="{ width: '600px' }"
  5. @submit="handleSubmit"
  6. class="input-box"
  7. >
  8. <h2 style="margin-bottom: 60px">Login</h2>
  9. <a-form-item
  10. field="name"
  11. tooltip="Please enter username"
  12. label="账号"
  13. class="element"
  14. :rules="rules"
  15. >
  16. <a-input
  17. v-model="loginData.username"
  18. placeholder="please enter your username..."
  19. style="margin-right: 40px"
  20. />
  21. </a-form-item>
  22. <a-form-item field="post" label="密码" class="element" :rules="rules">
  23. <a-input
  24. v-model="loginData.password"
  25. placeholder="please enter your password..."
  26. style="margin-right: 40px"
  27. />
  28. </a-form-item>
  29. <a-form-item field="isRead">
  30. <a-checkbox v-model="loginData.isRead">
  31. I have read the manual
  32. </a-checkbox>
  33. </a-form-item>
  34. <a-form-item>
  35. <a-button html-type="submit" class="input-box" @click="login"
  36. >Submit</a-button
  37. >
  38. </a-form-item>
  39. <div class="register-link">
  40. <a @click="isLogin = !isLogin">Don't have an account? Create Now!</a>
  41. </div>
  42. </a-form>
  43. </div>

这是之前登录页面的代码,我们直接把它复制一份,再把h2标签的login改成register就好了

此时页面上就出现了两个表单,还记得之前的搜素框控制显示隐藏吗,这个也是这样,甚至更加简单,

    <div class="login-box" v-if="!isLogin">在div标签这里用v-if来控制两个,

回忆之前的组件开发三部曲:前端样式代码(html,css)已经完成,下面开始数据绑定与事件

这里我们在script代码中加上

const isLogin = ref(false)  //记得引入ref(之前好像引入过了)

那么:登录页的div:     <div class="login-box" v-if="!isLogin">

           注册页的div:     <div class="login-box" v-if="isLogin">

这样就成功控制了一个显示一个隐藏的效果了(注意其中的逻辑关系,要让login先显示)

然后就是控制页面的转换了,当点击Don't have an account? Create Now!就转换到注册页,那么可以

        <div class="register-link">

          <a @click="isLogin = !isLogin">Don't have an account? Create Now!</a>

        </div>

加一个点击效果进行转换

除此之外,注册页面用的输入框可跟登录页不一样,这里可以去组件库找找

这里可以使用其中的一些输入框和表单校验方法,不过数据绑定这块建议继续用ref

然后我们前往api/user.js,为用户注册写调用后端接口方法(这里跟登录差不多)

  1. import request from '../utils/request'
  2. //创建一个调用登录接口函数
  3. export const userLoginService = (loginData) =>{
  4. //用urlSearchParams完成传递
  5. const params = new URLSearchParams()
  6. for(let key in loginData){
  7. params.append(key,loginData[key]);
  8. }
  9. return request.post('/user/login',params);
  10. }
  11. export const userRegisterService = (registerData) =>{
  12. //用urlSearchParams完成传递
  13. const params = new URLSearchParams()
  14. for(let key in registerData){
  15. params.append(key,registerData[key]);
  16. }
  17. return request.post('/user/register',params);
  18. }

不能说长得很像,只能说根本就是一模一样。。

然后我们在Login登录界面编写调用后端接口方法

const register = async () => {

  let result = await userRegisterService(registerData.value);

  renderIcon(result.msg ? result.msg : "注册成功");

};

然后在上面submit按钮上绑定@click=“register”即可

下面来展示一下登录页目前的全部代码:

  1. <template>
  2. <div class="container">
  3. <div class="login-box" v-if="!isLogin">
  4. <a-form
  5. :model="loginData"
  6. :style="{ width: '600px' }"
  7. @submit="handleSubmit"
  8. class="input-box"
  9. >
  10. <h2 style="margin-bottom: 60px">Login</h2>
  11. <a-form-item
  12. field="name"
  13. tooltip="Please enter username"
  14. label="账号"
  15. class="element"
  16. :rules="rules"
  17. >
  18. <a-input
  19. v-model="loginData.username"
  20. placeholder="please enter your username..."
  21. style="margin-right: 40px"
  22. />
  23. </a-form-item>
  24. <a-form-item field="post" label="密码" class="element" :rules="loginRules">
  25. <a-input
  26. v-model="loginData.password"
  27. placeholder="please enter your password..."
  28. style="margin-right: 40px"
  29. />
  30. </a-form-item>
  31. <a-form-item field="isRead">
  32. <a-checkbox v-model="loginData.isRead">
  33. I have read the manual
  34. </a-checkbox>
  35. </a-form-item>
  36. <a-form-item>
  37. <a-button html-type="submit" class="input-box" @click="login"
  38. >Enter</a-button
  39. >
  40. </a-form-item>
  41. <div class="register-link">
  42. <a @click="isLogin = !isLogin">Don't have an account? Create Now!</a>
  43. </div>
  44. </a-form>
  45. </div>
  46. <div class="login-box" v-if="isLogin">
  47. <a-form
  48. :model="loginData"
  49. :style="{ width: '600px' }"
  50. @submit="handleSubmit"
  51. class="input-box"
  52. >
  53. <h2 style="margin-bottom: 60px">Register</h2>
  54. <a-form
  55. ref="formRef"
  56. :rules="regRules"
  57. :model="registerData"
  58. :style="{ width: '600px' }"
  59. @submit="handleSubmit"
  60. >
  61. <a-form-item field="name" label="账号" validate-trigger="blur">
  62. <a-input
  63. v-model="registerData.name"
  64. placeholder="please enter your username..."
  65. style="margin-right: 60px"
  66. />
  67. </a-form-item>
  68. <a-form-item field="password" label="密码" validate-trigger="blur">
  69. <a-input-password
  70. v-model="registerData.password"
  71. placeholder="please enter your password..."
  72. style="margin-right: 60px"
  73. />
  74. </a-form-item>
  75. <a-form-item
  76. field="password2"
  77. label="确认密码"
  78. validate-trigger="blur"
  79. >
  80. <a-input-password
  81. v-model="registerData.password2"
  82. placeholder="please confirm your password..."
  83. style="margin-right: 60px"
  84. />
  85. </a-form-item>
  86. <a-form-item field="email" label="email">
  87. <a-input
  88. v-model="registerData.email"
  89. placeholder="please enter your email..."
  90. style="margin-right: 60px"
  91. />
  92. </a-form-item>
  93. </a-form>
  94. <a-form-item>
  95. <a-button html-type="submit" class="input-box" @click="register"
  96. >Submit</a-button
  97. >
  98. </a-form-item>
  99. <div class="register-link">
  100. <a @click="isLogin = !isLogin">Have Count? Login Now!</a>
  101. </div>
  102. </a-form>
  103. </div>
  104. </div>
  105. </template>
  106. <script setup>
  107. import { h } from "vue";
  108. import { IconExclamationCircleFill } from "@arco-design/web-vue/es/icon";
  109. import { ref } from "vue";
  110. import { userLoginService, userRegisterService } from "../api/user";
  111. import { useRouter } from "vue-router";
  112. const router = useRouter();
  113. const loginData = ref({
  114. username: "",
  115. password: "",
  116. isRead: false,
  117. });
  118. const loginRules = [
  119. {
  120. validator: (value, cb) => {
  121. return new Promise((resolve) => {
  122. window.setTimeout(() => {
  123. if (value !== " ") {
  124. cb("content not empty");
  125. }
  126. resolve();
  127. }, 1000);
  128. });
  129. },
  130. },
  131. ];
  132. const renderIcon = () => h(IconExclamationCircleFill);
  133. const login = async () => {
  134. let result = await userLoginService(loginData.value);
  135. renderIcon(result.msg ? result.msg : "登录成功");
  136. router.push("/");
  137. };
  138. const register = async () => {
  139. let result = await userRegisterService(registerData.value);
  140. renderIcon(result.msg ? result.msg : "登录成功");
  141. };
  142. //登录注册页显示隐藏
  143. const isLogin = ref(false);
  144. const handleSubmit = ({ values, errors }) => {
  145. console.log("values:", values, "\nerrors:", errors);
  146. };
  147. const registerData = ref({
  148. name: "",
  149. password: "",
  150. password2: "",
  151. email: ""
  152. });
  153. const regRules = {
  154. name: [
  155. {
  156. required: true,
  157. message:'name is required',
  158. },
  159. ],
  160. password: [
  161. {
  162. required: true,
  163. message:'password is required',
  164. },
  165. ],
  166. password2: [
  167. {
  168. required: true,
  169. message:'password is required',
  170. },
  171. {
  172. validator: (value, cb) => {
  173. if (value !== registerData.value.password) {
  174. cb('two passwords do not match')
  175. } else {
  176. cb()
  177. }
  178. }
  179. }
  180. ],
  181. email: [
  182. {
  183. type: 'email',
  184. required: true,
  185. }
  186. ],
  187. }
  188. </script>
  189. <style scoped>
  190. * {
  191. margin: 0;
  192. padding: 0;
  193. box-sizing: border-box;
  194. font-family: "Poppins", sans-serif;
  195. display: flex;
  196. justify-content: center;
  197. }
  198. .container {
  199. width: 100%;
  200. height: 100vh;
  201. background: url("../assets/background.jpg") no-repeat;
  202. background-size: cover;
  203. background-position: center;
  204. display: flex;
  205. justify-content: center;
  206. align-items: center;
  207. }
  208. .container .login-box {
  209. position: relative;
  210. width: 500px;
  211. height: 580px;
  212. background-color: transparent;
  213. border: 2px solid rgba(255, 255, 255, 0.5);
  214. border-radius: 20px;
  215. display: flex;
  216. justify-content: center;
  217. align-items: center;
  218. backdrop-filter: blur(15px);
  219. }
  220. .login-box h2 {
  221. font-size: 28px;
  222. color: #fff;
  223. text-align: center;
  224. }
  225. .login-box .input-box {
  226. position: relative;
  227. width: 310px;
  228. margin: 30px 0;
  229. }
  230. .input-box input {
  231. width: 80%;
  232. height: 60px;
  233. background: transparent;
  234. border: none;
  235. outline: none;
  236. font-size: 16px;
  237. color: #fff;
  238. padding: 0 2px 0 5px;
  239. }
  240. .input-box input::placeholder {
  241. color: #f9f9f9;
  242. }
  243. .input-box .icon {
  244. position: absolute;
  245. right: 8px;
  246. color: #fff;
  247. font-size: 16px;
  248. line-height: 25px;
  249. }
  250. .login-box .remember-forget {
  251. margin: -15px 0 15px;
  252. font-size: 15px;
  253. color: #fff;
  254. display: flex;
  255. justify-content: space-between;
  256. }
  257. .remember-forget label input {
  258. margin-right: 30px;
  259. }
  260. .login-box button {
  261. width: 100%;
  262. height: 40px;
  263. background: #fff;
  264. border: none;
  265. outline: none;
  266. border-radius: 40px;
  267. cursor: pointer;
  268. font-size: 16px;
  269. color: #000;
  270. transition: all 0.5s;
  271. }
  272. .login-box button:hover {
  273. background: #1f73c9;
  274. color: #fff;
  275. }
  276. .login-box .register-link {
  277. font-size: 15px;
  278. color: #fff;
  279. text-align: center;
  280. margin: 5px 0 5px;
  281. }
  282. .remember-forget a,
  283. .register-link a {
  284. color: #fff;
  285. text-decoration: none;
  286. }
  287. .remember-forget a:hover,
  288. .register-link a:hover {
  289. text-decoration: underline;
  290. }
  291. /* Responsive Design */
  292. @media (max-width: 460px) {
  293. .container .login-box {
  294. width: 350px;
  295. }
  296. .login-box .input-box {
  297. width: 290px;
  298. }
  299. }
  300. @media (max-width: 360px) {
  301. .container .login-box {
  302. width: 100%;
  303. height: 100vh;
  304. border: none;
  305. }
  306. }
  307. .element {
  308. margin: 20px 0;
  309. }
  310. </style>

全局页面跳转解决:

既然都讲到页面路由了,就多练练吧,

在全局页面(GlobalPage.vue)这一块我们把之前写死的searchPage去掉改成可变的router-view

  1. <template>
  2. <a-layout style="height: 400px">
  3. <a-layout-header><global-header></global-header></a-layout-header>
  4. <a-layout>
  5. <a-layout-sider theme="dark">Sider</a-layout-sider>
  6. <a-layout-content><router-view></router-view></a-layout-content><!--就是这里-->
  7. </a-layout>
  8. <a-layout-footer>
  9. <global-footer class="footer"></global-footer>
  10. </a-layout-footer>
  11. </a-layout>
  12. </template>

然后就可以开始布置了,现在点击GlobalHeader.vue全局头部,

  1. <template>
  2. <div class="menu-demo">
  3. <a-menu mode="horizontal" theme="dark" :default-selected-keys="['1']">
  4. <a-menu-item
  5. key="0"
  6. :style="{ padding: 0, marginRight: '38px' }"
  7. disabled
  8. class="logo"
  9. >
  10. <div
  11. :style="{
  12. width: '180px',
  13. height: '30px',
  14. background: 'var(--color-fill-3)',
  15. cursor: 'text',
  16. }"
  17. ><img src="../assets/logo.png" width="180px"></div>
  18. </a-menu-item>
  19. <a-menu-item key="1"><router-link to="/main/search">全局搜索</router-link></a-menu-item>
  20. <a-menu-item key="2"><router-link to="/main/article">文章大全</router-link></a-menu-item>
  21. <a-menu-item key="3">Cloud Service</a-menu-item>
  22. <a-menu-item key="4">Cooperation</a-menu-item>
  23. </a-menu>

这里修改一下a-menu-item标签,(一般在组件库这里会有专门的跳转属性这种,不过今天好像组件库页面打不开了,那暂时就用原始版的router-link来实现一下吧,(之后我会修改一下的))

这里布置了两个页面,全局搜素和文章大全,进行跳转,然后呢,去index.js处创建一下主页面的子路由,

下面,看代码展示

  1. import { createRouter, createWebHashHistory } from 'vue-router'
  2. import MainPage from '../components/GlobalPage.vue'
  3. import LoginPage from '../components/LoginPage.vue'
  4. import SearchPage from '../views/SearchPage.vue'
  5. import ArticlePage from '../views/ArticlePage.vue'
  6. const routes = [
  7. {
  8. path: '/',
  9. name: 'mainPage',
  10. component: MainPage,
  11. redirect: '/main/search',
  12. children: [
  13. {
  14. path: '/main/search',
  15. component: SearchPage
  16. },
  17. {
  18. path: '/main/article',
  19. component: ArticlePage
  20. }
  21. ]
  22. },
  23. {
  24. path: '/login',
  25. name: 'loginPage',
  26. component: LoginPage
  27. }
  28. ]
  29. const router = createRouter({
  30. history: createWebHashHistory(),
  31. routes
  32. })
  33. export default router

这里我目前添加了全局搜素和文章大全两个子页面(小细节:redirect: '/main/search',这里我使用了一个重定向,让每次进入‘/’页面的时候都会跳转到全局搜素页面处),全局搜素的页面之前已经写过了,那也就不用管了,这里我们添加以下文章大全的页面,在views文件夹下创建ArticlePage.vue文件用<vue>创建基本样子,

  1. <template>
  2. <div id="article">
  3. 文章篇
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. }
  9. </script>
  10. <style>
  11. </style>

先随便写一点吧,主要是要能现在展现以下跳转。

目前来看就差不多了,来试试能不能实现跳转。

好嘞,那么现在也就实现了这一功能,

好了,目前主要的一些前端样子也就差不多了,这一期的项目主要还是练练手,就做一些最基本文章管理这些吧。

文章管理界面开发:

既然写界面,我觉得还是先来一手布局比较合适

来吧,组件库见:

这里我没想太多,直接用这个朴实无华的布局吧。

先用代码写个初始布局

  1. <template>
  2. <div id="article">
  3. <a-divider />
  4. <a-layout style="height: 400px;">
  5. <a-layout-header>Header</a-layout-header>
  6. <a-divider orientation="left">热点文章</a-divider>
  7. <a-layout-content>Content</a-layout-content>
  8. <a-layout-footer>Footer</a-layout-footer>
  9. </a-layout>
  10. </div>
  11. </template>
  12. <script>
  13. export default {
  14. }
  15. </script>
  16. <style scoped>
  17. body {
  18. margin: 0;
  19. background-color: #f5f5f5;
  20. }
  21. /* fade-slide */
  22. .fade-slide-leave-active,
  23. .fade-slide-enter-active {
  24. transition: all 0.3s;
  25. }
  26. .fade-slide-enter-from {
  27. transform: translateX(-30px);
  28. opacity: 0;
  29. }
  30. .fade-slide-leave-to {
  31. transform: translateX(30px);
  32. opacity: 0;
  33. }
  34. </style>

这里我加了一个带有文字的分割线

然后就是最关键的content内容区域了,这里可以加上一些样式,(如果对自己的前端没有太自信的话,直接组件库!)

好,看一手,我们先找一个滑动条

就这个了,

将滚动条放入content区域之后,小改一下代码,调整大小,适应一下屏幕大小就好看多了

  1. <template>
  2. <div id="article">
  3. <a-divider />
  4. <a-layout style="height: 760px">
  5. <a-layout-header class="header">文章管理</a-layout-header>
  6. <a-divider orientation="left">Cetide-Net</a-divider>
  7. <a-layout-content>
  8. <a-scrollbar class="rollBar"
  9. style="height: 673.34px; overflow: auto; margin: 10px 20px">
  10. <div class="content">Content</div>
  11. </a-scrollbar>
  12. </a-layout-content>
  13. </a-layout>
  14. </div>
  15. </template>
  16. <script>
  17. export default {};
  18. </script>
  19. <style scoped>
  20. #article {
  21. margin: 20px;
  22. }
  23. /* fade-slide */
  24. .fade-slide-leave-active,
  25. .fade-slide-enter-active {
  26. transition: all 0.3s;
  27. }
  28. .fade-slide-enter-from {
  29. transform: translateX(-30px);
  30. opacity: 0;
  31. }
  32. .fade-slide-leave-to {
  33. transform: translateX(30px);
  34. opacity: 0;
  35. }
  36. .header {
  37. font-family: "Satisfy", cursive;
  38. font-size: 26px;
  39. color: rgb(93, 186, 216);
  40. padding-left: 50px;
  41. text-align: left;
  42. }
  43. .rollBar{
  44. }
  45. .content {
  46. height: 2000px;
  47. width: 1424px;
  48. background-color: var(--color-primary-light-4);
  49. }
  50. </style>

然后就是存放文章的了,这里可以找找组件库的列表组件:

这个组件就很奈斯(分页条,评论按键都有),因为这里主要是文章大全,所以就不用加上编辑和删除功能了,不过可以加上一个评论功能

这里加一个显示神评的吧,到时候把点赞数最多的评论放到让文章大全页面都能看到

修改一下代码,嵌入文章大全页面.

  1. <template>
  2. <div id="article">
  3. <a-divider />
  4. <a-layout style="height: 760px">
  5. <a-layout-header class="header">文章管理</a-layout-header>
  6. <a-divider orientation="left">Cetide-Net</a-divider>
  7. <a-layout-content>
  8. <a-scrollbar class="rollBar"
  9. style="height: 673.34px; overflow: auto; margin: 10px 20px">
  10. <div class="content">
  11. <a-list
  12. class="list-demo-action-layout"
  13. :bordered="false"
  14. :data="dataSource"
  15. :pagination-props="paginationProps"
  16. >
  17. <template #item="{ item }">
  18. <a-list-item class="list-demo-item" action-layout="vertical">
  19. <template #actions>
  20. <span><icon-heart />点赞 83</span>
  21. <span><icon-star />收藏{{ item.index }}</span>
  22. <span><icon-message />评论</span>
  23. </template>
  24. <template #extra>
  25. <div className="image-area">
  26. <img alt="arco-design" :src="item.imageSrc" />
  27. </div>
  28. </template>
  29. <a-list-item-meta
  30. :title="item.title"
  31. :description="item.description"
  32. >
  33. <template #avatar>
  34. <a-avatar shape="square">
  35. <img alt="avatar" :src="item.avatar" />
  36. </a-avatar>
  37. </template>
  38. </a-list-item-meta>
  39. <div style="width:100%; text-align: left; padding-left:20px">
  40. <a-divider />
  41. <a-comment author="Socrates" content="Comment body content." datetime="1 hour">
  42. <template #avatar>
  43. <a-avatar>
  44. <img
  45. alt="avatar"
  46. src="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp"
  47. />
  48. </a-avatar>
  49. </template>
  50. </a-comment>
  51. </div>
  52. </a-list-item>
  53. </template>
  54. </a-list>
  55. </div>
  56. </a-scrollbar>
  57. </a-layout-content>
  58. </a-layout>
  59. </div>
  60. </template>
  61. <script>
  62. import { reactive } from 'vue'
  63. const names = ['Socrates', 'Balzac', 'Plato'];
  64. const avatarSrc = [
  65. '//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a8c8cdb109cb051163646151a4a5083b.png~tplv-uwbnlip3yd-webp.webp',
  66. '//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/e278888093bef8910e829486fb45dd69.png~tplv-uwbnlip3yd-webp.webp',
  67. '//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/9eeb1800d9b78349b24682c3518ac4a3.png~tplv-uwbnlip3yd-webp.webp',
  68. ];
  69. const imageSrc = [
  70. '//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/29c1f9d7d17c503c5d7bf4e538cb7c4f.png~tplv-uwbnlip3yd-webp.webp',
  71. '//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/04d7bc31dd67dcdf380bc3f6aa07599f.png~tplv-uwbnlip3yd-webp.webp',
  72. '//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/1f61854a849a076318ed527c8fca1bbf.png~tplv-uwbnlip3yd-webp.webp',
  73. ];
  74. const dataSource = new Array(15).fill(null).map((_, index) => {
  75. return {
  76. index: index,
  77. avatar: avatarSrc[index % avatarSrc.length],
  78. title: names[index % names.length],
  79. description:
  80. 'Beijing ByteDance Technology Co., Ltd. is an enterprise located in China. ByteDance has products such as TikTok, Toutiao, volcano video and Douyin (the Chinese version of TikTok).',
  81. imageSrc: imageSrc[index % imageSrc.length],
  82. };
  83. });
  84. export default {
  85. setup() {
  86. return {
  87. dataSource,
  88. paginationProps: reactive({
  89. defaultPageSize: 3,
  90. total: dataSource.length
  91. })
  92. }
  93. },
  94. }
  95. </script>
  96. <style scoped>
  97. #article {
  98. margin: 20px;
  99. }
  100. /* fade-slide */
  101. .fade-slide-leave-active,
  102. .fade-slide-enter-active {
  103. transition: all 0.3s;
  104. }
  105. .fade-slide-enter-from {
  106. transform: translateX(-30px);
  107. opacity: 0;
  108. }
  109. .fade-slide-leave-to {
  110. transform: translateX(30px);
  111. opacity: 0;
  112. }
  113. .header {
  114. font-family: "Satisfy", cursive;
  115. font-size: 26px;
  116. color: rgb(93, 186, 216);
  117. padding-left: 50px;
  118. text-align: left;
  119. }
  120. .rollBar{
  121. }
  122. .content {
  123. /* height: 2000px; */
  124. width: 1424px;
  125. }
  126. .list-demo-action-layout .image-area {
  127. width: 183px;
  128. height: 119px;
  129. border-radius: 2px;
  130. overflow: hidden;
  131. }
  132. .list-demo-action-layout .list-demo-item {
  133. padding: 20px 0;
  134. border-bottom: 1px solid var(--color-fill-3);
  135. }
  136. .list-demo-action-layout .image-area img {
  137. width: 100%;
  138. }
  139. .list-demo-action-layout .arco-list-item-action .arco-icon {
  140. margin: 0 4px;
  141. }
  142. </style>

大家一定要看懂一些组件代码才好使用,(后续调用后端接口,使用后端数据库的时候就会用到)

这一期的项目,打算就先做一个文章管理页面,加上用户个人中心的东西就差不多了(主要还是先熟悉熟悉流程,后面可以看看加上一些更好的功能(也不能只是crud哈))

用户个人中心界面开发:

在component文件夹下面创建一个UserCentre.vue页面

先做一个雏形:

然后在index.js中注册页面

  {

    path: '/user',

    name: 'userPage',

    component: UserPage

 }

然后做一个页面跳转吧,这里我们回到GlobalHeader.vue全局导航栏区域,

  1. <template>
  2. <div class="menu-demo">
  3. <a-menu mode="horizontal" theme="dark" :default-selected-keys="['1']">
  4. <a-menu-item
  5. key="0"
  6. :style="{ padding: 0, marginRight: '38px' }"
  7. disabled
  8. class="logo"
  9. >
  10. <div
  11. :style="{
  12. width: '180px',
  13. height: '30px',
  14. background: 'var(--color-fill-3)',
  15. cursor: 'text',
  16. }"
  17. ><img src="../assets/logo.png" width="180px"></div>
  18. </a-menu-item>
  19. <a-menu-item key="1"><router-link to="/main/search">全局搜索</router-link></a-menu-item>
  20. <a-menu-item key="2"><router-link to="/main/article">文章大全</router-link></a-menu-item>
  21. <a-menu-item key="3">Cloud Service</a-menu-item>
  22. <a-menu-item key="4">Cooperation</a-menu-item>
  23. </a-menu>
  24. <div class="user-avatar">
  25. <img src="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp"
  26. alt="User Avatar" class="avatar-image"/>
  27. <div
  28. class="dropdown"
  29. style="font-family: 'Satisfy', cursive; margin-right: 20px"
  30. >
  31. <button class="dropdown-button">
  32. <img src="../assets/list.png" width="15px" />
  33. </button>
  34. <div class="dropdown-content">
  35. <a href="#">个人信息</a>
  36. <a href="#">修改密码</a>
  37. <a href="#">其他属性</a>
  38. <a href="/#/login">退出登录</a>
  39. </div>
  40. </div>
  41. </div>
  42. </div>
  43. </template>
  44. <script setup>
  45. </script>
  46. <style scoped>
  47. .logo{
  48. float: left;
  49. }
  50. .menu-demo {
  51. box-sizing: border-box;
  52. width: 100%;
  53. background-color: var(--color-neutral-2);
  54. }
  55. .user-avatar {
  56. /* position: absolute;
  57. right: 0;
  58. top: 4px; */
  59. }
  60. .avatar-image {
  61. position: absolute;
  62. top: 10px;
  63. right: 16px;
  64. width: 40px;
  65. height: 40px;
  66. border-radius: 50%;
  67. cursor: pointer;
  68. z-index: 10;
  69. }
  70. .dropdown {
  71. position: absolute;
  72. top: 28px;
  73. right: 50px;
  74. display: inline-block;
  75. z-index: 1;
  76. }
  77. .dropdown-button {
  78. background-color: #303030;
  79. color: white;
  80. padding: 5px 0px;
  81. border: none;
  82. cursor: pointer;
  83. }
  84. .dropdown-content {
  85. display: none;
  86. position: absolute;
  87. background-color: #f9f9f9;
  88. min-width: 85px;
  89. box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  90. z-index: 1;
  91. }
  92. .dropdown-content a {
  93. color: black;
  94. padding: 8px 8px;
  95. text-decoration: none;
  96. display: block;
  97. }
  98. .dropdown-content a:hover {
  99. background-color: #f1f1f1;
  100. }
  101. .dropdown:hover .dropdown-content {
  102. display: block;
  103. }
  104. </style>

这里展示一下之前添加的一点点代码,然后在右上角添加了一个用户头像和一个下拉栏目(感觉代码写的不太好,这边还是建议大家去组件库里找一些比较方便的(这里我是自己写的))

  1. <template>
  2. <div class="menu-demo">
  3. <a-menu mode="horizontal" theme="dark" :default-selected-keys="['1']">
  4. <a-menu-item
  5. key="0"
  6. :style="{ padding: 0, marginRight: '38px' }"
  7. disabled
  8. class="logo"
  9. >
  10. <div
  11. :style="{
  12. width: '180px',
  13. height: '30px',
  14. background: 'var(--color-fill-3)',
  15. cursor: 'text',
  16. }"
  17. >
  18. <img src="../assets/logo.png" width="180px" />
  19. </div>
  20. </a-menu-item>
  21. <a-menu-item key="1"
  22. ><router-link to="/main/search">全局搜索</router-link></a-menu-item
  23. >
  24. <a-menu-item key="2"
  25. ><router-link to="/main/article">文章大全</router-link></a-menu-item
  26. >
  27. <a-menu-item key="3">Cloud Service</a-menu-item>
  28. <a-menu-item key="4">Cooperation</a-menu-item>
  29. </a-menu>
  30. <div class="user-avatar">
  31. <img
  32. src="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp"
  33. alt="User Avatar"
  34. class="avatar-image"
  35. />
  36. <div
  37. class="dropdown"
  38. style="font-family: 'Satisfy', cursive; margin-right: 20px"
  39. >
  40. <button class="dropdown-button">
  41. <img src="../assets/list.png" width="15px" />
  42. </button>
  43. <div class="dropdown-content">
  44. <router-link to="/user">个人信息</router-link>
  45. <router-link to="/login">修改密码</router-link>
  46. <router-link to="/login">其他属性</router-link>
  47. <router-link to="/login">退出登录</router-link>
  48. </div>
  49. </div>
  50. </div>
  51. </div>
  52. </template>
  53. <script setup>
  54. </script>
  55. <style scoped>
  56. .logo {
  57. float: left;
  58. }
  59. .menu-demo {
  60. box-sizing: border-box;
  61. width: 100%;
  62. background-color: var(--color-neutral-2);
  63. }
  64. .user-avatar {
  65. /* position: absolute;
  66. right: 0;
  67. top: 4px; */
  68. }
  69. .avatar-image {
  70. position: absolute;
  71. top: 10px;
  72. right: 16px;
  73. width: 40px;
  74. height: 40px;
  75. border-radius: 50%;
  76. cursor: pointer;
  77. z-index: 10;
  78. }
  79. .dropdown {
  80. position: absolute;
  81. top: 28px;
  82. right: 50px;
  83. display: inline-block;
  84. z-index: 1;
  85. }
  86. .dropdown-button {
  87. background-color: #303030;
  88. color: white;
  89. padding: 5px 0px;
  90. border: none;
  91. cursor: pointer;
  92. }
  93. .dropdown-content {
  94. display: none;
  95. position: absolute;
  96. background-color: #f9f9f9;
  97. min-width: 85px;
  98. box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  99. z-index: 1;
  100. }
  101. .dropdown-content a {
  102. color: black;
  103. padding: 8px 8px;
  104. text-decoration: none;
  105. display: block;
  106. }
  107. .dropdown-content a:hover {
  108. background-color: #f1f1f1;
  109. }
  110. .dropdown:hover .dropdown-content {
  111. display: block;
  112. }
  113. </style>

那么,这样就可以点击个人中心进行跳转到个人中心了(这里的退出登录bug很大,应该要调用专门的函数,去除登录状态什么的,之后有机会再改一下)

这里刚开始就是这样了,老样子,做个布局吧。

就用这个了

  1. <template>
  2. <div id="userCenter">
  3. <a-layout style="height: 100vh">
  4. <a-layout-header>Header</a-layout-header>
  5. <a-layout style="margin: 24px 120px">
  6. <a-layout-sider>Sider</a-layout-sider>
  7. <a-layout-content>Content</a-layout-content>
  8. </a-layout>
  9. <a-layout-footer>Footer</a-layout-footer>
  10. </a-layout>
  11. </div>
  12. </template>
  13. <script>
  14. export default {};
  15. </script>
  16. <style>
  17. </style>

稍微搭建一下用户界面吧,明天继续(hhh)(emmm,还以为今天能写完这部分的)

发一下代码吧(感觉这个代码后面要大改。。)

  1. <template>
  2. <div id="userCenter">
  3. <a-layout style="height: 100vh">
  4. <a-layout-header>
  5. <div class="header">
  6. <div class="personal-introduce">
  7. <span class="name">我是小丑</span>
  8. <span class="sex-icon"></span>
  9. <span class="level-icon"></span>
  10. </div><div class="professional">演员,代表作:</div>
  11. </div>
  12. </a-layout-header>
  13. <a-layout style="margin: 24px 120px">
  14. <a-layout-sider>Sider</a-layout-sider>
  15. <a-layout-content>Content</a-layout-content>
  16. </a-layout>
  17. <a-layout-footer>Footer</a-layout-footer>
  18. </a-layout>
  19. </div>
  20. </template>
  21. <script>
  22. export default {};
  23. </script>
  24. <style lang="scss" scoped>
  25. #userCenter {
  26. background: url("../assets/image.png") no-repeat bottom center / 100%
  27. 100%;
  28. }
  29. .header {
  30. height: 20vh;
  31. margin-top: 5%;
  32. background: url("../assets/back.png") no-repeat center / 90%
  33. 100%;
  34. }
  35. .personal-introduce {
  36. display: flex;
  37. justify-content: center;
  38. align-items: flex-end;
  39. margin-top: 10px;
  40. text-shadow: 0px 0px 4px rgba(0, 0, 0, 0.31);
  41. .name {
  42. line-height: 29px;
  43. font-size: 22px;
  44. }
  45. .sex-icon {
  46. display: inline-block;
  47. width: 16px;
  48. height: 16px;
  49. margin: 0px 8px;
  50. margin-bottom: 4px;
  51. background: url(../assets/user-images/sex-icon.png) no-repeat center;
  52. background-size: contain;
  53. }
  54. .level-icon {
  55. display: inline-block;
  56. width: 16px;
  57. height: 16px;
  58. margin-bottom: 4px;
  59. background: url(../assets/user-images/leval-icon.png) no-repeat center;
  60. background-size: contain;
  61. }
  62. }
  63. </style>

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/979330
推荐阅读
相关标签
  

闽ICP备14008679号