VUE项目

实现登录页面

  1. 复制一遍Register.vue, 改名:Login.vue

  2. 修改页面文本内容。

  3. 去掉重复密码。

 

Navbar组件

navbar组件用于实现顶部选项卡(导航)。其基本语法结构如下:

<mt-navbar v-model="navactive">
    <mt-tab-item id="1">人文</mt-tab-item>
    <mt-tab-item id="2">教育</mt-tab-item>
    <mt-tab-item id="3">科技</mt-tab-item>
    <mt-tab-item id="4">数码</mt-tab-item>
</mt-navbar>
  data() {
    return {
      navactive : '1'
    }
  },

  

案例: 访问/navbar 测试navbar

mt-tab-item提供了一个名为icon的插槽,可以通过该插槽设置导航项的图标。

 

在脚手架项目中可以存放的位置有两个: public/ src/assets/

public下的图片如何访问? src/assets下的图片如何访问?

public下的图片用绝对路径访问(/开头的路径)

例如:
有如下图片:  /public/images/001.png
vue中的访问方式:
<img src="/images/001.png">
src/assets下的图片用相对路径访问:

例如:

有如下资源:    /src/assets/001.png
vue中的访问方式:
<img src="../assets/001.png">
<img src="@/assets/001.png">

  

在脚手架的设计理念下,public属于静态资源目录,不在编译的范围内。而src文件夹下的资源都应属于源代码的一部分,无论是vue文件,还是图片文件,都应该被统一编译处理。所以vue在加载assets下的图片时,将会把这些 图片重新命名,统一放入一个/img/目录下,同时篡改src路径,使得可以正常访问该图片。

 

什么时候把图片放入public,什么时候将图片放入src/assets ?

public属于普通静态资源目录,页面中需要显示的大图,更新比较频繁的图片适合放在public下。

assets是需要经过编译的,所以经常存放项目中必要的小图标等资源,作为源代码的一部分,编译到项目中。而这个编译图片的过程也会对图片访问做一些性能上的优化:

若图片足够小,将会在编译时将该图片转成base64图片字符串,直接写入src:
<img src="base64:imagexx/xxxxxxjasdfhaskfhsdlkqwrqwr">
将会在页面初次加载时,就会把图片完整显示在页面中,不会导致由于网络环境导致小图标显示不全的问题。

TabContainer组件

TabContainer组件用于实现面板,页面中可以保存多个面板,并且实现面板内容的切换。其基本语法结构如下:

<mt-tab-container v-model="navactive">
    <mt-tab-container-item id="1">面板1</mt-tab-container-item>
    <mt-tab-container-item id="2">面板2</mt-tab-container-item>
    <mt-tab-container-item id="3">面板3</mt-tab-container-item>
    <mt-tab-container-item id="4">面板4</mt-tab-container-item>
</mt-tab-container>

  

实现首页中的页面布局

完善首页中的标题栏、顶部导航、面板等组件的配置。

 

Tabbar组件

Tabbar组件用于实现底部选项卡。 其语法结构:

<mt-tabbar v-model="selected">
    <mt-tab-item id="shouye">首页</mt-tab-item>
    <mt-tab-item id="gouwuche">购物车</mt-tab-item>
    <mt-tab-item id="wode">我的</mt-tab-item>
</mt-tabbar>
data:{
    selected: 'shouye'
}

  

案例: 新建testing/Tabbar.vue,测试底部选项卡的用法。访问/tabbar时看到组件效果。

动态图片的路径设置问题
若有一个img访问如下资源:

<img slot="icon"  src="@/assets/main_1.png" alt="">
vuecli将会把该图片进行编译,放入/img/下,并且篡改src路径:

<img slot="icon"  src="/img/main_1.8e7c1489.png" alt="">
若希望src内的路径为动态路径,在不同的情况下引用不同的图片时,需要为src添加冒号,变为动态路径:

<img slot="icon"  :src="'@/assets/main_1.png'" alt="">
注意:一旦为src添加冒号设置为动态路径,vuecli将不会对该路径进行处理。最终编译为:

<img src="@/assets/main_1.png">
所以,若想要动态访问src下的图片,需要在路径外添加require方法,require方法将会对该资源进行编译,并且返回编译后的路径:

