回头看自己的代码,犹如鸡肋!!!里面有很多问题,建议大家不要看。我没时间整理╮(╯▽╰)╭

跨域解决方案

  config/dev.env.js

'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env') module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
API_ROOT: '"/api"'
})

  config/prod.env.js ,生产的服务器(你线上运行时的服务器)

'use strict'
module.exports = {
NODE_ENV: '"production"',
API_ROOT: '"http://api.xxx.com/"'
}

  config/index.js

    proxyTable: {
'/api': {
// target: 'https://www.xxx.com/',
// target: 'http://m.xxx.com/',
target: 'http://api.xxx.com/',
changeOrigin: true,
secure: false,
pathRewrite: {
'^/api': ''
}
}
}, // Various Dev Server settings
// host: 'xxx.xxx.xx.x', // can be overwritten by process.env.HOST //公司本地IP
host: 'localhost', // can be overwritten by process.env.HOST
port: 8085, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined

  接口请求的时候

export const _HomeNavList = params => {
return req('post', rootUrl+ '/xxxx/xxxxx/xxxxx/xxx',params)
}

rem设置

  有多种方式,可以 js,也可以 css 设置。
  鉴于 H5 的浏览器都比较高级,可以使用一些最新的属性,这里先介绍 css 的写法。 
/*rem设置*/
html{
font-size: calc(100vw/7.5); /*1rem=100px*/
}

  js 设置 rem,如下。

(function (doc, win) {
var docEl = doc.documentElement,
// 手机旋转事件,大部分手机浏览器都支持 onorientationchange 如果不支持,可以使用原始的 resize
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function () {
//clientWidth: 获取对象可见内容的宽度,不包括滚动条,不包括边框
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
docEl.style.fontSize = 100 * (clientWidth / 750) + 'px';
};
recalc();
if (!doc.addEventListener) return;
//注册翻转事件
win.addEventListener(resizeEvt, recalc, false);
})(document, window);

axios 的封装

  刚开始我也是设置 axios 的 baseURL ,以及在拦截器里把数据用 qs 序列化。后来又改回来了。

  最后有个需求是要把图片上传到七牛云(后面会讲),那么 axios 就不能在拦截器里设置了。

import axios from 'axios'
import qs from 'qs' axios.defaults.timeout = 5000;
// axios.defaults.baseURL = process.env.API_ROOT; //填写域名 //http request 拦截器
axios.interceptors.request.use(
config => {
// config.data = qs.stringify(config.data);
config.headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
return config;
},
error => {
return Promise.reject(err);
}
); //响应拦截器即异常处理
axios.interceptors.response.use(response => {
return response
}, err => {
if (err && err.response) {
switch (err.response.status) {
case 400:
console.log('错误请求')
break;
case 401:
console.log('未授权,请重新登录')
break;
case 403:
console.log('拒绝访问')
break;
case 404:
console.log('请求错误,未找到该资源')
break;
case 405:
console.log('请求方法未允许')
break;
case 408:
console.log('请求超时')
break;
case 500:
console.log('服务器端出错')
break;
case 501:
console.log('网络未实现')
break;
case 502:
console.log('网络错误')
break;
case 503:
console.log('服务不可用')
break;
case 504:
console.log('网络超时')
break;
case 505:
console.log('http版本不支持该请求')
break;
default:
console.log(`连接错误${err.response.status}`)
}
} else {
console.log('连接到服务器失败')
}
return Promise.resolve(err.response)
}) // 通用公用方法
export const req = (method, url, params) => {
return axios({
method: method,
url: url,
data: qs.stringify(params) ,
// traditional: true,
}).then(res => res.data);
};

底部菜单栏

  mint-ui的底部菜单栏,我个人觉得用的不是很习惯,找了很多资料才勉强填上这个坑,如下:

    <mt-tabbar class="bottom-tab" v-model="tabSelected">
