• 【前端】Vue实现个人空间


    AcWing Web应用课 (y总yyds)

    Vue3——网站整体布局、用户动态页面

    1. 前端渲染逻辑

    前端渲染:只有第一次打开页面的时候,向服务器发送请求,服务器返回所有js, 之后再打开页面,前端用返回的js文件将页面渲染出来。

    2. vue文件

    一个vue文件由三部分组成,html,js,css
    css部分标签 ,加上scoped,不同组件之间的css选择器就不会相互影响到了。
    在这里插入图片描述

    3. 组件化的框架

    • 可以拆分实现
      在这里插入图片描述
    • 引入组件的方式(根组件App.vue)
      在这里插入图片描述
      项目练习:
      在这里插入图片描述

    4. 一些准备

    • 引入bootstrap
      也是根组件app.vue中引入
    <script>
    import 'bootstrap/dist/css/bootstrap.css';
    import 'bootstrap/dist/js/bootstrap'
    </script>
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述
    有一个模块需要单独装
    在这里插入图片描述

    5. 实现导航栏

    1. 实现导航栏组件——直接使用bootstrap选取需要的元素,将组件export出去
      在这里插入图片描述

    NavBar.vue

    <template>
        <nav class="navbar navbar-expand-lg bg-light">
      <div class="container-fluid">
        <a class="navbar-brand" href="#">MySpace</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarText">
          <ul class="navbar-nav me-auto mb-2 mb-lg-0">
            <li class="nav-item">
              <a class="nav-link active" aria-current="page" href="#">首页</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#">好友列表</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#">用户动态</a>
            </li>
          </ul>
          <ul class="navbar-nav me-auto mb-2 mb-lg-0">
            <li class="nav-item">
              <a class="nav-link" href="#">登录</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#">注册</a>
            </li>
          </ul>
        </div>
      </div>
    </nav>
    </template>
    
    <script>
        export default{
            name: "NavBar",
        }
    </script>
    
    <style scoped>
    
    </style>
    
    • 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
    1. 在根组件将 实现的NavBar引入——引入路径,在components对象中添加组件名,同时在template中引入组件
      在这里插入图片描述
      在这里插入图片描述
      App.vue
    <template>
      <NavBar/>
    
      <router-view/>
    </template>
    
    <script>
    import 'bootstrap/dist/css/bootstrap.css';
    import 'bootstrap/dist/js/bootstrap';
    import NavBar from './components/NavBar';
    
    export default{
      name:"App",
      components:{
        NavBar
    }
    }
    </script>
    
    <style>
    #app {
      font-family: Avenir, Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
    }
    </style>
    
    
    • 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

    6. 写六个小组件

    对于一个比较大的组件,可以拆分为多个组件
    首页组件
    可以在bootstrap中找个card组件,然后用container包起来,container是用来动态调位置的
    在这里插入图片描述
    发现这一部分的html和css其实每个页面都一样,要将这块公共部分提取出来作为单独的组件,方便后期整体修改。

    可以将内容渲染到 slot标签中(slot可以用来获取子元素):在这里插入图片描述
    contentElem.vue

    <template>
      <div class="home">
        <div class="container">
            <div class="card">
              <div class="card-body">
                <slot></slot>
              </div>
            </div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
        name: "contentElem",
    }
    </script>
    
    <style scoped>
        .container{
            margin-top: 20px;
        }
    </style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    HomeView.vue

    <template>
      <contentElem>
        首页
      </contentElem>
    </template>
    
    <script>
    import contentElem from "../components/contentElem.vue";
    
    export default {
      name: 'HomeView',
      components: {
          contentElem,
      }
    }
    </script>
    
    <style scoped>
    
    
    </style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    图片也是可以渲染的:

    <template>
      <contentElem>
        首页
        <img src="https://cdn.acwing.com/media/user/profile/photo/108069_sm_fb7fff1e8d.jpg" alt="my head pic">
      </contentElem>
    </template>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    7. 添加路由

    1. 引入所有组件(页面)
      在这里插入图片描述

    2. 更新路由列表即可

    import { createRouter, createWebHistory } from 'vue-router'
    import HomeView from '../views/HomeView.vue'
    import LoginView from '../views/LoginView.vue'
    import NotFoundView from '../views/NotFoundView.vue'
    import RegisterView from '../views/RegisterView.vue'
    import UserList from '../views/UserList.vue'
    import UserProfile from '../views/UserProfile.vue'
    
    const routes = [
      {
        path: '/',
        name: 'home',
        component: HomeView
      },
      {
        path: '/login',
        name: 'login',
        component: LoginView
      },
      {
        path: '/404',
        name: '404',
        component: NotFoundView
      },
      {
        path: '/register',
        name: 'register',
        component: RegisterView
      },
      {
        path: '/userlist',
        name: 'userlist',
        component: UserList
      },
      {
        path: '/userprofile',
        name: 'userprofile',
        component: UserProfile
      },
    
      
    ]
    
    const router = createRouter({
      history: createWebHistory(),
      routes
    })
    
    export default router
    
    
    • 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

    8. 实现前端渲染的属性

    在这里插入图片描述
    想要实现前端渲染,将原本的a标签换成router-link标签,有特殊的属性 : to ,注意在vue中绑定属性需要用冒号: ,传入name,param
    在这里插入图片描述
    这样就能跳到home对应的路径。
    NavBar.vue

    <template>
        <nav class="navbar navbar-expand-lg bg-light">
      <div class="container">
        <router-link class="navbar-brand" :to="{name:'home',param:{}}">MySpace</router-link>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText" aria-controls="navbarText" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarText">
          <ul class="navbar-nav me-auto mb-2 mb-lg-0">
            <li class="nav-item">
              <router-link class="nav-link active" aria-current="page" :to="{name:'home',param:{}}">首页</router-link>
            </li>
            <li class="nav-item">
              <router-link class="nav-link" :to="{name:'userlist',param:{}}">好友列表</router-link>
            </li>
            <li class="nav-item">
              <router-link class="nav-link" :to="{name:'userprofile',param:{}}">用户动态</router-link>
            </li>
          </ul>
          <ul class="navbar-nav me-auto mb-2 mb-lg-0">
            <li class="nav-item">
              <router-link class="nav-link" :to="{name:'login',param:{}}">登录</router-link>
            </li>
            <li class="nav-item">
              <router-link class="nav-link" :to="{name:'register',param:{}}">注册</router-link>
            </li>
          </ul>
        </div>
      </div>
    </nav>
    </template>
    
    <script>
        export default{
            name: "NavBar",
        }
    </script>
    
    <style scoped>
    
    </style>
    
    • 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

    9. 用户动态页面的实现(三个组件)

    在这里插入图片描述
    userProfileInfo/userProfileWrite/userProfilePosts
    使用bootstrap的grid

    • 先对最大的一块进行划分
      在这里插入图片描述
      在这里插入图片描述
    • 再实现用户信息组件,对用户信息这个vue进行划分;以此类推
    • 对于图片:

    Bootstrap 中的图像使用.img-fluid. 这适用于图像max-width: 100%;,height: auto;以便它随父宽度缩放。

    图片变为圆形:

    img{
        border-radius: 50%;
    }
    
    • 1
    • 2
    • 3

    然后把文字等元素放进去,调调样式,用卡片包起来,即可完成这个模块。

    卡片:

    <div class="card">
      <div class="card-body">
        This is some text within a card body.
      </div>
    </div>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 帖子列表
      对于展示的个人信息、帖子列表都需要参数,这三个模块是相互交互的,对于这样的情况,需要将数据存到上层组件中。
      在这里插入图片描述
      上层组件UserProfileView.vue:
      // setup:()=>{
      // }
      // 当一个对象是函数时,可以简写为以下:
      setup(){
        const user =reactive({
          id:1,
          username:"ZhuJiaxuan",
          lastName:"Zhu",
          firstName:"Jiaxuan",
          followerCountL:0,
          is_followed:false,
    
        });
        //要用到的属性需要return
        return {
          user,
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    那么如何使用呢?(在不同组件之间传递信息)
    在这里插入图片描述
    在这里插入图片描述

    子组件接收:(props)
    在这里插入图片描述
    使用:
    在这里插入图片描述
    如果想要的数值需要被计算,如果需要用到传过来的属性
    使用computed,参数是一个函数
    在这里插入图片描述

        setup(props){
            let fullname=computed(()=>props.user.lastName+" "+props.user.firstName);
            return {
                fullname
            }
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    使用:直接使用{{fullname}}即可

    • 实现关注按钮
      逻辑: 如果没有关注,则显示 “关注”;如果已经关注,则显示 “取消关注”字样
      实现: 使用template的v-if

    在这里插入图片描述
    关注完以后,还需要更新user状态,此时需要定义事件处理函数。
    举例:
    在这里插入图片描述
    将这两个函数绑定起来:
    在这里插入图片描述
    子组件要向父组件传递消息:
    父组件:
    在这里插入图片描述
    在这里插入图片描述
    子组件:用context.emit可以出发父组件的事件
    在这里插入图片描述

    • 对于帖子列表,同理
      v-for
      在这里插入图片描述
    • 发帖区也是同理:
      UserProfileWrite.vue
    <template>
      <div class="card edit-field">
        <div class="card-body">
            <label for="edit-post" class="form-label">编辑帖子</label>
            <textarea class="form-control" id="exampleFormControlTextarea1" rows="3"></textarea>
            <button type="button" class="btn btn-outline-primary btn-sm">发帖</button>
        </div>
      </div>
    </template>
    
    <script>
    export default {
        name:"UserProfileWrite",
    
    }
    </script>
    
    <style>
    .edit-field{
        text-align: left;
        margin-top: 20px;
    }
    
    textarea{
        margin-bottom: 15px;
    }
    
    button{
        float:right;
        padding:2px 4px;
        font-size: 12px;
    
    }
    
    </style>
    
    • 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
    • 现在要将发帖区的内容显示在帖子列表区域
      子组件向父组件传递信息,然后父向子传递信息?!
      在这里插入图片描述
    • 首先要获取textarea里的信息
      在这里插入图片描述
      利用v-model,v-model的标签与内容绑定起来
      在这里插入图片描述
      举例:
      在这里插入图片描述
      在这里插入图片描述
    • 还需要一个触发函数。当click的时候,将textarea里的内容发成帖子。
      父组件需要一个函数, 并把这个函数暴露给按钮页即可
        const post_a_post =(content)=>{
          posts.count++;
          posts.posts.unshift({
            id:posts.count,
            userId:1,
            content:content,
          });
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    10. 用户列表页面实现

    从云端将用户列表读进来

    1. 安装 npm i jquery 使用ajax
    2. 页面中import $ from 'jquery';

    从云端动态获取用户(使用AJAX)

    <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>
    
    
    • 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

    使用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 实现登录

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

    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

    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;
    
    
    • 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

    LoginView.vue

    <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>
    
    
    • 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

    11.3 使用refresh刷新access

    因为5分钟access会过期,所以需要用到refresh进行刷新。

    方法1. 访问的时候发现access过期了,此时去获取一个新的access
    方法2. 每隔五分钟获取一次access,调用刷线access的接口,每五分钟一次

                     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);
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    12. 登录后跳转到用户列表页面

    1. 引入router
      在这里插入图片描述

    2. 使用api
      在这里插入图片描述

    13. 登录后修改展示页面

    NavBar修改一下。让这些页面都符合逻辑
    想要获取store中的全局变量,可以使用$ xxx
    在这里插入图片描述
    在这里插入图片描述

    14. 实现退出

    只需要写一个事件即可。
    在这里插入图片描述
    凡是要修改全局state,要把事件写到action/mutations里面 (需要store)
    在这里插入图片描述

    15. 未登录时的跳转

    userList.vue
    在这里插入图片描述
    点击时触发函数:
    在这里插入图片描述

    16. 用户动态从云端获取

    用户动态页面根据userId的改变而改变。
    还是ajax!
    在这里插入图片描述

    17. 判断发帖子模块是否需要

    只有在自己的页面才能发帖子。
    在这里插入图片描述

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

    App.vue
    在这里插入图片描述
    默认是用页面的name判断的,都叫userprofile,所以到别人页面,再点击自己的,就会出现不刷新不跳转的情况。

    19. 从前端删除到真的删除

    在这里插入图片描述

    在这里插入图片描述

    20. 部署

    1. build 打包成可以发布的版本

    在这里插入图片描述
    2. 打包
    在这里插入图片描述
    3. 传到服务器上

  • 相关阅读:
    ArcGIS绘制地球
    WoShop分销积分直播短视频商城全开源无加密商城源码
    C语言:指针数组与数组针的应用
    探索未来,开启无限可能:打造智慧应用,亚马逊云科技大语言模型助您一臂之力
    1382. 将二叉搜索树变平衡 ●●
    网络安全漏洞分析与漏洞复现
    github访问不进去,浏览器证书不安全,访问失败,证书失效,证书颁发者为VMware,谷歌浏览器小bug
    持续集成实战 —— Jenkins自动化测试环境搭建
    C++零碎记录(二)
    用ScheduledExecutorService接口,Quartz框架等创建定时任务
  • 原文地址:https://blog.csdn.net/qq_39679772/article/details/126367296