<img :src="require('@/assets/main_1.png')" >

  

实现首页中底部选项卡

  1. 搭建Home.vue底部选项卡的结构。默认选中“首页”。

  2. 新建Me.vue。底部选项卡默认选中“我的”。

  3. 实现两个页面中切换底部选项卡时的业务流程。

 

Swipe组件

swipe组件用于实现轮播图,其语法结构为:

<mt-swipe>
    <mt-swipe-item>
        <img src="......">
    </mt-swipe-item>
    ......
</mt-swipe>

案例: 访问/swipe 看到testing/Swipe.vue

 

项目架构

基于B/S架构的项目。 使用http协议作为网络通信协议。服务端数据存储在mysql数据库中。前后端分离架构。

客户端:MintUI

服务端:nodejs + mysql

通信协议: http

 

搭建学子问答项目服务端

下载server.zip, 解压缩。

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

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

mysql -uroot -p < [把sql文件拖拽进来生成路径]
# 检查数据库
mysql -uroot -p  # 进入mysql
​
MariaDB [(none)]> show databases;
MariaDB [(none)]> use xzqa;
MariaDB [(none)]> show tables;
MariaDB [(none)]> select * from xxxxx;
启动server,提供web数据服务:

cd server
node app.js
在浏览器中测试接口。

http://localhost:3000/category
http://localhost:3000/articles?cid=1&page=1

项目实现

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

实现步骤

安装配置axios。

下载安装aixos:

cd scaffolding
npm install --save axios
配置main.js:

import axios from 'axios'
axios.defaults.baseURL = 'http://localhost:3000/'
Vue.prototype.axios = axios
在mounted中发送axios请求,获取类别列表,渲染页面。

/** 初始化导航列表 */
initNav(){
    this.axios.get('/category').then(res=>{
        console.log(res)
        // 将 res.data.results 存入 this.cats 中
        this.cats = res.data.results
    })
}
<mt-navbar style="margin-top: 40px"
           v-model="navactive" fixed>
    <mt-tab-item 
  v-for="(item, i) in cats" :key="i" :id="item.id+''">
        {{item.category_name}}
    </mt-tab-item>
</mt-navbar>

  

加载首页UI类别下的文章列表

实现步骤

  1. 编写文章列表项的页面组件结构与布局。

  2. mounted中发送http请求,访问ui类别下的首页数据。

Swipe组件

swipe组件用于实现轮播图,其语法结构为:

<mt-swipe>
<mt-swipe-item>
  <img src="......">
   </mt-swipe-item>
  ......
</mt-swipe>

案例: 访问/swipe 看到testing/Swipe.vue

 

切换顶部选项卡更新文章列表

由于每个选项卡的布局都一样,切换选项卡时仅仅需要更新当前列表数据即可,没必要那么多的面板。干掉仨,留下第一个即可。

实现步骤:

  1. 编写watch监听navactive的变化。一旦navactive有变化就意味着用户更改了顶部导航选中项。

  2. 一旦顶部导航更新了选中项,获取当前选中项的类别id(就是newvalue), 将id作为参数传给/articles地址查询该类别下的首页数据。

  3. 获取响应数据后,替换当前列表即可。

 

列表触底分页加载

mintui提供了Infinite Scroll指令(无限滚动指令)用于监听触底事件。其基本用法:

<div 
  v-infinite-scroll="loadmore" 一旦触底将会执行loadmore方法
  infinite-scroll-distance="触发事件时距离底部的阈值">
    <p>....</p>
    <p>....</p>
    <p>....</p>
    <p>....</p>
    <p>....</p>
    <p>....</p>
    .....
</div>
 

  

VUEUI Unit05

列表触底分页加载

mintui提供了Infinite Scroll指令(无限滚动指令)用于监听触底事件。其基本用法:

<div 
 v-infinite-scroll="loadmore" 一旦触底将会执行loadmore方法
 infinite-scroll-distance="触发事件时距离底部的阈值"
 infinite-scroll-disabled="infDisabled"
 :infinite-scroll-immediate-check="true">
   <p>....</p>
   <p>....</p>
   <p>....</p>
   <p>....</p>
   <p>....</p>
   <p>....</p>
  .....
</div>

 

触底加载下一页的业务逻辑

声明一个变量维护“当前页码”:page. 一旦触底loadmore, page++

