vue.js三十六—— 从无到有完整的项目实战3

1. 图片分享功能初步改造

1.1 图片分享路由改造

将图片分享a标签替换为router-link标签

<li class="mui-table-view-cell mui-media mui-col-xs-4 mui-col-sm-3">
                <router-link to="/home/photolist">
                    <img src="../../images/menu2.png"  alt="" />
                    <div class="mui-media-body">图片分享</div>
                </router-link>
            </li>

1.2 新建photolist组件模板

photolist.vue

<template>
    <div>
        <h3>图片分享</h3>
    </div>
</template>

<script>
export default {
    data(){
		return {
	
		}
	},
	created(){
	},
	methods:{

	}
}
</script>

<style lang="scss" scoped>
	
</style>

1.3 创建路由与组件的关系

1.3.1 导入photolist组件

import photolist from './components/photos/photolist.vue';

1.3.2 配置路由地址

{path:'/home/photolist',component:photolist}    // 图片分享

运行,点击图片分享,效果如图

2. 制作顶部滑动条

在MUI目录下找到tab-top-webview-main.html文件,打开复制我们所需要的代码,粘贴到photolist.vue文件中

<div id="slider" class="mui-slider mui-fullscreen">
            <div id="sliderSegmentedControl" class="mui-scroll-wrapper mui-slider-indicator mui-segmented-control mui-segmented-control-inverted">
                <div class="mui-scroll">
                    <a class="mui-control-item mui-active" href="#item1mobile" data-wid="tab-top-subpage-1.html">
                        推荐
                    </a>
                    <a class="mui-control-item" href="#item2mobile" data-wid="tab-top-subpage-2.html">
                        热点
                    </a>
                    <a class="mui-control-item" href="#item3mobile" data-wid="tab-top-subpage-3.html">
                        北京
                    </a>
                    <a class="mui-control-item" href="#item4mobile" data-wid="tab-top-subpage-4.html">
                        社会
                    </a>
                    <a class="mui-control-item" href="#item5mobile" data-wid="tab-top-subpage-5.html">
                        娱乐
                    </a>
        </div>
   </div>
</div>

运行,如图:

2.1 解决图片导航在顶部的问题

通过f12,审查元素,我们发现,该导航用到了两个类,一个是mui-slider一个是mui-fullscreen,很显然,第二个类是全屏的类,我们显然是不需要全屏的,所以删除这个类,保存,在查看界面,正常了,如图:

2.2 解决图片导航不能左右滑动的问题

我们发现,导航只显示到了娱乐,而我们实际上是还有科技的,这是因为,图片导航是一个js插件,我们只是引用了CSS,没有引入js,所以无法触发滑动。

2.2.1 引入mui.js

在photolist.vue中导入mui.js

import mui from '../../lib/mui/js/mui.min.js';

2.2.2 初始化滑动条

// 初始化滑动控件
mui('.mui-scroll-wrapper').scroll({
	deceleration: 0.0005 //flick 减速系数,系数越大,滚动速度越慢,滚动距离越小,默认值0.0006
});

运行,报错了,报错信息为“Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them”,经过我们合理的推测,觉得,可能是 mui.js 中用到了 'caller', 'callee', and 'arguments' 东西,但是, webpack 打包好的 bundle.js 中,默认是启用严格模式的,所以,这两者冲突了。

2.2.3 解决webpack打包默认严格模式的问题

1. 安装babel插件babel-plugin-transform-remove-strict-mode

 npm i babel-plugin-transform-remove-strict-mode -D

2. 配置babel

在 .babelrc 中的plugins节点中配置 "transform-remove-strict-mode"

{
  "presets": ["env", "stage-0"],
  "plugins": ["transform-runtime", 
              ["component", [
                {
                  "libraryName": "mint-ui",
                  "style": true
                }
              ]],
              "transform-remove-strict-mode"
  ]
}

配置完babel之后,发现滑动好了,但是,有很多很多警告,这个警告是谷歌浏览器为了提高画面流畅性而设置的。

2.2.4 解决滑动警告提示问题

可以加上一个样式,就可以了

* {
        touch-action: pan-y;
    }

注意:

1. touch-action用于指定某个给定的区域是否允许用户操作,以及如何响应用户操作(比如浏览器自带的滑动、缩放等)。具体详细用法可以参考css操作文档。

