Table of Contents
下面回顾一下练习项目——爱家——过程中碰到的问题。因为是回顾,所以可能不尽全面。不过,尽力了,能写多少是多少。
一、轮播图兼容问题
因为 ie9 不支持transform,所以引入了jQuery,使用jQuery的animate实现无限轮播。
<template>
<div id="banner"
@mouseenter = "stop"
@mouseleave = "start"
>
<div class="pic">
<ul>
<li
v-for="(img,index) in imgArray"
:key = "index"
class = "fl"
>
<a>
<img :src="img" alt="" class="bgc">
</a>
</li>
</ul>
</div>
<div class="dot">
<span
v-for="index in dotArray"
:key = "index"
@click = "slide(index)"
:class="{active:index === curIndex}"
></span>
</div>
<div class="left" @click="slide('l')"><</div>
<div class="right" @click="slide('r')">></div>
</div>
</template>
<script>
import $ from "jquery";
export default {
props: {
banner: {
type: Object,
required: true
}
},
data(){
return {
imgArray: [
this.banner['2'].src,
this.banner['0'].src,
this.banner['1'].src,
this.banner['2'].src,
this.banner['0'].src
],
dotArray: [
1,
2,
3
],
curIndex: 1
}
},
methods: {
slide:function(index){
var $pic = $('.pic').first();
var self = this;
if($pic.is(":animated")){
return
}
index = 'l' === index ? this.curIndex - 1 : index;
index = 'r' === index ? this.curIndex + 1 : index;
this.curIndex = index;
var left = this.curIndex;
if(this.curIndex >= this.imgArray.length - 1){
this.curIndex = 1;
}
if(this.curIndex <= 0){
this.curIndex = this.imgArray.length - 2;
}
$pic.animate({
'margin-left': 0 - 1200 * left + 'px'
},1000,function(){
if(index >= self.imgArray.length - 1){
$pic.css({
'margin-left': '-1200px'
})
};
if(index <= 0){
$pic.css({
'margin-left': '-3600px'
})
}
});
},
start: function(){
var self = this;
// console.log(self);
self.interval = setInterval(function(){
// console.log(self);
self.curIndex++;
// if(self.curIndex === self.imgArray.length){
// self.curIndex = 0;
// }
self.slide(self.curIndex);
},2000)
},
stop: function(){
clearInterval(this.interval);
}
},
mounted: function(){
this.start();
}
}
</script>
<style scoped>
#banner {
position: relative;
width: 1200px;
height: 430px;
overflow: hidden;
margin: auto;
}
.pic {
overflow: hidden;
width: 6000px;
margin-left: -1200px;
}
.pic img {
width: 1200px;
height: 430px;
}
.dot {
text-align: center;
margin-top: -50px;
}
.dot span {
width: 20px;
height: 20px;
border-radius: 50%;
margin: 0 10px;
display: inline-block;
background-color: #fff;
border: 2px solid #fff;
cursor: pointer;
}
.dot span.active {
background-color: #333;
border: 2px solid linen;
}
.left, .right {
position: absolute;
top:50%;
margin-top: -50px;
height: 100px;
width: 30px;
line-height: 100px;
text-align: center;
background-color: #333;
color: #fff;
cursor: pointer;
}
.right {
right: 0px;
}
</style>
二、依据条件渲染链接
图片等都是使用vue的for循环渲染的。在实际展示的时候有一个需求:如果内容存在,则链接有效。否则使用默认内容,链接无效。
<a
:href="'#' === a_case.id ? 'javascript:;' : './?c_id=' + a_case.id"
:target="'#' !== a_case.id ? '_blank' : ''"
><img
:src="a_case.cover"
:alt="a_case.title" class="cover"
></a><br />
<a
:href="'#' === a_case.id ? 'javascript:;' : './?c_id=' + a_case.id"
:target="'#' !== a_case.id ? '_blank' : ''"
><span
v-html="a_case.title"
class="ellipse ilb"
></span></a>
#是在id不存在的时候约定的默认符号。如果id不存在,渲染时候的默认链接就是javasript:;。
默认链接不能是#。如果是锚点,页面会跳到头部,在target为_blank的时候还会在新页面打开。
默认链接不能是javascript:void(0);。主要是在 IE 下面会出现问题。(好像是打开新标签。)
三、设计师照片条件渲染
这个问题是由前期设计不足引起的。在之前设计的时候并没有考虑到缩略图的问题。比如设计师,上传的时候是大图片。但一般页面需要的是缩略图。大图太耗带宽了。所以,只能在后台增加了裁切的代码。但是已经注册并上传图片的设计师并没有对应的缩略图——除非再一次上传图片。为了在前端兼容这种情况,需要条件渲染。
<img :src="designer.thumb ? designer.thumb : designer.photo" :alt="designer.name" class="photo" />
如果缩略图存在,就使用缩略图,否则用原图。
四、年龄计算
出生年月和工作年月在数据库中是这样存储的:XXXX_XX。比如1980_6。但在展示的时候需要以这种格式展示:XX岁和XX年XX月。所以,就需要对原数据进行转换。
computed: {
age(){
return Math.floor(new Date().getFullYear() - this.user.birth.split('_')[0] + (new Date().getMonth() - this.user.birth.split('_')[1])/12) + '岁';
},
working(){
return Math.floor(new Date().getFullYear() - this.designer.working_years.split('_')[0] + ( new Date().getMonth() - this.designer.working_years.split('_')[1] ) /12 ) + '年' + (new Date().getMonth() - this.designer.working_years.split('_')[1] + 12)%12 + '月';
}
}
this.user.birth是出生年月, this.designer.working_years 是参加工作年月。
五、div 垂直居中问题
有一个需求,在一个盒子中显示联系方式。盒子宽高确定,联系方式条数不确定。
@white: white;
@pink: #edd9d9;
.contact-board {
width: 240px;
height: 200px;
line-height: 200px;
background: @white;
border: 5px solid @pink;
left: 50%;
top: 50%;
margin-left: -120px;
margin-top: -100px;
display: table;
> div:first-child {
display: table-cell;
vertical-align: middle;
}
p {
line-height: 35px;
}
这里用的less。外层盒子.contact-board的display属性为table。内层盒子> div:first-child的display属性为table-cell,vertical-align属性为middle。
六、scoped 穿透
通用组件确实很方便,但不同的页面布局有所不同,有必要对通用组件进行改造。
还是放参考链接吧。# Vue中的scoped及穿透方法
在练习中我采用了第二种方法:曲线救国。
七、vue-router 默认路由
const routes = [
{
path: '/',
redirect: '/login'
},
{
path: '/login',
component: login
},
{
path: '/register',
component: register
}
];
redirect后面可以是一个函数,根据需要返回不同的路由。
八、通过实例方法改变当前路由
还是先放链接:## vue router.push(),router.replace(),router.go()
this.$router.replace({path:'/setting'});
九、vue-router 传值方法
路由传值有params、query、props。
先放链接:Vue-router props 如何传递参数 ,传参请看这里
路由里面props的值确实可以传给子组件的props。
我的需求是,父组件向后台发出ajax请求,返回的一堆数据在分解后需要传给子组件。路由的props属性貌似无法取得父组件的数据。虽然可以在父组件中通过this.$route……这样的方式一层一层地找到需要数据的子组件,然后赋值,但这样并不是响应式的。后来,只能通过vuex解决问题。父组件将数据存入vuex。
this.$store.commit('store_origin_info',this.info);
子组件监听变化。
created(){
this.$store.watch(state => {
if(!state.origin_info){
return;
}
this.origin_info = this.$store.state.origin_info;
this.init_info();
});
}
一开始并不是用的监听的方式,而是在computed中返回。
computed: {
origin_info: function(){
return this.$store.state.origin_info;
}
},
但不知为什么,这种无法响应store中数据的变化。
十、添加图片并预览的一系列问题
这里的问题比较多,主要是 ie9 的兼容。
input不能连续选择同一张图片。- ie9 不支持
type=file,无法通过e.target.files获取文件信息。 - ie9 不支持
FileReader,无法通过此方法将图片读取为base64用于预览。
先放代码。
add(e,item,index){
e = e || event;
//如果值为空,返回。主要针对 createTextRange 触发的onchange
if(!e.target.value){
return;
}
let pics = [];
if(window.FileReader){
pics = e.target.files;
}else{ //低版本ie兼容
try{
e.target.select();
e.target.blur();
let path = document.selection.createRange().text;
let fso = new ActiveXObject("Scripting.FileSystemObject");
pics[0] = {};
pics[0].path = path;
pics[0].size = fso.GetFile(path).size;
pics[0].type = fso.GetFile(path).type;
}catch(e){
alert(e+"\n"+"如果错误为:Error:Automation 服务器不能创建对象;"+"\n"+"请按以下方法配置浏览器:"+"\n"+"请打开【Internet选项-安全-Internet-自定义级别-ActiveX控件和插件-对未标记为可安全执行脚本的ActiveX控件初始化并执行脚本(不安全)-点击启用-确定】");
}
}
let len = pics.length;
//这里的mark 为什么设置为 -2,而不是0.原因未知,总之下面的 mark++ 执行次数会比循环次数多 2。所以设置为 -2 .
let mark = -2;
if(!window.FileReader){ //ie9 不存在多执行两次的情况
mark = 0;
}
// console.log(e.target);
// console.log(pics);
let rule = {
size: 300 * 1024,
type: [
'jpeg',
'png',
'gif'
]
};
for(let key in pics){
this._CHECK_PIC(rule,pics[key])
.then( result => {
if(result.right){
console.log("359" + pics);
item.detail.push({
path: result.data,
description: ''
});
}
mark++;
console.log('len:'+len+' mark:'+mark);
if(len === mark){
e.target.value = '';
if(window.ActiveXObject){
e.target.createTextRange().execCommand('delete');
e.target.blur();
}
console.log(e.target.value);
this.check_content(index);
}
});
}
}
add()是input onchange事件的处理函数(方法)。参数分别是事件对象、要添加图片的数组和索引。_CHECK_PIC()是封装的图片检查方法。check_content()是整个内容区域的检查方法。
下面是封装的_CHECK_PIC()
Vue.prototype._CHECK_PIC = function(rules,pic){
//预设变量
let variable = rules;
let result = {
right: true,
data: null
};
return new Promise(function(resolve,reject){
//检查图片格式
if(rules.type){
let r = rules.type.some(val => {
if(window.FileReader){
return pic.type === 'image/' + val;
}else{ //低版本ie兼容
console.log(pic);
let type = pic.type.split(" ")[0].toLowerCase();
if('jpg' === type){
type = 'jpeg';
}
return val === type;
}
});
if(!r){
result.right = false;
resolve(result);
return;
}
}
//检查图片大小
if(rules.size){
if(pic.size > rules.size){
result.right = false;
resolve(result);
return;
}
}
//检查图片宽高
if(window.FileReader){
let reader = new FileReader();
//读取图片
reader.readAsDataURL(pic);
reader.onload = function(e){
let temp_pic = new Image();
temp_pic.src = e.target.result;
temp_pic.onload = function(){
// console.log(temp_pic.width);
// console.log(temp_pic.height);
// console.log(variable);
check_w_h(temp_pic,rules,result);
}
}
}else{ //低版本ie兼容
let temp_pic = new Image();
temp_pic.src = pic.path;
temp_pic.onload = function(){
// console.log("89" + this);
check_w_h(temp_pic,rules,result);
}
}
//检查宽高
function check_w_h(temp_pic,rules,result){
// console.log("98" + this);
//检查最小宽高
if(rules.min_width && rules.min_height){
if(temp_pic.width < rules.min_width || temp_pic.height < rules.min_height){
result.right = false;
resolve(result);
return;
}
}
//检查最大宽高
if(rules.max_width && rules.max_height){
if(temp_pic.width > rules.max_width || temp_pic.height > rules.max_height){
result.right = false;
resolve(result);
return;
}
}
//检查最小宽高比
if(rules.min_ratio){
if(temp_pic.width / temp_pic.height < rules.min_ratio * 0.9){
result.right = false;
resolve(result);
return;
}
}
//检查最大宽高比
if(rules.max_ratio){
if(temp_pic.width / temp_pic.height > rules.max_ratio * 1.1){
result.right = false;
resolve(result);
return;
}
}
//图片有效
result.data = temp_pic.src;
// console.log(result);
resolve(result);
}
});
}
input不能连续选择同一张图片可以通过清空input value值来解决。ie11 及非 ie 浏览器可以通过e.target.value=''实现。其余 ie 通过e.target.createTextRange().execCommand('delete'); e.target.blur();解决。但这样貌似会触发onchange事件,导致一次添加两张图的bug。所以,在前面要对input value进行判断。if(!e.target.value){return;}。
ie9 不支持type=file和FileReader可以通过ActiveXObject("Scripting.FileSyetemObject")和滤镜解决。下面放链接:
上传图片快速预览HTML5 FileReader + Window.URL+滤镜(兼容低版本IE)
不知为什么,好像不使用滤镜,直接将路径给图片的src属性也可以。
ie9 下将图片转为 base64 的问题尚未解决。
十一、axios post 请求后台接收不到数据
先放链接:
解决方法比较多,我这里是通过transformRequest解决的。
Vue.prototype._POST = function(post_data,func){
axios({
method: 'post',
url: './',
headers: {
'Content-type': 'application/x-www-form-urlencoded'
},
data: post_data,
transformRequest: [
function(data){
let newData = '';
for ( let i in data){
newData += encodeURIComponent(i) + '=' + encodeURIComponent(data[i]) + '&';
}
// console.log(newData);
return newData;
}
]
}).then(response => {
func(response);
});
}
十二、数据挂载
目前是将数据挂载在vuebody下面。或许可以考虑将数据挂载到meta标签下面,或者弄一个其他不需要的标签,省去读取数据后在将vuebody设为显示的步骤。
十三、webpack css 分离问题
之前写诗词网站demo的时候就尝试过将css分离出来,但失败了。这一次倒是成功了。原因嘛——之前配置写错了。
const webpack = require('webpack');
const VueLoadPlugin = require('vue-loader/lib/plugin');
const path = require('path');
const HTMLPlugin = require('html-webpack-plugin');
const miniCSS = require('mini-css-extract-plugin');
const isDev = process.env.NODE_ENV === 'development';
const config = {
mode: isDev ? 'development' : 'production',
target: 'web',
entry: {
home: './src/pages/home/home.js',
designer: './src/pages/designer/designer.js',
about: './src/pages/about/about.js',
detail: './src/pages/detail/detail.js',
login: './src/pages/login/login.js',
panel: './src/pages/panel/panel.js'
},
output: {
path: path.resolve(__dirname,'dist'),
filename: 'js/[name].js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.css$/,
use: [
miniCSS.loader,
'css-loader'
]
},
{
test: /\.less$/,
use: [
miniCSS.loader,
'css-loader',
'less-loader'
]
},
{
test: /iconfont\.(ttf|svg|eot|woff)$/,
use: [{
loader: 'file-loader',
options: {
name: 'font/[name].[ext]'
}
}]
},
{
test: /\.js$/,
use: {
loader: 'babel-loader'
},
exclude: path.resolve(__dirname,'node_modules/')
}
]
},
plugins: [
new VueLoadPlugin(),
new miniCSS({
filename: "css/[name].css",
allChunks: true
}),
new HTMLPlugin({
template: './src/pages/home/home.html',
filename: './home.html',
chunks: ['lib','home']
}),
new HTMLPlugin({
template: './src/pages/about/about.html',
filename: './about.html',
chunks: ['lib','about']
}),
new HTMLPlugin({
template: './src/pages/login/login.html',
filename: './login.html',
chunks: ['lib','login']
}),
new HTMLPlugin({
template: './src/pages/detail/detail.html',
filename: './detail.html',
chunks: ['lib','detail']
}),
new HTMLPlugin({
template: './src/pages/designer/designer.html',
filename: './designer.html',
chunks: ['lib','designer']
}),
new HTMLPlugin({
template: './src/pages/panel/panel.html',
filename: './panel.html',
chunks: ['lib','panel']
})
],
optimization: {
splitChunks: {
cacheGroups: {
lib: {
name: 'lib',
filename: 'js/[name].js',
minChunks: 2,
chunks: 'initial'
}
}
}
}
};
module.exports = config;
只要将module里面css和less部分的style-loader换成mini-css-extract-plugin的loader就可以了。当然,plugins里面也要配置一下就是了。(之前optimization里面也写了,并且style-loader没删掉。)
十四、php 部分
实际上这里也有很多东西可以写。但是,还是直接放源码链接好了。
https://github.com/tonyzhou1890/love-home/blob/master/src/index.php
总结
数据库部分也就不记录了。
1、总体来说,还很弱。
2、总体来说,还有很大进步空间。
文章最初发布在简书,时间为 2018.07.14 18:08。