在loadmore方法中发送http请求,请求当前类别下的下一页数据。

优化:

应该loadmore方法正在执行过程中,禁用无限滚动。

当loadmore方法请求发送完毕,响应接收完毕, 数据处理完毕后,再把无限滚动给打开。

一旦获取响应数据,将得到的新的一页文章列表 追加到当前文章列表的末尾。

 

/articles?cid=1&page=1
/articles?cid=1&page=2
/articles?cid=1&page=3
/articles?cid=1&page=4
.....
​

  

 

封装一个方法:loadArticles()用于异步加载文章列表

至此发现触底加载下一页时发送的请求,与切换选项卡、mounted后发送的请求非常类似,都是要加载文章列表。向同一个地址发请求,传递不同的参数,接收列表数据后更新列表。

不一样的地方是:传递参数不同,还有就是接收到响应后的处理方式不同 : mounted与切换选项卡后替换列表,而loadmore是要追加列表。可以设计一个方法, 封装这个功能,提高代码的重用性以及可维护性。

 

loadArticles方法是一个异步方法,该方法需要异步发送请求,并且把响应后的结果返回给方法的调用者。这个业务场景有两种解决方案:

callback

promise

loadArticles(cid, page, callback){
    this.axios.get('/articles?${cid}&${page}').then(res=>{
        let arts = res.data.results
        callback(arts)
    })
}
​
mounted(){
    this.loadArticles(1, 1, (arts)=>{
        // arts 就是服务端获取文章数组
        this.articles = arts
    } )
}
watchnav(){
    this.loadArticles(xxx, 1, (arts)=>{})
}
loadmore(){
    this.loadArticles(xx, xxxx, (arts)=>{})
}

  

 

文章详情页的实现

需求是点击首页中某一个文章列表项后,跳转到文章详情页 ,并且传递当前选中文章的id。 在详情页中接收该id参数,发送http请求, 获取详情数据, 更新界面。

实现步骤

  1. 准备好Article.vue

    解压缩,复制粘贴, 配置路由。 /article <---> Article.vue

  2. 通过routerlink,跳转页面,并且传参。

    vue中通过router-link路由跳转并且携带参数的方式有两种:

    第一种:使用?的方式向第二个页面传参。

    <router-link to="/article?name=x&id=xx">
    </router-link>

    详情页中如下方式接收idname

    mounted(){
    this.$route.query.id
    this.$route.query.name
    }

     

    第二种:使用路径参数向第二个页面传参。

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

    如下方式接收:

    {
    path: '/article/:id',
    component: Article
    }
    mounted(){
    this.$route.params.id
    }

     

     

  3. 接收参数,发送请求,获取响应,更新界面。

 

moment.js

moment.js是一个日期时间的js类库。 可以运行在浏览器及Node环境下。

moment.js的常用操作

解析(想方设法 获取一个Moment对象)

let day = moment()   // 描述 当前时刻 的 Moment对象
let day = moment('2020-10-12')  // 通过字符串创建Moment对象
day = moment('10-13/2020', 'MM-DD/YYYY')
day = moment('2020-10-01 11:11:11', 'YYYY-MM-DD HH:mm:ss')
day = moment.unix(秒级时间戳)

  

显示(将Moment对象输出成字符串)

let day = moment()
day.format()  -->   '2021-10-10T08:10:20xxxx'
day.format('YYYY年MM月DD日')  -->   '2020年12月12日'

  

安装配置moment.js
# 在项目目录下执行命令:
npm install moment --save
// 在main.js中,引入moment
import moment from 'moment'
Vue.prototype.moment = moment

  

实现详情页回到首页后,保留首页的状态

回到详情页:

<mt-button @click="$router.go(-1)" 
    icon="back" slot="left"></mt-button>
回到详情页后发现首页又做了一次初始化,显示UI类别下的首页数据。所以需要让Home.vue保活(keepAlive)。

在App.vue中添加keepAplive让vuerouter保活其中涉及到的组件:

<keep-alive>
    <router-view />
</keep-alive>
这么做虽然Home.vue保活了,但是重新点击文章列表项看另外一篇文章时,发现Article.vue也保活了,导致无法触发mounted,当然也就没有办法更新文章详情了。所以,又有一个新需求,Article.vue不需要保活。如下配置:

