Vue
1. webpack4 配置文件
const htmlWebpackPlugin = require('html-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
// 打包提取css
const ExtractTextPlugin = require("extract-text-webpack-plugin");
// 混淆解压代码
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
//提取公共模块,其的依赖
const webpack = require('webpack');
const path = require('path')
module.exports = {
optimization: {
minimizer: [new UglifyJsPlugin()],
},
entry: { //main是默认入口,也可以是多入口
main: './src/main.js',
},
//出口
output: {
// filename:'./build.js?v=1.1.1', //指定js文件
filename: 'js/[name].[chunkhash:8].js', //指定js文件名
path: path.join(__dirname, 'dist'), //最好是绝对路径(网站根目录) --打包文件夹名
publicPath: '/', // 企业中也可以是www.***.com/ 所有资源请求以/(网站根目录)开头
},
module: {
//一样的功能rules: webpack2.x之后新加的
rules: [ //require('./a.css||./a.js')
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.(png|jpg|gif|svg|ttf|woff|woff2)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
name: 'assets/[name].[ext]'
},
},
],
}, {//处理ES6的js
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.vue$/,
use: 'vue-loader',
exclude: /node_modules/
},
]
},
plugins: [
// 打包提取css 打包名字[] 唯一标识
new ExtractTextPlugin("css/[name].[hash:8].css"),
//插件的执行顺序是依次执行的
new htmlWebpackPlugin({
template: './src/index.html',
inject: true,
favicon: './favicon.ico'
}),
new VueLoaderPlugin()
//将src下的template属性描述的文件根据当前配置的output.path,将文件移动到该目录
],
// 提取公共组件及第三方包
optimization: {
//包清单
runtimeChunk: {
name: "manifest"
},
//拆分公共包
splitChunks: {
cacheGroups: {
//项目公共组件
common: {
chunks: "initial",
name: "common",
minChunks: 2,
maxInitialRequests: 5,
minSize: 0
},
//第三方组件
vendor: {
test: /node_modules/,
chunks: "initial",
name: "vendor",
priority: 10,
enforce: true
}
}
}
}
}
打包
- 提取css
- 安装
# 为3的WebPack
npm install --save-dev extract-text-webpack-plugin
# 为2的WebPack
npm install --save-dev extract-text-webpack-plugin@2.1.2
# 为1的WebPack
npm install --save-dev extract-text-webpack-plugin@1.0.1
- 使用
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
]
},
plugins: [
new ExtractTextPlugin("styles.css"),
]
}
- 提取公共代码及loader
- webpack.config.js与
module
plugins
同级
- webpack.config.js与
optimization: {
//包清单
runtimeChunk: {
name: "manifest"
},
//拆分公共包
splitChunks: {
cacheGroups: {
//项目公共组件
common: {
chunks: "initial",
name: "common",
minChunks: 2,
maxInitialRequests: 5,
minSize: 0
},
//第三方组件
vendor: {
test: /node_modules/,
chunks: "initial",
name: "vendor",
priority: 10,
enforce: true
}
}
}
}
- 压缩
- 安装
npm i -D uglifyjs-webpack-plugin
- 使用
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
与webpack.config.js与module
plugins
同级
optimization: {
minimizer: [new UglifyJsPlugin()],
},
2.ES6
2.1. ES6 中的模块
模块引用
//在commonjs引入cal对象
// var cal = require('./cal.js');
//es6的模块引入
import cal from './cal.js';
模块导出
// ----------------> cal.js <--------------
//在commonjs导出
// module.exports = cal;
// ES6导出
var cal = 1
export default cal;
// ----------------> cal.js <--------------
var temp1 = '我是默认导出的结果';
export default temp1;
// 导入方式是 import xxx from './cal.js'
//声明式导出
export var obj1 = '我是声明式导出1';
export var obj2 = '我是声明式导出2';
export var obj3 = '我是声明式导出3';
// 导入方式是
// import {obj1,obj2} from './cal.js';
//另一种方式声明导出
var obj4 = '我是声明式导出4'
export {obj4};
// 导入方式是
// import {obj1,obj2,obj4} from './cal.js';
- 默认
- 导入
import [,..xxx] [,..from] './xxx.ext'
- 导出
export default obj;
- 导入
- 声明式
- 1导出
export var obj = xxx;
- 2导出
export var obj2 = {};
- 3单独导出
export {stu};
- 导入多个
import {obj,obj2,stu} from './xxx.js'; 直接使用obj
- 全体导入
import * as newName from '/.cal.js'
- import 和export一定写在顶级,不要包含在{}内 !!!!!!
- 1导出
npm i babel-loader@7.1.1 babel-preset-es2015@6.24.1 babel-core@6.25.0 babel-plugin-transform-runtime@6.23.0 -D
webpack-dev-server@2.6.1
html-webpack-plugin@2.30.1
npm i webpack@3.4.1 -D
2.2.ES6 中的代码变化
- 对象属性的声明
var name = 'abc';
var person = {name}; 简写 相当于--> var person = {name:name};
声明函数
var cal = {
add:function(){
return 1;
},
add2(){
return 2;
},
add3:funtion(n1,n2){
return n1 + n2;
},
add4(n1,n2){ 干掉了function
return n1 + n2;
}
}
- 当属性的key和变量的名相同,而要使用变量的值做value,
- 就可以简写{name}->{name:name}
- es6中的函数声明
- 就是干掉了:function add(){ }
2.3.ES6 函数
// render:function(c){
// return c;
// }
render: c => c(App)
//1:当参数是一个的时候,小括号可以省略
//2:当代码只有一行且是返回值的时候,可以省略大括号及renter
3.webpack-dev-server
安装
//如果安装报错:invalid "instanceof" keyword value Promise
//需安装以下版本 兼容 webpack@3.4.1
npm i webpack-dev-server@2.9.4 -D
简单使用 不配置的情况下
// ----------------> package.js <--------------
"scripts": {
"dev": "webpack-dev-server --open --port 3000 --contentBase src" //开发者模式
}
//文件路径方式
"scripts": {
"dev": "..\\node_modules\\.bin\\webpack-dev-server --open --port 3000 --contentBase src" //开发者模式
}
配置
// ----------------> webpack.config.js <--------------
module.exports = {
entry:{ //main是默认入口,也可以是多入口
main:'./src/main.js'
},
//出口
output:{
filename:'./build.js', //指定js文件
path: path.join(__dirname,'dist') //最好是绝对路径
//代表当前目录的上一级的dist
},
devServer:{
contentBase:false,
//我这里没有设置contentBase,个人研究contentBase必须指向存在的bundle.js文件所在目录,
//因为这里是开发模式,所以dist目录并不存在,所以用false.
host:'localhost',
port:'8888',
inline:true,//webpack官方推荐
watchOptions: {
aggregateTimeout: 2000,//浏览器延迟多少秒更新
poll: 1000//每秒检查一次变动
},
compress:true,//一切服务都启用gzip 压缩
historyApiFallback:true,//找不到页面默认跳index.html
hot:true,//启动热更新,必须搭配new webpack.HotModuleReplacementPlugin()插件
open:true,
}
}
使用
// ----------------> package.js <----------------------
"scripts": {
"start": "webpack-dev-server --open" //开发者模式
}
4.vue单文件方式
- 单文件就是以*.vue结尾的文件。最终通过webpack也会编译成*.js在浏览器运行
- 内容: + +
- 1:template中只能有一个根节点 2.x
- 2:script中 按照 export default {配置} 来写
- 3:style中 可以设置scoped属性,让其只在template中生效
4.1.以单文件的方式启动
-
webpack找人来理解你的单文件代码
安装
vue-loader,vue-template-compiler,代码中依赖vue,
npm i vue@2.6.10 -S npm i vue-loader@13.0.4 vue-template-compiler@2.6.10 -D
5.vue中常用的v-指令演示
- 常用指令
- v-text 是元素的innerText只能在双标签中使用
- v-html 是元素的innerHTML,不能包含
- v-if 元素是否移除或者插入
- v-show 元素是否显示或隐藏
- v-model 双向数据绑定,v-bind是单向数据绑定(内存js改变影响页面)
6.class结合v-bind使用
<div v-bind:class="isRed?'red':'green'">单个class</div>
<div :class="{'red':true,'big':true}">多个class</div>
// 复杂情况,通过遍历,根据当前对象的成绩,匹配成绩和样式的清单对象,用成绩做key,取对象的value,最终返回字符串做样式名
<ul> //如果stu.score 为 A 就使用red class
<li v-for="stu in stus" :class="{'A':'red','B':'green'}[stu.score]">
{{stu.name}}
</li>
</ul>
7.methods和v-on的使用
- 绑定事件的方法
v-on:事件名="表达式||函数名"
- 简写:
@事件名="表达式||函数名"
- 函数名如果没有参数,可以省略() 只给一个函数名称
- 声明组件内函数,在export default这个对象的根属性加上methods属性,其是一个对象
- key 是函数名 值是函数体
- 在export default这个对象的根属性加上data属性,其是一个函数,返回一个对象
- 对象的属性是我们初始化的变量的名称
- 凡是在template中使用变量或者函数,不需要加this
- 在script中使用就需要加上this
export default {
data() {
return {
Yes:true,
users:[{name:'小红',age:19},{name:'小明',age:18}]
}
},
methods:{
change(){
this.Yes = !this.Yes;
this.users.push({
name:'小红',age:18
})
}
}
}
8.v-for
<template>
<div>
<ul>
<!-- 操作对象 -->
<!-- <li v-for="(value,key,index) in abc" :key="index">
value:{{ value }}
index:{{index}}
key:{{ key }}
</li> -->
<!-- 操作数组 -->
<li v-for="(use,index) in users" :key="index">
value:{{ use }}
index:{{index}}
</li>
</ul>
</div>
</template>
9.父子组件 (在组件内使用组件)
<template>
<div>
<HeaderVue></HeaderVue>
<BodyVue></BodyVue>
<FooterVue></FooterVue>
</div>
</template>
<script>
import HeaderVue from './components/header.vue';
import BodyVue from './components/body.vue';
import FooterVue from './components/footer.vue';
export default {
data() {
return {
}
},
methods:{
},
components:{
HeaderVue,
BodyVue,
FooterVue
}
}
</script>
10.全局组件
- 全局组件,使用更为方便,不需要声明,直接用
- 在main.js中引入一次,在main.js中使用
vue.component('组件名',组件对象);
- 所有的组件就可以直接通过组件名,使用
<!-- app.vue -->
//1:引入 vue
import Vue from 'vue';
import App from './app.vue';
//引入子组件对象
import headerVue from './components/header.vue';
import bodyVue from './components/body.vue';
import footerVue from './components/footer.vue';
//声明全局组件
Vue.component('headerVue', headerVue); //注册一个组件,第一个参数是名称,在template中使用,第二个参数是实际的对象,显示成什么内容,具备什么功能
Vue.component('bodyVue', bodyVue);
Vue.component('footerVue', footerVue);
new Vue({
el: '.app',
// render:function(c){
// return c;
// }
render: c => c(App)
//1:当参数是一个的时候,小括号可以省略
//2:当代码只有一行且是返回值的时候,可以省略大括号
})
11.父组件向子组件传值
父传
- 常量: textOne=“常量值”
- 变量: :testTow=“变量名”
<!-- app.vue -->
<template>
<div>
<HeaderVue textOne='哈哈父组件的值'></HeaderVue>
<BodyVue :testTow='testTow'></BodyVue>
<FooterVue></FooterVue>
</div>
</template>
子接受
<!-- header.vue -->
<template>
<div>头{{ textOne }}{{ testTow }}</div>
</template>
<script>
export default {
data() {
return {}
},
methods:{
},
props:['textOne','testTow'] // <--------------------
}
</script>
12.子组件向父组件传值
-
src 下新建一个连接器(电话) connector.js
-
o n 与 on与 on与emit 父接 o n 子 发 on 子发 on子发emit
-
在connector.js中new 一个 vue
-
import Vue from 'vue'; var connector = new Vue(); export default connector;
-
-
在父子组件中分别引入connector.js
-
<script> import connector from './connector.js' // <-------------------- export default { data() { return { text:"呔!妖怪!项目给你搭建好了", } }, } </script>
-
-
父组件中打开”电话“ 随时接受子组件的数据 (要想打开才能接受)
-
<script> import connector from './connector.js' export default { data() { return { text:"呔!妖怪!项目给你搭建好了", } }, mounted () { var me = this; connector.$on('masg',function (msg) { // <----------------- console.log(msg) }) } } </script>
-
-
子组件发送数据 (最好通过元素点击事件来完成发送,想发送的时候再去触发相应事件)
-
<script> import connector from './connector.js' export default { data() { return { text:"呔!妖怪!项目给你搭建好了", } }, mounted () { setTimeout(function() { connector.$emit('masg', me.msg) // <-------------------- // console.log("yimaio") }, 500); } } </script>
-
-
13.过滤器
-
content | 过滤器,vue中没有提供相关的内置过滤器,可以自定义过滤器
-
组件内的过滤器 + 全局过滤器
- 组件内过滤器就是options中的一个filters的属性(一个对象)
- 多个key就是不同过滤器名,多个value就是与key对应的过滤方式函数体
Vue.filter(名,fn)
- 组件内过滤器就是options中的一个filters的属性(一个对象)
-
输入的内容帮我做一个反转
export default { data() { return { title: '哈哈' } }, filters:{ filterNOe:function (value) { //转数组 反转数组 转字符串 return value.split('').reverse().join('') } } }
-
总结
- 全局 :范围大,如果出现同名时,权利小
- 组件内: 如果出现同名时,权利大,范围小
14.获取DOM元素 组件对象
- 救命稻草, 前端框架就是为了减少DOM操作,但是特定情况下,也给你留了后门
- 获取单个元素
- 在指定的元素上,添加ref=“名称A”
- 在获取的地方加入 this.$refs.名称A
- 获取元素组 比如 ul 下的所有li
- 在指定的父级元素上,添加ref=“名称A”
- 在获取的地方加入 this.$refs.名称A.children;
- ==================================================
- 如果ref放在了原生DOM元素上,获取的数据就是原生DOM对象
- 可以直接操作
- 如果ref放在了组件对象上,获取的就是组件对象
- 1:获取到DOM对象,通过this. r e f s . s u b . refs.sub. refs.sub.el,进行操作
- 对应的事件 (钩子函数)!! ! !! !! !! !!! !!! !!! !!! !! !!! !! !! !!! !!!
- created 完成了数据的初始化,此时还未生成DOM,无法操作DOM
- mounted 将数据已经装载到了DOM之上,可以操作DOM
- computed 用来监控自己定义的变量,当变量值发生改变的时候触发里面的函数
- 该变量不在data里面声明,直接在computed里面定义,然后就可以在页面上进行双向数据绑定展示出结果或者用作其他处理;
export default {
data() {
return {
}
},
filters:{
},
components:{
Header
},
mounted () {
console.log(this.$refs.refOne)
}
}
computed示例:
computed:{
payment(){
console.log("改了执行了")
let num = 0; //数量
let sum = 0; //总金额
this.newList.forEach((ele) => {
if (ele.isTrue) {
num += ele.sum
sum += ele.sum * ele.sell_price
}
})
return {
num,sum
}
}
}
//接收
payment.num
payment.sum
15.mint-ui
- 组件库
- 饿了么出品,element-ui 在PC端使用的
- 移动端版本 mint-ui
- https://mint-ui.github.io/#!/zh-cn
//Mint:引入mint-ui
import Mint from 'mint-ui';
//Mint:引入css
import 'mint-ui/lib/style.css';
//Mint:安装插件
Vue.use(Mint);
hellomui
http://www.dcloud.io/hellomui/
- 注意:
- 如果是全部安装的方式
- 1:在template中可以直接使用组件标签
- 2:在script中必须要声明,也就是引入组件对象(按需加载)
- 如果是全部安装的方式
16.vue-router
-
核心:锚点值改变
-
以后看到vue开头,就知道必须Vue.use
-
vue的核心插件:
- vue-router 路由
- vuex 管理全局共享数据
-
使用方式
-
1:下载
npm i vue-router -S
-
2:在main.js中引入
import VueRouter from 'vue-router';
-
3:安装插件
Vue.use(VueRouter);
-
4:创建路由对象并配置路由规则
-
5:将其路由对象传递给Vue的实例,options中
-
options中加入
router:router
import Home from './components/Home.vue' let router = new VueRouter({ routes:[ {name:'name'path:'/home',component:Home} ] }); new Vue({ el: '#app', render: creater => creater(App), router })
-
-
6:在app.vue中留坑
<router-view></router-view>
-
17.命名路由
- 需求,通过a标签点击,做页面数据的跳转
- 使用router-link标签
- 1:去哪里
<router-link to="/beijing">去北京</router-link>
- 2:去哪里
<router-link :to="{name:'bj'}">去北京</router-link>
- 更利于维护,如果修改了path,只修改路由配置中的path,该a标签会根据修改后的值生成href属性
- 1:去哪里
18.参数router-link
- 在vue-router中,有两大对象被挂载到了实例this
- r o u t e ( 只 读 、 具 备 信 息 的 对 象 ) 、 route(只读、具备信息的对象)、 route(只读、具备信息的对象)、router(具备功能函数)
- 查询字符串
- 1:去哪里
<router-link :to="{name:'detail',query:{id:index} } ">xxx</router-link>
- 2:导航(查询字符串path不用改)
{ name:'detail' , path:'/detail',组件}
- 3:去了干嘛,获取路由参数(要注意是query还是params和对应id名)
this.$route.query.id
- 1:去哪里
- path方式
- 1:去哪里
<router-link :to="{name:'detail',params:{id:1} } ">xxx</router-link>
- 2:导航(path方式需要在路由规则上加上/:xxx)
{ name:'detail' , path:'/detail/:id',组件}
- 3:去了干嘛,获取路由参数(要注意是query还是params和对应name名)
this.$route.params.id
- 1:去哪里
20.编程导航
- 不能保证用户一定会点击某些按钮
- 并且当前操作,除了路由跳转以外,还有一些别的附加操作
- this.$router.go(1) 根据浏览器记录 前进1 后退-1
- this.$router.push(直接跳转到某个页面显示)
- push参数: 字符串 /xxx
- 对象 :
{name:'xxx',query:{id:1},params:{name:2} }
21.重定向和404
- 进入后,默认就是/
- 重定向
{ path:'/' ,redirect:'/home' }
- 重定向
{ path:'/' ,redirect:{name:'home'} }
- 404 : 在路由规则的最后的一个规则
- 写一个很强大的匹配
{ path:'*' , component:notFoundVue}
22.多视图
- 以前可以一次放一个坑对应一个路由和显示一个组件
- 一次行为 = 一个坑 + 一个路由 + 一个组件
- 一次行为 = 多个坑 + 一个路由 + 多个组件
- components 多视图 是一个对象 对象内多个key和value
- key对应视图的name属性
- value 就是要显示的组件对象
- 多个视图
<router-view></router-view>
-> name就是default <router-view name='xxx'></router-view>
-> name就是xxx
23.嵌套路由
- 用单页去实现多页应用,复杂的嵌套路由
- 开发中一般会需要使用
- 视图包含视图
- 路由父子级关系路由
期组件内包含着第一层router-view
{ name:'music' ,path:'/music', component:Music ,
children:[ 子路由的path /就是绝对路径 不/就是相对父级路径
{name:'music.oumei' ,path:'oumei', component:Oumei },
{name:'music.guochan' ,path:'guochan', component:Guochan }
]
}
vue-resource(了解)
- 可以安装插件,早期vue团队开发的插件
- 停止维护了,作者推荐使用axios
- options预检请求,是当浏览器发现跨域 + application/json的请求,就会自动发起
- 并且发起的时候携带了一个content-type的头
24.axios
-
https://segmentfault.com/a/1190000008470355?utm_source=tuicool&utm_medium=referral
-
post请求的时候,如果数据是字符串 默认头就是键值对,否则是对象就是application/json
-
this.$axios.get(url,options)
-
this.$axios.post(url,data,options)
-
options:{ params:{id:1}//查询字符串, headers:{ ‘content-type’:‘xxxxx’ },baseURL:’’ }
-
全局默认设置 :Axios.defaults.baseURL = ‘xxxxx’;
-
针对当前这一次请求的相关设置
//main.js import Axios from 'axios'; //给Vue原型挂载一个属性 Vue.prototype.$axios = Axios; //默认配置 Axios.defaults.baseURL = 'http://182.254.146.100:8899/api/';
//app.vue export default { data() { return { } }, created(){ function a(res1,res2){ console.log(res1) console.log(res2) } //合并请求 this.$axios.all([ this.$axios.post('https://api.douban.com/v2/movie/in_theaters', 'name=xiaoming&age=18' ), this.$axios.get('https://api.douban.com/v2/movie/top250') ]) .then(this.$axios.spread(a)) .catch(err => { console.log(err); }) //单get请求 this.$axios.get('http://127.0.0.1:2000/json') .then(res => { console.log(res) console.log(123) }) .catch(err => { console.log(err) }) } }
关于axios post请求 参数错误问题
- 方法一
var params = new URLSearchParams();
params.append('data',JSON.stringify(data));
this.$axios.post('upData',params,
{header:{'Content-Type': 'application/x-www-form-urlencoded'}})
.then(res => {
})
.catch(err => {
console.log(err);
})
- 方法二 原文章地址
25.拦截器 (实现加载中。。效果)
- 过滤,在每一次请求与响应中、添油加醋
- main.js 中配置:
- axios.interceptors.request.use(fn) 在请求之前
import { Indicator } from 'mint-ui';
//在请求之前
Axios.interceptors.request.use(function (config) {
Indicator.open({
text: '加载中...',
spinnerType: 'fading-circle'
});
return config //必须return 出去
})
- axios.interceptors.response.use(fn) 在请求结束后
//在请求结束后
Axios.interceptors.response.use(function (config) {
Indicator.close();
return config //必须return 出去
})
- function(config){ config.headers = { xxx }} config 相当于options对象
- 默认设置 defaults 范围广、权利小
- 单个请求的设置options get(url,options) 范围小、权利中
- 拦截器 范围广、权利大
26.数据监听 watch
-
单个数据监听
export default{ data() { return { text3:0 } }, watch:{ text3:function () { // text3值发生改变的时候触发 console.log('改变了') } }, methods:{ change(){ this.text3+=1 } } }
- 深度监听 (单数据为对象或其他的时候)
<script> export default { data() { return { text1:0, text2:0, obj:[ {name:'哈哈'} ] } }, match:{ obj:{ handler: function (value,oldValu){ console.log('obj改变了') }, deep: true } } } </script>
- 监听多个
- computed可以监视多个this相关属性值的改变,如果和原值一样
- 不会触发函数的调用,并且可以返回对象
<template> <div> <input type="text" value="" v-model="text1">* <input type="text" value="" v-model="text2">= {{ sum }} <br/> </div> </template> <script> export default { data() { return { text1:0, text2:0 } }, computed:{ sum(){ return this.text1*this.text2 } } } </script>
25.时间格式化moment
安装:
bower install moment --S
使用:
//引用
import moment from 'moment'
//传入值
var value = '2019-04-24T16:30:08.417'
moment(value).format('YYYY-MM-DD') //2019-04-24
js 实现时间格式化
var time = 1000; //单位秒
var formatTime = function (time) {
/*00:00:00*/
var h = Math.floor(time/3600);
var m = Math.floor(time%3600/60);
var s = Math.floor(time%60);
return (h<10?'0'+h:h)+':'+(m<10?'0'+m:m)+':'+(s<10?'0'+s:s)
}
26.图片缩略图(vue-preview)
https://github.com/LS1231/vue-preview
27.vue-cli 不能引用css 问题
{
test: /\.css$/,
include: [
/src/,//表示在src目录下的css需要编译
'/node_modules/bootstrap/' //增加此项
],
loader: 'style-loader!css-loader!autoprefixer-loader'
}
28.上拉获取更多 loadmore
https://mint-ui.github.io/docs/#/zh-cn/loadmore
<div class="main-body" ref="wrapper" :style="{ height: (wrapperHeight-50) + 'px' }">
<mt-loadmore :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" :auto-fill="isAutoFill" ref="loadmore">
<ul>
<li v-for="item in list">{{ item }}</li>
</ul>
</mt-loadmore>
</div>
//父盒子main-body css必须加 overflow-y: scroll; !!!!!!!!!!!!!!!!
export default {
data() {
return {
allLoaded:false, //是否禁止触发上拉函数 取消上拉就改为true
isAutoFill:false,//是否自动触发上拉函数
lists: [],
wrapperHeight:0
}
},
mounted() {
// 父控件要加上高度,否则会出现上拉不动的情况
this.wrapperHeight =
document.documentElement.clientHeight -
this.$refs.wrapper.getBoundingClientRect().top;
},
methods: {
loadBottom() {
console.log("上拉触发啦");
//通知上拉操作已经完结
// console.log(this.$refs.loadmore.onBottomLoaded());
this.$refs.loadmore.onBottomLoaded();
}
},
}
29.vue 追加数据
this.lists = this.lists.concat(response.data.data)
//concat 追加
30.formidable提交文件
安装:
npm i formidable -S
*引用
const formidable = require('formidable')
同步提交基本使用
<!-- 同步上传文件必须写上 enctype="multipart/form-data" -->
<form enctype="multipart/form-data" action="/upload" method="post">
<input type="file" name="file" id="file">
<input type="submit" name="" value="提交">
</form>
app.post('/upload',function (request,responst, ) {
var form = new formidable.IncomingForm();
//为了能更好的保存文件在本地服务器目录 保存路径
form.uploadDir = path.join(__dirname,'files');
//解析请求
form.parse(request, function(err, fields, files) {
if(err) next(err);
console.log('上传文件完毕')
});
responst.send("hello")
})
异步提交:
<form>
<input type="file" name="" id="file">
<input type="submit" name="" value="提交">
</form>
document.querySelector('form').onsubmit = function(e){
e.preventDefault(); //取消默认事件
//错误代码的出现会导致return false不执行,不太好调试程序
var formData = new FormData();
//第一个参数key和表单中的name的值是一个意思
//第二个参数是文件的数据对象
formData.append('myFile',document.getElementById('file').files[0])
var xhr = new XMLHttpRequest();
xhr.open('post','/upload');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
alert('成功');
}
}
xhr.send(formData);
// return false;
}
jquery 使用 formidable
$('form').on('submit',function(e){
var formData = new FormData();
formData.append('myFile',document.getElementById('file').files[0]);
e.preventDefault();
//jq默认头是content-type: www-url..... 键值对
$.ajax({ // Illegal invocation
url:'/upload',
type:'post',
data:formData, //当传递formData的时候,就会默认将该对象转换成键值对字符串,不合理的
//jq上传文件必须要以下两个属性
contentType:false,//不需要头
processData:false,//不转换数据
success:function(){
console.log('ok')
}
})
})
31.关于this 指向
created() {
// Event.$on('sum_subtract',function (sum_subtract) {
// console.log(sum_subtract)
//这里的 this.sum_subtract 指向的不是Vue data 中的 sum_subtract
// this.sum_subtract += sum_subtract
// console.log(this.sum_subtract)
// })
//需要通过箭头函数来使用
//箭头函数当前找不到匹配的this就会去上一级找相匹配的this
Event.$on('sum_subtract',sum_subtract => {
this.sum_subtract = this.sum_subtract + sum_subtract
console.log(this.sum_subtract)
})
}
32.Vue 过渡
过渡JavaScript 钩子
可以在属性中声明 JavaScript 钩子
<transition
v-on:before-enter="beforeEnter" //过渡进入之前
v-on:enter="enter" //过渡进入
v-on:after-enter="afterEnter" //过渡进入之后
v-on:enter-cancelled="enterCancelled" //过渡取消
v-on:before-leave="beforeLeave" //过渡离开之前
v-on:leave="leave" //过渡离开
v-on:after-leave="afterLeave" //过渡离开之后
v-on:leave-cancelled="leaveCancelled" //过渡离开取消
>
<!-- ... -->
</transition>
<transition name="show">
<router-view></router-view>
</transition>
.show-eneter-active,
.show-leave-active{
/* 过渡开始到过渡结束 */
transition: opacity .5s;
}
.show-enter,.show-leave-to{
/* 过渡开始状态与过渡结束后状态 */
opacity: 0;
}
过渡模式
同时生效的进入和离开的过渡不能满足所有要求,所以 Vue 提供了 过渡模式
in-out
:新元素先进行过渡,完成之后当前元素过渡离开。out-in
:当前元素先进行过渡,完成之后新元素过渡进入。
用 out-in
重写之前的开关按钮过渡:
<transition name="fade" mode="out-in">
<!-- ... the buttons ... -->
</transition>
33.购物车数量本地存储 window.localStorage
let prodTools = {};
let store = window.localStorage;
// let prods = {没有数据就应该是空对象}; //未来从localStorage中获取
let prods = JSON.parse(store.getItem('prods')||'{}');
//{ id:num }
//增加或追加
prodTools.addOrUpdate = function(p){
//判断是否存在
if(prods[p.id]){//追加
prods[p.id] += p.num;
}else{
prods[p.id] = p.num;
}
//保存
this.saveProds(prods);
}
//删除
prodTools.delete = function(id){
//es5 相当于 prods.id
delete prods[id];
//保存
this.saveProds(prods);
}
//获取到storage
prodTools.getProds = function(){
return JSON.parse(store.getItem('prods')||'{}');
}
//获取总数
prodTools.getTotalCount = function(){
let sum = 0;
for(let id in prods){
sum += prods[id];
}
return sum;
}
//存储
prodTools.saveProds = function(prods){
//第一个参数是key 第二个是 value
store.setItem('prods',JSON.stringify(prods));
}
export default prodTools;
34.导航钩子
beforeRouteEnter (to, from, next) {
在请求之前
在渲染该组件的对应路由被 confirm 前调用
不!能!获取组件实例 `this`
因为当钩子执行前,组件实例还没被创建
},
beforeRouteEnter (to, from, next) {
console.log(from.name)
let titlee =''
if (from.name == "goodsDetail") {
titlee = "图文详情"
}else if (from.name == "newsList"){
titlee = "新闻详情"
}
console.log(4545)
next(vm => {
vm.titlee = titlee
})
}
beforeRouteUpdate (to, from, next) {
在当前路由改变,但是该组件被复用时调用
举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
导航离开该组件的对应路由时调用
可以访问组件实例 `this`
}
35.Vue 给对象添加属性 this.$set
//在vue中添加属性,是没有办法做到响应,setter
// ele.num = 123;
// ele.isPicked = true;
//添加属性一定要this.$set
//三个参数 对象 属性名 值
this.$set(ele,'num',123);
this.$set(ele,'isPicked',true);
36.vue-cli 打包
1.将 config/index.js 中的build:{}中的 assetsPublicPath: ‘/’,改为 assetsPublicPath: ‘./’,
build: {
// Template for index.html
index: path.resolve(__dirname, '../dist/index.html'),
// Paths
assetsRoot: path.resolve(__dirname, '../dist'),
assetsSubDirectory: 'static',
assetsPublicPath: './', //改这里!!!!!
36 vue sessionStorage 存储
//存储并转成json字符串
sessionStorage.setItem('user',JSON.stringify(this.responseText));
//获取
sessionStorage.getItem('user');
//指定删除
sessionStorage.removeItem('user');
//清空所有
sessionStorage.clear();
2.执行命令:
npm run build
3.安装http-server 后 运行http-server 可本地服务器访问
*常用技巧
1.打包后ttf字体图标路径问题
更改 build/utils.js 文件中 ExtractTextPlugin 插件的options 配置:
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
publicPath: '../../', // 注意配置这一部分,根据目录结构自由调整
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
2.如果在config -> index.js 中的 build 代码中的 productionSourceMap的值设为false ,打包后文件体积可以减少百分之八十
3.如果设置build文件夹下的webpack.prod.conf.js中HtmlWebpackPlugin插件配置参数添加hash: true,即会使打包生成的index.html中的js和css路径带有?+随机字符串,也就是版本控制
37.路由懒加载
const Foo = resolve => require(['./Foo.vue'],resolve) //列子
import Home from '@/components/home' //默认
//懒加载
const Home = resolve =>require(['@/components/home'],resolve)
38.vue不能全屏解决方法
- 给vue 中 template 中的第一个元素添加 (前提body,html的高度是全屏的)
height: 100%;
position: absolute;
top: 0px;
left: 0px;
width: 100%;
39 vue项目中关闭eslint
- 在项目根目录新建文件
vue.config.js
- 其内容为
module.exports = {
lintOnSave:false
}
40 webstorm 关闭 elsint 检测
点击File 下的 settings 如图 (如果以新建了上面 39 方法的vue.config.js 的话 是找不到 ESLint 这一选项的 须删除vue.config.js 文件 或 注销其内容)
41 vue 操作data
设置
获取
42 vue(在uni-app中)使用多个v-for循环的时候报错
错误显示为重复的key值
解决方法:不一定要拿循环出的index值来当key的值可以用循环的对象id或其它属性来代替index
监视锚点值的改变 (hashchange事件)
window.addEventListener(‘hashchange’, function() {
var text = ‘’;
switch (location.hash) {
case ‘#/music’:
text = ‘各种音乐的数据’;
break;
case ‘#/movie’:
text = ‘各种电影的数据’;
break;
}
查看文档的对象分类
- 1:全局的代表Vue.的
- 2:实例的代表this.或者new Vue().
- 3:选项代表 new Vue() 的参数
- 或者 export default里边的属性
来了 api 要用趁早哦
用到的api
- get 请求获取所有品牌列表的 api
http://kerys.pythonanywhere.com/api/getprodlist/
调用方式: GET 请求直接调用
- post 请求添加品牌的 api
http://kerys.pythonanywhere.com/api/addprod/
调用方式:POST 请求 需要的参数 {name: '品牌名称'} , {emulateJSON:true} 普通表单请求
- get 请求删除品牌的 api
http://kerys.pythonanywhere.com/api/delprod/id
调用方式: GET 请求 id 是品牌的id int类型