2. 属性值 pan-y 表示启用单指垂直平移手势 

2.2.5 解决初始化滑动无效的问题

我们发现,当我们点击图片分享,进入photolist的时候,滑动是失效的,需要刷新一下才能生效。很显然,出现这个问题的原因是滑动效果生效的时机不对,我们将滑动效果的代码移动到mounted中

mounted(){
        // 初始化滑动控件
        mui('.mui-scroll-wrapper').scroll({
            deceleration: 0.0005 //flick 减速系数,系数越大,滚动速度越慢,滚动距离越小,默认值0.0006
        });
    }

为什么将代码移到mounted中就可以了,因为mounted是vue的生命周期操作元素的最后一个生命周期函数,mounted是在页面已经生成好了,DOM结构也已经完成了,这时候,初始化滑动控件才有意义,因为该控件是基于js的,js是操作DOM的,所以只有在DOM加载完成之后,js才能生效,从这里我们可以得出一个结论,如果要操作DOM元素,最早要在mounted函数中

2.2.6 解决tabbar无法正常切换组件的问题

我们经过一系列的操作,发现滑动条做好了,但是,tabbar组件切换却失效了,这是因为在app.vue中的路由标签中的mui-tab-item类与mui中的冲突引起的,咱们只需要修改一下mui-tab-item的名字,在重写样式即可。

我们将mui-tab-item改成mui-tab-item1,并在style中重写mui-tab-item的样式

