10. 用户列表页面实现
从云端将用户列表读进来
- 安装
npm i jquery
使用ajax
- 页面中
import $ from 'jquery';
从云端动态获取用户(使用AJAX)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <template> <contentElem>用户列表</contentElem> </template>
<script> import contentElem from "../components/contentElem.vue"; import $ from 'jquery'; import { ref } from 'vue'; export default { name: 'UserList', components: { contentElem, }, setup(){ let users= ref([]); $.ajax({ url:"https://app165.acapp.acwing.com.cn/myspace/userlist/", type:"get", success(resp){ console.log(resp); } });
return { users } }, } </script>
<style scoped>
</style>
|
使用bootstrap的 Grid system进行布局:

微调样式,

访问不存在的页面,则跳转到404:

给链接加上id

路由中需要添加参数,用:

对应的UserProfileView中,使用提供的useRoute接口,即可获取这个参数


11. 实现登录页面
需要双向绑定两个变量username,password






ref中的值需要.value访问

阻止默认行为

11.1 vuex
因为很多前端行为需要获得用户信息,所以要将登录的用户信息存到全局变量中——此时需要vuex
交互:

vuex创建的全局唯一对象:
/store/index.js



访问:

11.1.1 传统登录方式

存到cookie中,跨域时难处理。
11.1.2 JWT方式
json web token

11.2 实现登录
1 2 3 4 5 6 7
| vuex:存储全局状态,全局唯一。 state: 存储所有数据,可以用modules属性划分成若干模块 getters:根据state中的值计算新的值 mutations:所有对state的修改操作都需要定义在这里,不支持异步,可以通过$store.commit()触发 actions:定义对state的复杂修改操作,支持异步,可以通过$store.dispatch()触发。注意不能直接修改state,只能通过mutations修改state。 modules:定义state的子模块
|
dispatch调用store中的事件

附注:使用ajax需要import $ from 'jquery';
\

从获得的access字符串中解码出用户信息,需要安装一个解码包

然后在user.js中引入
import jwt_decode from 'jwt-decode';
使用:
const access_obj=jwt_decode(access);
纯背过:用于授权


可以成功获得现在登录的用户信息:

有了这些信息后,要将这些信息存到state里面:
但是action里面是不能直接更新的,要通过mutations

完整版user.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| import $ from 'jquery'; import jwt_decode from 'jwt-decode'; const ModuleUser={ state: { id:"", username:"", photo:"", followerCount:"", access:"", refresh:"", is_login:false, }, getters: { }, mutations: { updateUser(state,user){//第一个参数是state,第二个参数是自己定义的 state.id=user.id; state.username=user.username; state.photo=user.photo; state.followerCount=user.followerCount; state.access=user.access; state.refresh=user.refresh; state.is_login=user.is_login; }
}, actions: { login(context,data){ //context 传api,data传一些信息(dispatch的参数) $.ajax({ url:"https://app165.acapp.acwing.com.cn/api/token/", type: "POST", data:{ username: data.username, password: data.password, }, success(resp){ // console.log(resp); // const access=resp.access; // const refresh=resp.refresh; const {access,refresh}=resp; //ES6语法 const access_obj=jwt_decode(access); // console.log(access_obj,refresh); //然后可以根据其中的user_id和我们的api去获取信息 $.ajax({ url:"https://app165.acapp.acwing.com.cn/myspace/getinfo/", type:"GET", data:{ user_id:access_obj.user_id, }, headers:{ 'Authorization':"Bearer "+access, }, success(resp){ context.commit("updateUser",{ ...resp, access:access, refresh:refresh, is_login:true, }); data.success(); }, error(){ data.error(); } })
} }) } }, modules: { } };
export default ModuleUser;
|
LoginView.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| <template> <contentElem> <div class="row justify-content-md-center"> <div class="col-3"> <form @click.prevent="login"> <div class="mb-3"> <label for="username" class="form-label">用户名</label> <input v-model="username" type="text" class="form-control" id="username"> </div> <div class="mb-3"> <label for="password" class="form-label">密码</label> <input v-model="password" type="password" class="form-control" id="password"> </div> <div class="error-message">{{error_message}}</div> <button type="submit" class="btn btn-primary">登录</button> </form> </div> </div>
</contentElem> </template>
<script> import contentElem from "../components/contentElem.vue"; import { ref } from "vue"; import { useStore } from "vuex"; export default { name: 'UserList', components: { contentElem, }, setup(){ let username=ref(''); let password=ref(''); let error_message=ref(''); const store=useStore(); const login=()=>{ // console.log(username.value); // console.log(password.value); //如果想调用外面action中的一个api,用dispatch store.dispatch("login",{ username:username.value, password:password.value, success(){ console.log("success"); }, error(){ console.log("fail"); } }) }
return { username, password, error_message, login
}
} } </script>
<style scoped> .error-message{ color: red; } button{ float: right; }
</style>
|
11.3 使用refresh刷新access
因为5分钟access会过期,所以需要用到refresh进行刷新。
方法1. 访问的时候发现access过期了,此时去获取一个新的access
方法2. 每隔五分钟获取一次access,调用刷线access的接口,每五分钟一次
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| setInterval(()=>{ $.ajax({ url:"https://app165.acapp.acwing.com.cn/api/token/refresh/", type:"POST", data:{ refresh:access_obj.refresh, }, success(resp){ context.commit("updateAccess",resp.access);
}, error(){ data.error(); }
});
},4.5*60*1000);
|
12. 登录后跳转到用户列表页面
引入router

使用api

13. 登录后修改展示页面
NavBar修改一下。让这些页面都符合逻辑
想要获取store中的全局变量,可以使用$ xxx


14. 实现退出
只需要写一个事件即可。

凡是要修改全局state,要把事件写到action/mutations里面 (需要store)

15. 未登录时的跳转
userList.vue

点击时触发函数:

16. 用户动态从云端获取
用户动态页面根据userId的改变而改变。
还是ajax!

17. 判断发帖子模块是否需要
只有在自己的页面才能发帖子。

18. 用完整链接判断页面是否相同
App.vue

默认是用页面的name判断的,都叫userprofile,所以到别人页面,再点击自己的,就会出现不刷新不跳转的情况。
19. 从前端删除到真的删除


20. 部署
- build 打包成可以发布的版本

2. 打包

3. 传到服务器上