只有route中meta的keepAlive属性为true时,才保活
<keep-alive>
    <router-view v-if="$route.meta.keepAlive"/>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"/>
还需要在路由中(index.js)添加meta,指定什么路由需要keepAlive:

{
    path: '/article',
    component: Article,
    meta: {
        keepAlive: false  // Article 不希望被缓存
    }
},
{
    path: '/',
    name: 'Home',
    component: Home,
    meta: {
        keepAlive: true  // 希望被缓存
    }
},
保活业务完成后,又发现一个bug,当在Article.vue中滚动时,竟然会触发Home.vue的无限滚动。所以希望离开Home.vue时禁用无限滚动,回到Home.vue时再开启无限滚动的功能即可。这里需要使用keepAlive相关的两个生命周期方法:activated (当重新激活Home.vue时执行) deactivated(当离开Home.vue时执行)

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

  

 

实现注册业务

注册表单验证成功后,发送请求执行注册。

let params = `username=${this.name}&password=${this.pwd}`
this.axios.post('/register', params).then(res=>{
    console.log(res)
})
注册完毕后若返回成功,需要去数据库中验证是否注册了正确的数据。

mysql -uroot -p  进入mysql
select * from xzqa_author;
比较密码:是不是md5加密后的密码: select md5('123123');

  

登录业务

完成登录页面的表单验证。

发送post请求,执行登录操作。

针对不同的响应结果给出不同的界面呈现。

登录成功后,将用户存入vuex,其它页面中若需要当前登录用户则直接去vuex中找即可。

  

Vuex

Vuex是一个专门为vue.js应用程序开发的状态管理模式。它采用集中式的存储来管理应用中涉及到的状态信息(state)。

Vuex的基本使用
state 存储数据
state: {
    name:'zs'
},
如下访问:

this.$store.state.name
 

mutations 定义方法,修改state
mutations: {
    updateName(state, newName){
        state.name = newName
    }
},
如何访问:

//vuex,帮我调用updateName这个mutatitions,修改name,给你传个参数:zhangsan
this.$store.commit('updateName', 'zhangsan')
 

actions 定义方法,异步操作后调用mutations修改state

actions: {
    login(store, userinfo){
        axios.post('/login', ...).then(res=>{
            store.commit('updateName', name)       
        })
    }
},
如何访问actions:

this.$store.dispatch('login', xxxxxxxx)

  

 

vuex的确可以在不刷新的情况下解决用户状态管理的问题。但是一旦刷新页面,将会重新加载vue实例, 自然会销毁vuex中保存的所有的状态。如果需要持久化存储一些状态, 可以使用HTML5新特性中webstorage来解决。

所以通常情况下,vuex都需要与webstorage结合在一起实现一些需求。

 

WebStorage

webStorage提供了localStorageSessionStorage用于在客户端持久化存储键值对数据。

localStorage提供了一个独立的数据存储区域, 这部分数据将会永久存储在客户端本地。

sessionStorage提供了一个独立的数据存储区域,这部分数据只在当前会话中生效,关闭浏览器后将会自动销毁。

webstorage的基本使用

sessionstoragelocalstorage都可以通过window对象直接获取:

let ss = window.sessionStorage
let ls = window.localStorage

然后直接调用lsss的方法,即可对这两个存储空间进行操作:

如何存?

ss.setItem('name', 'zs')
ls.setItem('islogin', true)

如何取?

ss.getItem('name')
ls.getItem('islogin')

如何删?

ss.removeItem('name')
ls.removeItem('islogin')

如何清空?

ss.clear()
ls.clear()

 

 

实现用户状态的持久化保存

  1. 在登录成功后,将isloginname存入sessionStorage

  2. 当刷新页面时,vuex将会初始化,我们需要重置vuexisloginname两个变量的初始化值,取sessionStorage中读取即可。

 

vuecli项目上线流程
链接:https://pan.baidu.com/s/1BqWxsbs00qLkfCJ6E4peEQ
提取码:7lln

 

 

posted @ 2021-12-10 09:29  野居青年  阅读(111)  评论(0)    收藏  举报
/*鼠标跟随效果*/ /* 点击爆炸效果*/ /* 鼠标点击求赞文字特效 */