查漏补缺
# 查漏补缺
# 声明式编程
模板的结构和最终显示的效果基本一致,如vue
# npm
# 麻烦
当一个网站依赖的代码越来越多,程序员发现这是一件很麻烦的事情:
- 去 jQuery 官网下载 jQuery
- 去 BootStrap 官网下载 BootStrap
- 去 Underscore 官网下载 Underscore
- 做完项目,打包时,终端npm i自动导入依赖
- --save 放在包前面后面都行,
package.json
会保存包的依赖项 - ……
有些程序员就受不鸟了,一个拥有三大美德 (opens new window)的程序员 Isaac Z. Schlueter (opens new window) (以下简称 Isaaz)给出一个解决方案:用一个工具把这些代码集中到一起来管理吧!
这个工具就是他用 JavaScript (运行在 Node.js 上)写的 npm,全称是 Node Package Manager
# 具体步骤
NPM 的思路大概是这样的:
买个服务器作为代码仓库(registry),在里面放所有需要被共享的代码
发邮件通知 jQuery、Bootstrap、Underscore 作者使用 npm publish 把代码提交到 registry 上,分别取名 jquery、bootstrap 和 underscore(注意大小写)
社区里的其他人如果想使用这些代码,就把 jquery、bootstrap 和 underscore 写到 package.json 里,然后运行 npm install ,npm 就会帮他们下载代码
下载完的代码出现在 node_modules 目录里,可以随意使用了。
这些可以被使用的代码被叫做「包」(package),这就是 NPM 名字的由来:Node Package(包) Manager(管理器)。
# babel
babel的核心概念就是利用一系列的plugin来管理编译案列,通过不同的plugin,他不仅可以编译es6的代码,还可以编译react JSX语法或者别的语法,甚至可以使用还在提案阶段的es7的一些特性,这就足以看出她的可扩展性。在以后的博客,会介绍他和webpack,react如何共同创建一个完美的开发环境。
# 跨域
网页协议,域名,端口 有一个不同就是跨域
cookie,session用来保持状态(不可跨域)
token用来维持状态(可跨域)
# spa
- 单页面富应用
- spa就是在前后端分离的基础上加了一层前端路由
- 就是前端来维护一套路由规则
# 前端路由
- 改变URL,但是页面不进行整体的刷新
# 本地存储
# 小程序获取经纬度
//Page Object
Page({
data: {
},
//options(Object)
onLoad: function(options) {
wx.getLocation({
type: 'wgs84',
altitude: false,
success: (result) => {
// 获取经纬度
console.log(result)
wx.openLocation({
latitude: result.latitude,
longitude: result.longitude,
scale: 18,
success: (result) => {
},
fail: () => {},
complete: () => {}
});
},
fail: () => {},
complete: () => {}
});
},
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# PC地图
# PC轮播图
- npm install vue-awesome-swiper@3 --save-dev
- vue-awesome-swiper轮播图 (opens new window)
# vue实现全屏滚动效果
左右弹出效果,结合全屏滚动效果使用
.active { left: 0 !important; right: 0 !important; top: 0 !important; bottom: 0 !important; opacity: 1 !important; filter: alpha(opacity=100); } .center1_list1 { padding-top: 40px; box-sizing: border-box; width: 80%; opacity: 0; filter: alpha(opacity=0); position: relative; left: -80%; transition: all 2s ease 100ms; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18.active1 { right: 0 !important; opacity: 1 !important; filter: alpha(opacity=100); } .center1_list2 { box-sizing: border-box; padding-left: 30px; height: 100%; display: flex; flex-direction: column; width: 80%; opacity: 0; filter: alpha(opacity=0); position: relative; right: -80%; transition: all 2s ease 100ms; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Vue计算属性
- computed计算属性和v-bind结合使用
- 控制按钮的使用时候
<el-button type="primary" size="mini" :disabled="isBtnDisabled">添加参数</el-button>
computed: {
isBtnDisabled() {
if (this.selectedCateKeys.length !== 3) {
return true
}
return false
},
},
2
3
4
5
6
7
8
# 将字符串变成数组显示
- 字符串为空返回空的数组
- JSON.parse()可以将字符串转化为JSON数据
- JSON.parse('[]')
res.data.forEach(item=>{
item.attr_vals = item.attr_vals?item.attr_vals.split(' '):[]
})
2
3
# 将数组变成字符串
- 调用join方法
- JSON.stringify(arr)
this.addForm.goods_cat.join(',')
# 小程序上传图片
<view class="img_wrap" wx:for="{{imgList}}">
<image src="{{item}}"></image>
</view>
<view wx:if="{{isShow}}" class="img" bindtap="handleImg">+</view>
2
3
4
5
.img_wrap{
width: 200rpx;
height: 200rpx;
position: relative;
margin:0 20rpx 20rpx 20rpx;
float: left;
border: 1rpx solid #ccc;
image{
width: 100%;
height: 100%;
}
}
.img{
margin: 20rpx;
width: 200rpx;
height: 200rpx;
display: flex;
justify-content: center;
align-items: center;
font-size: 36rpx;
border: 1rpx dashed #333;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// pages/demo/demo.js
Page({
/**
* 页面的初始数据
*/
data: {
isShow:true,
imgList:[],
num:0
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
handleImg(){
wx.chooseImage({
count: 9,
sizeType: ['original', 'compressed'],
sourceType: ['album', 'camera'],
success: (result) => {
console.log(result)
let tempFilePaths = result.tempFilePaths;
let imgList = this.data.imgList.concat(tempFilePaths);
if(imgList.length==9){
this.setData({
isShow:false
})
}
this.setData({
imgList,
num:imgList.length
})
}
});
},
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 验证码
<input v-model="num" type="text"/>
<!--关键 ↓-->
<div id="v_container" style="border:1px solid red;height:50px"></div>
</div>
<button @click="handleClick">确定</button>
2
3
4
5
import { GVerify } from '../js/GVerify.js'
export default {
data() {
return {
verifyCode:"",
num:''
}
},
mounted() {
this.verifyCode = new GVerify('v_container')
console.log(this.verifyCode)
},
methods: {
handleClick(){
var ver = this.verifyCode.validate(this.num)
console.log(ver)
}
},
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# PC端get请求
都要加params来请求参数
this.$http.get('goods',{params:this.queryInfo})
# 时间过滤器
一、转运行依赖moment
// 时间过滤器
import moment from 'moment'
Vue.filter('dataFormat', function(datastr, pattren="YYYY-MM-DD HH:mm:ss"){
return moment(datastr).format(pattren)
})
2
3
4
5
二、渲染数据名|过滤器名字
// 时间过滤器
Vue.filter('dataFormat',function(originVal){
const dt = new Date(originVal)
const y = dt.getFullYear()
const m = (dt.getMonth()+1+'').padStart(2,'0')
const d = (dt.getDate()+'').padStart(2,'0')
const hh = (dt.getHours()+'').padStart(2,'0')
const mm = (dt.getMinutes()+'').padStart(2,'0')
const ss = (dt.getSeconds()+'').padStart(2,'0')
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
})
2
3
4
5
6
7
8
9
10
11
调用
<template slot-scope="scope">
{{scope.row.add_time | dataFormat}}
</template>
2
3
三、自定义过滤器
<text>发表时间:{{item.add_time | formatDate}}</text>
exprot default{
filter:{
formatDate(date){
const nDate = new DAte(date)
const year = nDate.getFullYear()
const month = nDate.getMonth().toString().padStart(2,0)
const day = nDate.getDay().toString().padStart(2,0)
return year + '-' + month + '-' + day
}
}
}
2
3
4
5
6
7
8
9
10
11
# vue富文本编辑器
- 安装运行依赖vue-quill-editor
- 全局导入
// 导入富文本编辑器
import VueQuillEditor from 'vue-quill-editor'
// 导入富文本编辑器对应的样式
import 'quill/dist/quill.core.css' // import styles
import 'quill/dist/quill.snow.css' // for snow theme
import 'quill/dist/quill.bubble.css' // for bubble theme
// 将富文本编辑器,注册为全局可用的组件
Vue.use(VueQuillEditor)
2
3
4
5
6
7
8
- 使用,v-model与表单添加的数据双向绑定
<quill-editor v-model="addForm.goods_introduce"></quill-editor>
# 进度条
- 运行依赖中安装NProgress
- main.js中加入展示进度条NProgress.start();隐藏进度条 NProgress.done();
// 导入NProgress 包对应的JS和CSS
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
// 在request拦截器中,展示进度条NProgress.start();
axios.interceptors.request.use(config=>{
NProgress.start();
console.log(config)
config.headers.Authorization=window.sessionStorage.getItem('token');
return config
})
// 在response拦截器中,隐藏进度条 NProgress.done();
axios.interceptors.response.use(config=>{
NProgress.done();
return config
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 小程序背景图
.page_bg{
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: -1;
background-repeat:no-repeat; background-size:100% ;
min-height:100vh;padding-bottom:20rpx;
background: url(data:image/png;base64,..........) }
}
2
3
4
5
6
7
8
9
10
11
# IP&端口号
- IP地址用来定位计算机
- 172.27.157.44局域网的ip地址(访问别人的服务器)
- 127.0.0.1本机ip地址
- 端口号用来定位具体的应用程序
- 一切需要联网通信的软件都会占用一个端口号
- 端口号的范围从0-65536之间
- 计算机中有一些默认的端口号最好不要去使用,例如http服务的80
- 可以开启多个服务,但一定要确保不同服务占用的端口号不一致才可以
# 伪数组
var fakeArray = {
"0": "first",
"1": "second",
"2": "third",
length: 3
}
2
3
4
5
6
- 伪数组转化为真数组
[].slice().call(fakeArray)
# node解决跨域问题
app.all('*', function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');
res.header("X-Powered-By",' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
next();
});
2
3
4
5
6
7
8
9
# 正则表达式
("abca").replace(/a/g,'')
# 函数、方法和接口的区别
- 函数是语句序列的打包
- 方法是对 对象成员的操作,由函数实现
- 接口是对方法的抽象和概括,由方法实现具体的接口;
# SPA
- 单页面应用程序,整个网站只有一个页面,内容的变化通过Ajax局部更新实现,同时支持浏览器地址栏的前进和后退操作
- SPA原理:基于URL地址的hash(hash的变化会导致浏览器记录方位历史的变化、但是hash的变化不会触发新的URL请求)
- 在实现SPA过程中,最核心的技术就是前端路由
# 城市天气
城市天气和经纬度查询
<input type="text" v-model="city" />
<input type="submit" @click.prevent="searchWeather" value="提交" />
<h1>{{temp}}</h1>
<h1>{{text}}</h1>
methods: {
async searchWeather(){
console.log("查询天气")
console.log(this.city)
let city = await axios.get(`https://geoapi.qweather.com/v2/city/lookup?location=${this.city}&key=4e9c818e50cd4592b340d53fa94c4892`)
console.log(city)
let result = city.data.location[0].lon + ',' + city.data.location[0].lat
console.log(result)
let httpUrl = `https://devapi.qweather.com/v7/weather/now?location=${result}&key=4e9c818e50cd4592b340d53fa94c4892`
let res = await axios.get(httpUrl)
console.log(res)
this.temp = res.data.now.temp + '°'
this.text = res.data.now.text
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 合并两个对象
- 安装
lodash
插件 - 导入:
import _ from 'lodash'
- 合并两个对象
const result = _.merge(res.data,this.options)
# 关闭ESlint语法检查
vue.config.js
module.exports = {
lintOnSave:false // 关闭语法检查
}
2
3
# npm安装不了
- 删除本地node_modules 依赖包
- 执行 npm cache clean --force 清理缓存
- npm install
# 控制台文字乱码
package.josn
:"start":"chpc 6500 && electron-forge start"
# WIFI连不上
Windows+x ,按A,执行命令:netsh winsock reset
# HTTP状态码
101未登录
200成功
204预见请求
301永久重定向
302临时重定向
400客户端错误
401认证失败
403服务端接受到了请求,但是拒绝访问
404文件不存在
405请求方式错误
500服务器异常
503服务器繁忙中
# 请求方式
- get传输数据
- post向服务端发送数据
- OPTIONS检查服务器是否支持给请求
- put发送文件
- head
- delete
- trace
- connect
# 关闭浏览器清空缓存
window.onbeforeunload = function (e) {
window.localStorage.removeItem("userData");
};
2
3
# 优化项目
# 移除打包的打印
- 插件
babel-plugin-transform-remove-console
# 生产打包报告
命令vue-cli-service build --report
# 自定义打包优化
vue.config.js
:项目两个主入口文件,main-prod.js/main-dev.js
# externals加载外部CDN资源
vue.config.js
:本质去window全局查找引用所需要的资源
删除样式表:在index.js
中添加
# CDN优化element-ui
# 设置开发与发布的资源引入
vue.config.js
:当开发模式则使用import,发布则用CDN
index.html
中写代码包裹CDN
资源的文件
<% if(htmlWebpackPlugin.options.isProd){ %>
//CDN资源文件
<% } %>
2
3
# 路由懒加载
# 项目上线
- 通过node创建web服务器
- 开启gzip配置:减小文件体积,使传输速度更快,一定要把代码写在静态资源托管之前
- 配置https服务
- http协议传输的数据都是明文,不安全
- https协议对传输的数据进行了加密处理,可以防止数据被中间人窃取,使用更安全
- 使用pm2管理应用:脚本为app.js