MintUi项目实战(项目中BUG的处理)

项目架构

基于BS架构项目。 使用http作为网络协议,数据存储在mysql数据库。前后端分离。

客户端:VueCLIMintUI

服务端:nodejsmysqlexpress

搭建学子问答项目的服务端

  1. 下载server.zip,解压。

  2. 下载xzqa.sql,导入mysql数据库。

    打开xampp,启动mysql服务。 点击shell, 进入命令行,执行命令:

    mysql -u root < [把xzqa.sql文件拖拽到此处生成路径即可]
    

    导入成功后,可以进入mysql,查看一下数据:

    root>  mysql -u root 
    MariaDB> show databases;
    MariaDB> use xzqa;
    MariaDB> show tables;
    MariaDB> select * from xzqa_category;
    MariaDB> desc xzqa_article;
    MariaDB> select id, subject from xzqa_article limit 0,5;
    MariaDB> select xa.id, xa.subject, xc.category_name from 
    	xzqa_article xa join xzqa_category xc on xa.category_id=xc.id
    	limit 0,5;
    
  3. 启动server,提供http访问接口。

    node app.js
    

    访问地址:

    http://localhost:3000/category
    

项目实现

加载首页中的类别列表信息

实现步骤

  1. 安装配置axios

    安装axios

    # 进入项目目录下,执行安装命令
    npm  install  --save  axios
    

    配置main.js

    import axios from 'axios'
    axios.defaults.baseURL = 'http://localhost:3000/'
    Vue.prototype.axios = axios  // 任何Vue对象都将会携带一个属性:axios
    
  2. Index.vuemounted中发送http请求,获取响应,渲染页面。

    /** 发请求,加载文章类别列表 */
    loadCats(){
        this.axios.get('/category').then(res=>{
            console.log('加载类别列表', res)
            this.cats = res.data.results   // 将数组存入data.cats
        })
    }
    
加载首页UI类别下的文章列表数据(第一页数据)
http://localhost:3000/articles?cid=1&page=1
http://localhost:3000/articles?cid=1&page=2
http://localhost:3000/articles?cid=1&page=5
http://localhost:3000/articles?cid=2&page=1
.......

实现步骤:

  1. Index.vuemounted生命周期方法中,发送http请求,访问ui类别下的首页文章列表。

    // 加载UI类别下的首页文章列表
    this.axios.get(`/articles?cid=1&page=1`).then(res=>{
        console.log('加载UI类别下首页数据', res)
        this.articles = res.data.results  // 将文章数组存入data.articles
    })
    
  2. 获取数据,存入data,在页面完成遍历显示。

    <ArticleItem v-for="(item, i) in articles" :key="i"
                 :article="item" />      
    

    遍历输出20个ArticleItem组件,需要给每一个组件传递参数(当前文章信息)。

    ArticleItem组件中接收,并且显示在页面中。

    <template>
    	....
        {{article.subject}}
        ....
    </template>
    
    export default {
      props:['article'],  // article接受了当前文章信息对象{id,desc,img,sub}
      ....
    };
    
实现切换顶部导航时更新文章列表

由于每个选项卡的布局都一样,切换顶部选项卡时仅仅需要更新列表就行了。所以没必要搞那么多的面板。干掉仨,留下一个即可。

当点击某一个顶部选项卡时,获取当前激活项的id,发送http请求,获取响应数据,重新渲染列表。

列表的触底分页加载

需求:当列表滚到底部,触发事件,在事件处理函数中,发送请求,加载下一页数据,追加到当前文章列表的末尾即可。

Infinite Scroll指令 (无限滚动指令)

Infinite Scroll 用于监听元素的触底事件。 基本使用方法:

<div v-infinite-scroll="loadMore"   当div滚动到底自动执行loadMore方法
     infinite-scroll-distance="定义无限滚动触发的距离阈值">
    <p>.....</p>
    <p>.....</p>
    <p>.....</p>
    ......