// 改类名,解决 tabbar 点击无法切换的问题
    .mui-bar-tab .mui-tab-item1.mui-active {
        color: #007aff;
    }

    .mui-bar-tab .mui-tab-item1 {
        display: table-cell;
        overflow: hidden;
        width: 1%;
        height: 50px;
        text-align: center;
        vertical-align: middle;
        white-space: nowrap;
        text-overflow: ellipsis;
        color: #929292;
    }

    .mui-bar-tab .mui-tab-item1 .mui-icon {
        top: 3px;
        width: 24px;
        height: 24px;
        padding-top: 0;
        padding-bottom: 0;
    }

    .mui-bar-tab .mui-tab-item1 .mui-icon~.mui-tab-label {
        font-size: 11px;
        display: block;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    

2.3 渲染列表数据

2.3.1 在data定义列表数组cates

2.3.2 在method中定义方法获取后台数据

getAllimgCategory(){
            this.$http.get('getimgcategory').then( res => {
                res.data.message.unshift({"id":0,"title":"全部"});
                this.cates = res.data.message;
            } );
        }

然后在created生命周期函数中调用

this.getAllimgCategory();

注意:这里有用到数组的unshift方法,该方法用于在数组的开始位置插入元素并返回插入之后的数组的长度。

3 渲染数据到页面

删除其他的a标签,只保留一个,用v-for循环赋值

<a :class="['mui-control-item',c.id == 0 ? 'mui-active' : '']" 
                        v-for="c in cates" :key="c.id" @tap="getPhotoListByCateGoryId(c.id)">
                        {{c.title}}
                    </a>

注意:这里的@tap时间是MUI特有的,可以解决@click事件在手机端无法切换组件的问题。

3.1 解决样式问题

我们发现,初始化数据之后,所有的a标签都是蓝色的,这明显与我们的需求不符,我们希望初始化的时候,全部为蓝色,其他的为黑色,所以我们希望让mui-active样式按需动态的加载,怎么实现了,我们可以使用vue的样式绑定,通过数组的形式来实现

<a :class="['mui-control-item',c.id == 0 ? 'mui-active' : '']" v-for="c in cates" :key="c.id">
    {{c.title}}
</a>

3.2 获取对应分类的图片列表数据并渲染页面

我们使用mintUI提供的Lazyload组件来加载图片

3.2.1 在main.js中配置

import { Lazyload } from 'mint-ui';

Vue.use(Lazyload);

3.2.2 在data中定义图片列表数据list

3.2.3 在method中定义获取数据方法

getPhotoListByCateGoryId(cateId){
            // 根据分类id获取图片列表
            this.$http.get('getimages/' + cateId).then( res => {
                this.list = res.data.message;
                console.log(JSON.stringify(this.list));
            } );
        }

3.3.4 定义getPhotoListByCateGoryId

在created生命周期函数调用getPhotoListByCateGoryId,参数为0,表示默认展示所有

created(){
        this.getAllimgCategory();
        this.getPhotoListByCateGoryId(0);
    },

3.3.5 定义图片列表区域

 <!-- 图片列表区域 -->
<ul>
   <li v-for="item in list" :key="item.id">
       <img v-lazy="item.img_url">
   </li>
</ul>

3.3.6 定义图片基本样式

img[lazy="loading"] {
    width: 40px;
    height: 300px;
    margin: auto;
}
img {
     width: 100%;
     vertical-align: middle; // 垂直对齐方式
}

3.3.7 美化图片展示样式与文字显示

ul标签

<!-- 图片列表区域 -->
        <ul class="photo-list">
            <li v-for="item in list" :key="item.id" >
                <img v-lazy="item.img_url">
                <div class="info">
                    <h1 class="info-title">{{item.title}}</h1>
                    <div class="inf-body">{{item.zhaiyao}}</div>
                </div>
            </li>
        </ul>

样式

.photo-list {
        list-style: none;
        margin: 0;
        padding: 10px;
        padding-bottom: 0;
        li {
            background-color:#ccc;
            text-align: center;
            margin-bottom: 10px;
            box-shadow: 0 0 10px #999;  // 加边框阴影
            position: relative;
            img[lazy="loading"] {
                width: 40px;
                height: 300px;
                margin: auto;
            }
            img {
                width: 100%;
                vertical-align: middle; // 垂直对齐方式
            }

            // 文字样式
            .info {
                color: white;     // 文字背景色
                text-align: left;   // 文字居左对齐
                // 怎么让文字在图片上显示了?因为图片在li中,所以让li相对定位,img绝对定位,同时让bottom为0
                position: absolute; 
                bottom: 0;
                width: 100%;
                max-height: 80px;
                background-color: rgba(0, 0, 0, 0.3);
                .info-title {
                    font-size: 14px;
                }
                .info-body {
                    font-size: 12px;
                }
            }
        }
    }

 

效果图:

注意:这里要让文字位于图片上,需要设置父容器的相对位置,文字容器绝对定位。

3.3.8 解决图片滚动区域上滑动的时候,覆盖header的问题

当我们往下拉的时候,发现滚动区域会覆盖在header,如图:

怎么解决了?我们用开发者模式观察header,发现其有一个类mint-header,我们在app.vue中,重写这个类

 .mint-header {
        z-index:99;
    }

问题解决

4 实现图片详情的数据加载与页面美化

4.1 改造路由标签

<!-- 图片列表区域 -->
<ul class="photo-list">
    <router-link v-for="item in list" :key="item.id" 
         :to="'/home/photoinfo/' + item.id" tag="li">
        <img v-lazy="item.img_url">
        <div class="info">
              <h1 class="info-title">{{item.title}}</h1>
              <div class="inf-body">{{item.zhaiyao}}</div>
        </div>
    </router-link>
</ul>

注意:

1. 因为这里用到了动态的参数,所以to属性需要用属性绑定。to后面跟的是表达式,所以字符串用单引号括起来。

2. tag表示将router-link渲染成什么标签,加这个属性的原因是,router-link默认渲染的是a标签。

4.2 新建photoinfo.vue组件模板与路由配置

4.2.1 模板创建

<template>
    <div class="newsinfo-container">
        <h3 class="title">{{newsInfo.title}}</h3>
        <p class="subttle">
            <span>发表时间:{{newsInfo.add_time | dateFormate}}</span>
            <span>点击:{{newsInfo.click}}次</span>
        </p>
        <hr/>
        <div class="content" v-html="newsInfo.content"></div>
        <comment-box :id="this.id"></comment-box>
    </div>
</template>

<script>
// 导入评论子组件
import comment from '../subComponents/comment.vue';
export default {
    data(){
		return {
            id:this.$route.params.id,
            newsInfo:{}
		}
	},
	created(){
		this.getNewsInfo();
    },
	methods:{
		getNewsInfo(){
            this.$http.get('getnew/'+this.id).then( response => {
                this.newsInfo=response.data.message;
            } );
        }
    },
    components:{ // 用来注册子组件的节点
        "comment-box":comment   // 给组件comment取一个别名 comment-box
    }
}
</script>

<style lang="scss">
    .newsinfo-container {
        padding: 0 4px;  // 左右内边距
        .title {
            font-size: 16px;
            text-align: center;
            margin: 15px 0; // 上下外边距
            color: red;
        }
        .subttle {
            font-size: 13px;
            color: #226aff;
            display: flex;		// CS3语法
            justify-content: space-between; // 两端对齐
        }
        .content {
            img {
                width:100%;
            }
        }
    }
    
</style>

4.2.2 路由配置

// 导入图片详情组件
import photoinfo from './components/photos/photoinfo.vue';

{path:'/home/photoinfo/:id',component:photoinfo} // 图片详情

4.3 photoinfo.vue的基本布局

<template>
    <div class="photoinfo-container">
        <h3>{{photoinfo.title}}</h3>
        <p class="subtitle">
            <span>发表时间:{{photoinfo.add_time | dateFormate}}</span>
            <span>点击:{{photoinfo.click}}次</span>
        </p>

        <hr/>

        <!-- 图片缩略图区域 -->
        <div>

        </div>

        <!-- 图片内容区域 -->
        <div class="content" v-html="photoinfo.content"></div>

    </div>
</template>

<script>
export default {
    data(){
		return {
            id:this.$route.params.id,
            photoinfo:{}
		}
	},
	created(){
        this.getPhotoInfo();
    },
    mounted(){
        
    },
	methods:{
       getPhotoInfo(){
           this.$http.get('getimageInfo/'+this.id).then(res => {
               this.photoinfo = res.data.message;
               console.log("this.photoinfo="+JSON.stringify(this.photoinfo));
           });
       }
    }
}
</script>

<style lang="scss" scoped>
    .photoinfo-container {
        padding: 3px;
        h3 {
            color:#26A2FF;
            font-size: 16px;
            text-align: center;
            margin: 15px 0;
        }
        .subtitle {
            display: flex;
            justify-content: space-between;
            font-size: 13px;
        }
        .content {
            font-size: 13px;
            line-height: 30px;
        }
    }
</style>

添加评论子组件

三个步骤:

1. 导入组件

2. 注册组件

3. 标签的形式引入组件

// 导入评论子组件
import comment from '../subComponents/comment.vue';

components:{
        'cms-box':comment
    }

<!-- 评论子组件 -->
        <cms-box :id="id"></cms-box>

效果图:

4.4 完成图片详情缩略图制作

4.4.1 vue-preview

vue-preview是一个vue集成的photoSwipe图片预览插件

地址:https://github.com/LS1231/vue-preview

4.4.2 安装 vue-preview

npm i vue-preview -S

4.4.3 vue-preview使用

1. 导入组件

/**
 * 导入vue-preview组件
 *  */
import VuePreview from 'vue-preview';
Vue.use(VuePreview);

2. 定义缩略图标签

 <!-- 缩略图区域 -->
 <template>
       <vue-preview :slides="list" @close="handleClose"></vue-preview>
</template>

3. 在data中定义list图片数组

list: [] // 缩略图的数组

4. 调用方法获取数据

getPhotoListByCateGoryId(){
            // 根据分类id获取图片列表
            this.$http.get('getImagsById/' + this.id).then( res => {
                res.data.message.forEach(item => {
                    item.w = 400;
                    item.h = 300;
                });
                this.list = res.data.message;
                console.log("this.list = " + JSON.stringify(this.list));
            } );
            
        },

注意:

1. 因为后台返回的数据没有w和h,所以需要循环为每一项都赋w与h

2. 另一种缩略图方式

2.1 导入同上

2.2 引入缩略图标签

<!-- 缩略图区域 -->
    <div class="thumbs">
      <img class="preview-img" v-for="(item, index) in list" :src="item.src" height="100" @click="$preview.open(index, list)" :key="item.src">
    </div>

2.3 获取缩略图数据

getThumbs() {
      // 获取缩略图
      this.$http.get("api/getthumimages/" + this.id).then(result => {
        if (result.body.status === 0) {
          // 循环每个图片数据,补全图片的宽和高
          result.body.message.forEach(item => {
            item.w = 600;
            item.h = 400;
          });
          // 把完整的数据保存到 list 中
          this.list = result.body.message;
        }
      });
    }

2.4 定义样式

.thumbs{
    img{
      margin: 10px;
      box-shadow: 0 0 8px #999;
    }
  }

box-shadow给图片加阴影。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值