<mt-tab-item id="home">
<span class="iconfont icon-zhuye"></span>
<p>首页</p>
</mt-tab-item>
<mt-tab-item id="study">
<span class="iconfont icon-xianshanghuodong"></span>
<p>学习</p>
</mt-tab-item>
<mt-tab-item id="ask">
<span class="iconfont icon-kefu"></span>
<p>咨询</p>
</mt-tab-item>
<mt-tab-item id="user">
<span class="iconfont icon-wode"></span>
<p>我的</p>
</mt-tab-item>
</mt-tabbar>

  路由嵌套,底部 tabbar 是第一层组件,点击底部元素,可切换不同模块

{
path: '/bottomTab',
component: bottomTab,
children: [{
path: '/home',
name: 'home',
component: home,
meta: {
keepAlive: true,
}
},
{
path: '/study',
name: 'study',
component: study,
meta: {
RequireLogin: true
}
},
...
}

  最后我是没有设置默认选中,默认的是组件创建的时候的路由名称,然后在路由变化时,直接 watch 监控路由的名称,并作出相关操作

export default {
data() {
return {
tabSelected: "",
routerPath: ""
};
},
created() {
this.tabSelected = this.$route.path.slice(1);
},
mounted() {},
beforeDestroy() {},
watch: {
$route(to, from) {
if (
to.name == "home" ||
to.name == "study" ||
to.name == "ask" ||
to.name == "user"
) {
this.routerPath = this.$route.path;
this.tabSelected = this.routerPath.slice(1);
}
},
tabSelected: function(val, oldVal) {
this.$router.push({
name: val
});
}
},
methods: {},
computed: {}
};

返回上一页

  顶部返回上一页,有的需求是直接发个详情页的链接给别人,然后客户在点击返回的时候,是没有本站的浏览记录的。那么可能会退出到一个空白页,造成不必要的客户流失,我们的需求是让他去首页或者本站的其他页面,留住客户。

    <mt-header :title="headTitle">
<mt-button icon="back" slot="left" @click="goBack">返回</mt-button>
</mt-header>

  浏览记录最少要有2条,否则去首页。我刚开始写的1,最后发现空白页也是记录。

  methods: {
goBack() {
if (window.history.length <= 2) {
this.$router.push({ path: "/" });
return false;
} else {
this.$router.back();
}
}
},

路由守卫

  有些页面是需要登录了之后才能进的,这样的页面如果多了,就可以用路由守卫来判断

router.beforeEach((to, from, next) => {
// 登录页、不需要登陆的和已登录的页面直接跳转
if (to.path == "/login" || !to.meta.RequireLogin || localStorage.getItem("user")) {
next();
} else {
next({
path: "/login",
query: {
redirect: to.fullPath
}
})
}
})

  路由守卫跳转过来的登录页,是带参的(目标页面的路径)在登录成功之后,就自动进入目标页面

              if (r.Code == 0) {
this.LOGIN(r.Data)
if (this.$route.query.redirect) {
this.$router.push({
path: this.$route.query.redirect
});
} else {
this.$router.push("/");
}
}

列表页上拉加载,下拉刷新

  课程列表页做了这个功能,待验证,使用  mt-loadmore

视频格式 m3u8

  这个格式的视频还是挺多的,但是实现播放的话,就有点复杂了(要装两个插件,还一堆问题),折腾了两天,这速度算快还是慢呢。

import 'video.js/dist/video-js.css'
import 'vue-video-player/src/custom-theme.css'
import videojs from 'video.js'
//得手动绑定对象,不然找不到
window.videojs = videojs
//这里写成 import 还不行,必须得 require
require('videojs-contrib-hls/dist/videojs-contrib-hls');

  写元素的时候,可以不用写 source

      <video id="video-wrap" class="video-js vjs-custom-skin vjs-big-play-centered">
<!-- <source
src="http://xxx.m3u8"
type="application/x-mpegURL"
> -->
</video>

  如果多格式类型的视频,可能需要自动判断

  mounted() {// 创建播放器
this.videoPlay = videojs('video-wrap', {
playbackRates: [0.7, 1.0, 1.5, 2.0], //播放速度
autoplay: false, //如果true,浏览器准备好时开始播放
muted: false, //默认情况下将会消除任何音频
loop: false, //导致视频一结束就重新开始
preload: 'auto', //建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
aspectRatio: '4:3', // 16:9 不会自动放中间
// fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
// width:720,
// height:540,
notSupportedMessage: '此视频无法播放',
controls: true,
// sources: [{
// // type: "application/x-mpegURL", //video/mp4
// // type: "", //video/mp4
// // src: "http://37273.long-vod.cdn.aodiany210ad87667dd544439b28733e.m3u8",
// }],
// bigPlayButton: true,
// textTrackDisplay: false,
// posterImage: true,
// errorDisplay: false,
// controlBar: true
})
},
watch: {
onlineVideoVideoId(){
this.videoPlayUrl(this.onlineVideoInfo)
}
},
methods: {
videoPlayUrl(info) {
// 视频观看
// console.log(info);
if (this.user) {
if (info.bought == true) {
// 获取课程视频
_StageItemPlayUrl({
courseId: this.$route.query.id,
memberId: this.user.id,
classId: info.videoId,
}).then(res => {
// console.log(res)
if (res.Code === "0") {
this.showVideoPlayer = true;
this.changeVideo(res.Data.positiveUrl)
}
}).catch((err) => {
console.log(err)
})
} else {
console.log('没有购买')
this.$toast({
message: '请购买课程',
position: 'bottom',
duration: 2000
});
}
} else {
this.$router.push({
path: '/login',
query: {
redirect: to.fullPath
}
})
}
},
changeVideo(vdSrc) {
// 切换视频路径及类型
if (/\.m3u8$/.test(vdSrc)) {
this.videoPlay.src({
src: vdSrc.replace("http://", "https://"),
type: 'application/x-mpegURL'
})
} else {
this.videoPlay.src({
src: vdSrc,
type: 'video/mp4'
})
}
this.videoPlay.load();
this.videoPlay.play(); //pause()暂停 销毁 dispose()
},
},
beforeDestroy() {
this.videoPlay.dispose();
console.log("video destroy");
}

  在 build/webpack.base.conf.js 的 moudel 拿了要加上 noParse: [/videojs-contrib-hls/],不然可能会报错 t is not definded 之类的错误。

  但是我在移动端没写上面这个操作,也播放成功了,PC端写了。现在不确定这段代码是否有必要。

  module: {
noParse: [/videojs-contrib-hls/],
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
...

mt-radio 的使用

  需求是做一个单选的数据列表,但是 mt-radio 的 options 的数据结构是 label 和 value ,其中 label 是显示的名称, value 是值。

  那么我们的数据结构就也得是 value 和 label 了,如果不是,就必须得手动转换。

            Object.values(this.majorList).map(value => {
value.value = value.id;
value.label = value.majorName;
// console.log(value)
// console.log(this.majorList)
});

自适应多层级目录

  使用迭代,

  调用:

            <DetailMultiMenu
v-for="(classItem,index) in this.classListData"
:key="index"
:item="classItem"
@videoInfo="videoPlayUrl"
></DetailMultiMenu>

  组件:

<template>
<ul class="multi-menu">
<li v-if="item.stageName == ''">
<div
class="class-title-wrap"
@click="toggleItemList = !toggleItemList"
:style="{marginLeft: 0.3*(item.level-1) +'rem'}"
>
<span>
<i class="iconfont icon-caidan"></i>
<span>{{item.classjName}}</span>
</span>
<i :class="[toggleItemList?'iconfont icon-xiangshang':'iconfont icon-xiangxia']"></i>
</div> <ul v-for="(child,index) in item.sub" :key="index" v-show="toggleItemList">
<DetailMultiMenu v-if="child.stageName == ''" :item="child" :key="child.classjName"></DetailMultiMenu>
<li
v-else
:key="child.id"
:class="activeLi+index == child.id+index ? 'activeLi': ''"
@click="videoInfo(child.id,child.isPay,child.id)"
>
<div class="class-item-wrap" :style="{marginLeft: 0.3*(child.level-1) +'rem'}">
<span class="class-title">
<i class="iconfont icon-zhibo11"></i>
<span>{{child.classjName}}</span>
</span>
</div>
</li>
</ul>
</li> <li v-else class="class-item-wrap">
<div>
<i class="iconfont icon-zhibo11"></i>
{{item.classjName}}
</div>
</li>
</ul>
</template>
<script>
import {
// mapGetters,
mapMutations
// mapState
} from "vuex";
export default {
name: "DetailMultiMenu",
data() {
return {
toggleItemList: false,
activeLi: -1
};
},
props: {
item: {
type: Object,
required: true
}
},
computed: {},
created() {},
mounted() {},
methods: {
...mapMutations([
"ONLINE_VIDEO_VIDEOID",
"ONLINE_VIDEO_BOUGHT",
"ONLINE_VIDEO_PLAY"
]),
videoInfo(itemId, bought, videoId) {
if (bought) {
this.activeLi = itemId;
}
this.ONLINE_VIDEO_BOUGHT(bought);
this.ONLINE_VIDEO_VIDEOID(videoId);
// this.ONLINE_VIDEO_PLAY(true);
// this.$emit("videoInfo",{bought, videoId} );
}
},
watch: {},
components: {}
};
</script>
<style scoped>
/* .activeLi {
background: #26a2ff;
} */
/* 课程目录 */
.multi-menu {
font-size: 0.3rem;
}
.class-title-wrap {
border-bottom: 1px solid #ddd;
line-height: 1rem;
height: 1rem;
display: flex;
justify-content: space-between;
}
.class-item-wrap {
border-bottom: 1px solid #ddd;
overflow: hidden;
line-height: 1rem;
height: 1rem;
display: -webkit-box;
/*! autoprefixer: off */
-webkit-box-orient: vertical;
/* autoprefixer: on */
-webkit-line-clamp: 1;
overflow: hidden;
white-space: pre-line;
font-size: 0.24rem;
}
</style>

行内切换 class 名

        <i :class="[toggleItemList?'iconfont icon-xiangshang':'iconfont icon-xiangxia']"></i>

        <li
v-else
:key="child.id"
:class="activeLi+index == child.id+index ? 'activeLi': ''"
@click="videoInfo(child.id,child.isPay,child.id)"
></li>

行内样式自动计算

        <div class="class-item-wrap" :style="{marginLeft: 0.3*(child.level-1)  +'rem'}"></div>

七牛云上传图片

                <input
type="file"
id="avatarUpload"
ref="imgInput"
accept="image/*"
@change="PreviewImage"
>

  可以不用七牛云的插件,但要手动创建一个 formData,并且设置请求头

    PreviewImage(event) {
let file = event.target.files[0];
let formData = new FormData();
formData.append("file", file);
formData.append("token", this.qiniutoke);
this.$http({
url: "https://up-z2.qiniup.com",
method: "POST",
headers: { "Content-Type": "multipart/form-data" },
data: formData
})
// _UploadQiniu({
// file:file,
// token:this.qiniutoke
// })
.then(res => {
console.log(res);
this.currentUser.handUrl = res.data.url + res.data.key;
console.log(this.currentUser.handUrl);
})
.catch(err => {
console.log(err);
});
}

vue 移动端项目总结(mint-ui)的更多相关文章

  1. 从零开始搭建vue移动端项目到上线的步骤

    初始化项目 1.在安装了node.js的前提下,使用以下命令 npm install --g vue-cli 2.在将要构建项目的目录下 vue init webpack myproject(项目目录 ...

  2. 从零开始搭建vue移动端项目到上线

    先来看一波效果图 初始化项目 1.在安装了node.js的前提下,使用以下命令 npm install --g vue-cli 2.在将要构建项目的目录下 vue init webpack mypro ...

  3. Vue移动端项目模板

    一个集成移动端开发插件的Vue移动端模板包含1.css: 使用stylus开发css 集成reset样式文件 修改UI组件文件 统一样式处理(如主题色等)2.UI组件 使用热门的vant与mint-u ...

  4. Vue移动端项目总结

    使用Vue项目写了一个移动端项目,然后又把项目硬生生的抽离了组件,一直忙着写RN项目没有时间总结心得,今天上午终于下定决心,写点总结. 1.position:absolute: 定位的时候不同手机的浏 ...

  5. vue 移动端项目切换页面,页面置顶

    之前项目是pc端是使用router的方式实现置顶的 //main.js router.afterEach((to, from, next) => { window.scrollTo(0, 0) ...

  6. vue PC端项目中解决userinfo问题

    在vue2 中用脚手架建立的项目,后端提供接口获取数据.在公司做第一个项目的时候不清楚公司里的对接流程,结果后续代码被一个接口整的乱七八糟,这个接口是获取用户信息的接口——'usre/info'. 如 ...

  7. 将Vue移动端项目打包成手机app---HBuilder

    将移动端页面打包成app 1.使用 HBuilder 直接编译打包 点击左上角 文件>打开目录>选择目录  选择用Webpack打包好的dist文件目录 由于我添加到项目了,所以会显示该项 ...

  8. vue移动端项目

    用vue mint-ui  jquery-weui写了一个移动端demo 技术栈 vue2.0 vue-router axios mint-ui jquery-weui webpack 页面截图 最后 ...

  9. vue移动端项目在手机上调试

    1.电脑和手机要连同一个wifi  一定是复制无线网的IP,而不是以太网的IP 2.在你的电脑上查找无线网络的ipv4地址: 查找方法:windows+r   然后再输入框里输入cmd 回车 会出现这 ...

随机推荐

  1. June. 27th 2018, Week 26th. Wednesday

    To be great, truly great, you have to be the kind of person who makes the others around you great. 要 ...

  2. Linux基本操作

    1. ctr + alt + t 打开新的终端窗口2. ctr + shift + + 终端窗口字体放大3. ctr + - 终端窗口字体缩小4. ls : 查看目录下的文件信息5. pwd: 查看目 ...

  3. C#中的out 参数,ref参数,值参数

    大家可能在编码中或多或少的使用过out的ref,但是是否注意过他两的详细用法以及区别? 本文想介绍下详细介绍下out参数,ref参数以及一般值参数. 值参数 在使用参数时,把一个值传递给函数使用的一个 ...

  4. 类String 初识

    String类概述 java.lang.String 类代表字符串.Java程序中所有的字符串文字(例如 "abc" )都可以被看作是实现此类的实例.类 String 中包括用于检 ...

  5. 石家庄地铁系统开发(java web版)(二)

    两种方法: 一,自己写数据库,自己写算法实现 二,调用已有软件的API(百度,高德)

  6. selenium webdriver 如何实现将浏览器滚动条移动到某个位置

    说明: 在做selenium webdriver  在做UI 自动化时,有些页面时使用懒加载的形式显示页面图片,如果在不向下移动滚动条时,获取到的图片会是网站的默认图片和真实的图片不相符. 所以研究了 ...

  7. [转帖]流程控制:for 循环

    流程控制:for 循环 http://wiki.jikexueyuan.com/project/linux-command/chap34.html need more study need more ...

  8. 2019-04-04 Mybatis学习知识点

    1. 比较#和$的区别 #是占位符?,$是字符串拼接.因此使用$的时候,如果参数是字符串类型,那么要使用引号 尽量使用#而不是$ 当参数表示表名或列名的时候,只能使用$ 2. 多参数时候 配置文件中使 ...

  9. Nginx访问配置

    配置HTTP协议(使用80默认端口,非HTTPS配置SSL)访问网站 包括RestAPI的配置和RestAPI文档的配置 例如: server { # 配置为HTTP协议 listen ; serve ...

  10. 配置spring的监听器 让spring随项目的启动而启动

    <!-- 配置spring的监听器 让spring随项目的启动而启动 --> <listener> <listener-class>org.springframew ...