</div>
methods:{
	loadMore(){  console.log('到底了~')  }
}

防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。

节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率

实现思路
  1. 为列表容器添加无限滚动指令。

    <mt-tab-container v-infinite-scroll="loadMore"
                      infinite-scroll-distance="50">
        ....
    </mt-tab-container>
    
  2. 触底后加载下一页。就需要在data中声明一个变量page用于保存当前页码。每次下一页时,page++。然后向当前类别的下一页发送请求即可。

    /articles?cid=2&page=1
    /articles?cid=2&page=2
    /articles?cid=2&page=3
    /articles?cid=2&page=4
    
    this.page++
    let cid = this.active
    let page = this.page
    http://localhost:3000/articles?cid=${cid}&page=${page}
    
  3. 将得到新文章列表追加到当前列表的末尾。

  4. 处理一下节流问题。通过isLoading变量防止触底频繁发送请求。

  5. 处理刷新页面时立即执行一次loadMorebug

    问题的原因在于infinite-scroll指令。 它将会在首页数据不满一屏幕的情况下,自动执行loadMore

  6. 切换顶部导航时,需要将滚动条复位,还有需要重置this.page为1.

    // 将滚动条滚动到顶部
    window.scrollTo(0, 0)
    // 重新重置page变量为1
    this.page = 1
    

异步方法的封装

至此我们发现,有3个地方都发送了/articles请求,希望获取到文章列表:

  1. mounted /articles?cid=1&page=1
  2. watch active /articles?cid=xxxxxx&page=1
  3. loadMore /articles?cid=xxxx&page=xxxx

我们可以将访问文章列表的请求,封装到一个loadArticles方法中,这样,这三个地方都可以直接调用这个loadArticlies方法,提高代码的重用性与可维护性。

该方法的功能是,接收cid与page,发送请求, 返回articleList
loadArticles(cid, page, callback){
    this.axios.get('/articles?cid=${cid}&page=${page}').then(res=>{
        let articleList = res.data.results
        callback(articleList)  // 执行callback方法
    })
}
mounted(){
    this.loadArticles(1, 1, (articleList)=>{
        this.articles = articleList   // 替换列表
    })
}
watch Active(){
    this.loadArticles(this.active, 1, (articleList)=>{
        this.articles = articleList
    })
}
loadMore(){
    this.loadArticles(this.active, ++this.page, (articleList)=>{
        this.articles.push(...articleList)
    })
}

自定义封装的方法内部执行异步任务,异步任务的结果是无法直接通过return返回的。如果需要返回异步任务的结果给自定义方法的调用者,两种方法:

  1. callback
  2. promise

实现文章详情页的内容展示

业务流程:点击首页列表项中某一项时,跳转到详情页,显示选中项文章的详情信息。

实现步骤

  1. 点击列表项,跳转到详情页。 跳转的同时,需要将选中项文章的ID传给详情页。

    传参的第一种方式:

    Index.vue

    <router-link to="/article?id=123"></router-link>
    

    Article.vue

    mounted(){
        let id = this.$route.query.id
    }
    

    传参的第二种方式:

    Index.vue

    <router-link to="/article/123"></router-link>
    <router-link to="/article/237"></router-link>
    <router-link to="/article/238"></router-link>
    

    router/index.js

    {
        path: '/article/:articleId',
        component: Article组件
    }
    

    Article.vue

    mounted(){
        this.$route.params.articleId
    }
    
  2. 在详情页中获取选中文章的ID,发送http请求,获取详情数据。/detail?id=xx

  3. 获取到详情数据后,将信息渲染到页面上。

处理刷新首页时滚动位置的更新问题

基于Vue的滚动行为解决刷新滚动位置的修改。

基于keepAlive实现首页的保活

router/index.js合适的路由中,添加路由meta信息,指定哪些路由组件需要保活:

{
    path: 'index',
    component: () => import('../views/Index.vue'),
    meta: {
        keepAlive: true
    }                            
},

App.vue中,使用keepAlive组件包裹router-view。被包裹的路由组件将会保活。

<keepAlive>
	<router-view v-if="$route.meta.keepAlive"/>
</keepAlive>
<router-view v-if="!$route.meta.keepAlive"/>

如上配置即可实现首页的保活,但是,当跳转到详情页后,在滚动时会触发mintui的无限滚动指令监听方法。解决方法如下:

当首页开启了keepAlive,将会解锁两个生命周期方法,activated deactivated

activated() {
	this.isLoading = false;
},
deactivated() {
	this.isLoading = true;
},

实现注册业务

业务流程:

在注册页面,填写表单;

点击快速注册,验证表单;

验证成功后,发送注册请求,提交用户信息,执行注册业务;

  1. 注册成功,跳转到登录;
  2. 注册失败,弹窗提示。

实现登录业务

业务流程:

在登录页面,填写表单;

点击登录,验证表单;

验证成功后,发送登录请求,提交用户信息,执行登录业务;

  1. 登录成功,跳转到首页;
  2. 登录失败,弹窗提示。

基于Vuex登录成功后在首页提示用户信息

Vuex

state 用于定义存在vuex中的状态信息

mutations 用于定义修改state所需要的方法

actions 用于定义异步方法,执行完异步任务后,可以调用mutations修改state

Vuex的核心功能就是在合适的时间点,存数据、取数据。

实现步骤:

  1. store/index.js中,向state对象中存入一些信息,用来全局保存用户登录状态。

    state:{
        isLogin: true,
        name: 'zs'
    }
    

    在页面中引用:

    <div slot="right" v-if="$store.state.isLogin">
        欢迎:{{$store.state.name}}
    </div>
    
  2. 在vuex的mutations声明一个方法,用于登录成功后修改state

    mutations: {
        /** 定义一个方法 当登录成功后修改state
         *  state: vuex将会自动传入state对象,方便操作变量
         *  newname: 该参数是调用者携带的自定义参数
         */
        loginOK(state, newname){
            state.isLogin = true
            state.name = newname
        }
    },
    

    如何调用mutations中声明的方法:

    // commit()方法用于请求vuex,执行mutations中定义的loginOK
    this.$store.commit('loginOK', 'zhangsan')
    
Actions

actions中定义函数,异步完成任务得到结果后,将结果更新到state

actions:{
    login(store, userObj){
        // actions中执行异步任务
        执行登录().then(res=>{
            // 异步任务得到结果后,不能直接操作state,应该调用store.commit方法
            // 让mutations直接修改state。
            store.commit('loginOK', userObj.name)
        })
    }   
}

vuex可以在不刷新页面的前提下保存多页面的共享数据。但是一旦刷新,意味着页面将重新加载,整个Vue容器也将会重新加载,Vuex中存储的数据也将不复存在,全部初始化。也就无法保存登录状态信息。

如果希望持久化保存用户数据(刷新不销毁,甚至客户端关机重启依然存在),推荐使用HTML5新特性中的WebStorage来解决。

WebStorage

WebStorageHTML5提供的可以让前端持久化缓存数据的存储空间。包含两种对象:

  1. sessionStorage: 这一块存储空间存储的数据单浏览器会话生效。重启浏览器即销毁。
  2. localStorage: 这一块存储空间存储的数据永久有效。
WebStorage相关API

存数据:

sessionStorage.setItem('name', '张三')
localStorage.setItem('age', '15')

let user = {"id":1,"name":"zs","age":15}
sessionStorage.setItem('user', JSON.stringify(user))

读数据:

sessionStorage.getItem('name')  -->  '张三'
localStorage.getItem('age')   -->  '15'

sessionStorage.getItem('user')  -->  JSON字符串
JSON.parse(sessionStorage.getItem('user'))  -->  JS对象

删除数据:

sessionStorage.removeItem('name')
localStorage.removeItem('name')

清空数据:

sessionStorage.clear()
localStorage.clear()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值