文章目录
一、vue是什么
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
二、MVVM
- View层:视图层,负责展示信息。
- Model层:数据层,为视图层提供数据便于展示。
- ViewModel层:视图层和数据层的中间层,负责让视图和数据实现绑定,以及在视图层中进行DOM事件监听,可以监听后改变数据层的数据。
三、生命周期
生命周期:vue从创建到销毁所经历的事情。
- beforeCreate():实例被创建出来之前执行。data 和 methods 中的 数据都还没有没初始化
- create():data 和 methods 都已经被初始化好了
- beforeMount():模板已经在内存中编辑完成了,尚未被渲染到页面中
- mounted():内存中的模板已经渲染到页面,用户已经可以看见内容
- beforeUpdate():内存中的数据已更新,但是页面尚未被渲染
- updated():内存中的数据已更新,并且页面已经被渲染
四、基础标签
4.1v-once
数据第一次显示后,之后不会被修改。
4.2v-html
会把返回的字符串数据以HTML语法的方式解析。
4.3v-text
文本的方式解析数据,通常情况下接受string类型。一般不用。mustache语法更常用
4.4v-pre
让vue的效果展示失效。如果用mustache语法,则会直接显示代码的内容。
4.5v-cloak
在vue解析之前,div中有一个属性v-cloak
在vue解析之后,div中没有一个属性v-cloak
4.6v-bind
动态绑定属性,缩写:
v-bind绑定class
v-bind绑定style
4.7v-on
事件监听,缩写@
.stop:可以阻止冒泡
.prevent:可以阻止默认事件
.native:监听组件的事件
.once:第一次点击后有反应
4.8v-if、v-else
if和else语句的判断
4.9v-show
和v-if非常类似
区别
v-if:当条件为false时,会把包含v-if的元素从dom中移除。而当v-show条件为false时,它会给元素增加一个行内样式:display:none。
如何选择
当显示与隐藏间切换频繁时,用v-show,因为它不是真的在dom中移除元素,效率更高。当只显示一次时,用v-if。
4.10v-for
遍历对象时,顺序是value,key,index
推荐添加组件key的属性,在更新时更加高效。
可以理解为插入操作,添加了组件key就是链表的方式o(1)时间复杂度,没有添加就是数组从中插入,o(m-n)的时间复杂度。
4.11v-model
双向绑定
原理实现
用v-bind可以实现单向绑定,当数据改变后,页面也会改变,但是修改页面的元素,数据不会改变,此时只需要在页面给组件添加对应的事件监听,传入修改的值赋值给数据。就可以实现双向绑定了。
v-model:radio
v-model:checkbox
选择一个时,data中的属性为字符。选择多个时,data中的属性为数组
v-model的修饰符
-
lazy:延迟加载,在input中点击回车后才会同步更新
-
number:把输入框的内容转成数字类型,默认会转为字符串
-
trim:去除输入内容左右两边的空格
五、常用语法
5.1mustache
就是双括号{{}},里面的值可以进行简单的算术运算。如果是字符串,+则会拼接;如果是数字,+会相加。
5.2计算属性computed
把结果进行封装,显示时用双括号不用加方法的括号。
计算属性一般不会用到它的set方法,我们都用get方法,所以写法上可以省略。
computed对比methods
- computed返回的值在双括号内编码时,不用加括号
- computed会引入缓存,多次调用只会执行一次
5.3过滤器filter
对参数进行过滤
过滤器定义
filters: {
showPrice(price) {
return '¥' + price.toFixed(2)
}
}
过滤器使用
//{{参数|过滤器}}
<h2>总价格: {{totalPrice | showPrice}}</h2>
5.4Vue对象中的template
使用Vue对象中对方template,加载的组件会在index.html中把div的id=app的部分给替换,这里的App是引用的一个组件
Main.js
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>',
})
index.html
!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>vuecli2test</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
5.5render函数
初始化vue cli脚手架时,可以选择Runtime-Compiler和Runtime-only
使用Runtime-only不会解析template的内容,在脚手架中需要通过package.json中引入vue-template-compiler依赖可以解决。
使用Runtime-only的方式运行效率更高。
使用Runtime-Compiler的生命周期:
template -> ast -> render -> vdom -> UI
使用Runtime-only的生命周期:
render -> vdom -> UI
六、 ES6和JavaScript语法
6.1const
将某个变量声明为常量。
const使用时注意修饰的标识符必须赋值,而且使用后不能修改。
建议:在es6开发中,优先使用const,只有在改变某个标识符的时候才使用let。
6.2块级作用域var和let
- var是全局的,会有污染的问题,推荐少用。
- let是局部的,推荐用。
- let是es6引入的。在es5之前,没有块级作用域,通过借助于function的作用域来实现块级作用域,因为方法都是独立开辟的。
6.3对象增强
6.4filter函数
进行过滤
const nums = [10, 20, 111, 222, 444, 40, 50]
用filter函数得到小于100的值
其中return的值为boolean,如果为true,则会加入newNums中,如果为false则不会加入。
// 10, 20, 40, 50
let newNums = nums.filter(function (n) {
return n < 100
})
6.5map函数
进行映射
const newNums = [10, 20, 40, 50]
用map把数组中的每个值*2
// 20, 40, 80, 100
let new2Nums = newNums.map(function (n) {
return n * 2
})
6.6reduce函数
const new2Nums = [20, 40, 80, 100]
用reduce对数组中所有的内容进行汇总
其中有两个参数,第一个是函数(函数第一个参数为上一次调用的返回值,第二个参数为当前值),第二个为第一次调用的默认值。
//240
let total = new2Nums.reduce(function (preValue, n) {
return preValue + n
}, 0)
6.7链式编程
上面例子的汇总
let total = nums.filter(function (n) {
return n < 100
}).map(function (n) {
return n * 2
}).reduce(function (prevValue, n) {
return prevValue + n
}, 0)
精简版(采用Lambda表达式)
let total = nums.filter(n => n < 100).map(n => n * 2).reduce((pre, n) => pre + n,0);
6.8Promise
使用背景:用于异步编程
- 当使用resolve时,会调用then方法里面的内容
- 当使用reject时,会调用error方法里面的内容
- resolve和reject是互斥的
new Promise((resolve,reject)=>{
setTimeout(() => {
//异步的内容xxx
resolve('Success zyp')
reject('Error zyp')
}, 1000)
}).then(data=>{ //成功时执行
console.log(data);
}).error((data)=>{
console.log(data); //失败时执行
})
七、组件化开发
7.1使用组件化的目的
-
可以把页面拆分,单独管理,提高了扩展性。
-
组件拆分后可以进行复用,减少了代码冗余。
7.2注册组件化的步骤
- 创建组件
- 注册组件
- 使用组件
7.3全局组件和局部组件
区别:注册的时候不一样,全局组件注册:Vue.component(‘cpn’, cpnC)
而局部组件注册在Vue对象里面。
7.4注册组件时写法的简化
- Vue.extend可以直接用对象代替
- template的内容可以使用script标签和template标签
7.5父组件和子组件
- 组件之间通过components来进行注册关联
- 父组件和子组件默认数据是隔离的
- 组件内的数据data只能通过函数返回的方式
父组件获取子组件数据的方式:
$refs、$children
子组件获取父组件数据的方式:
$parent
父组件传数据到子组件,通过props的方式
其中props的属性的类型检查
type:类型
required:是否必须
default:默认值
子组件传数据到父组件,通过$emit()事件的方式
7.6插槽slot
为什么要用slot
便于组件可以更加个性化的复用
slot的使用
作用域插槽
使用场景:在父组件中替换插槽的标签,数据由子组件提供
八、模块化开发
8.1导入导出
导入导出的作用
通过导入导出,可以更加模块化的方式来进行开发。
CommonJS的方式
导出
导入
ES6的方式
用export和export default的区别:
export default在一个模块中,只能使用一个
export default在导入时,不用加{},可以自定义名字
导出
// 1.导出方式一:
export {
flag, sum
}
// 2.导出方式二:
export var num1 = 1000;
export var height = 1.88
// 3.导出函数/类
export function mul(num1, num2) {
return num1 * num2
}
//4.用export default的方式
export default function (argument) {
console.log(argument);
}
导入
import {sum} from './zyp.js'
//如果采用export default的方式,导入时不用{},可以重命名
import add from "./zyp.js";
九、 webpack
9.1webpack是什么
项目的打包工具
9.2node、npm、webpack之间的关系
- webpack使用时底层需要node.js的环境支持
- npm是node.js的一个工具,下载node.js时自动集成了。目的是可以用npm命令去帮助安装很多node的依赖
- 我们写的很多语法,浏览器不能直接解析,需要通过webpack打包加工,给浏览器解析。
9.3webpack的全局安装和局部安装
全局:npm install webpack@版本号 -g
局部:npm install webpack@版本号 --save-dev
9.4webpack引入各种load
为什么要引入load
因为webpack本身转化功能有限,需要借助load去更好的打包转换。
项目配置流程
当我们执行npm i 或者npm install命令时,是node的命令,它会找package.json的文件
其中devDependencies代表着开发时会下载的依赖,我们执行npm install xxx --save-dev时会产生,比如各种打包的依赖,但是一般都只会使用一次,等正式上线后就不需要用到了。所以还有dependencies这个运行时会下载的依赖,我们执行npm install xxx --save时会产。下面的代表就代表着当我们npm i或npm install时会执行各种npm babelxxx和npm install webpack,版本也指定了。
其中的main:index.js代表着这个项目的运行入口为main.js。
scripts下的命令,是我们用命令行执行npm run时使用的,比如这里我们在命令行webpack可以用npm run build来代替,同时它会在局部webpack的作用域打包。
执行npm run dev,会打开vue服务,并且会自动打开页面(配了–open)
{
"name": "meetwebpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"dev": "webpack-dev-server --open"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-preset-es2015": "^6.24.1",
"css-loader": "^2.0.2",
"file-loader": "^3.0.1",
"html-webpack-plugin": "^3.2.0",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"style-loader": "^0.23.1",
"uglifyjs-webpack-plugin": "^1.1.1",
"url-loader": "^1.1.2",
"vue-loader": "^13.0.0",
"vue-template-compiler": "^2.5.21",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.3"
},
"dependencies": {
"vue": "^2.5.21"
}
}
当执行webpack命令或npm run build后,会去找webpack.confg.js文件
rules下第一个配置的是解析css 的load
rules下第二个配置的是解析less的load
rules下第三个配置的是解析图片的load
rules下第四个配置的是ES6语法转化成ES5的load
rules下第五个配置的是Vue
devServer配置的是一个webpack服务
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
// publicPath: 'dist/'
},
module: {
rules: [
{
test: /\.css$/,
// css-loader只负责将css文件进行加载
// style-loader负责将样式添加到DOM中
// 使用多个loader时, 是从右向左
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.less$/,
use: [{
loader: "style-loader", // creates style nodes from JS strings
}, {
loader: "css-loader" // translates CSS into CommonJS
}, {
loader: "less-loader", // compiles Less to CSS
}]
},
{
test: /\.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
// 当加载的图片, 小于limit时, 会将图片编译成base64字符串形式.
// 当加载的图片, 大于limit时, 需要使用file-loader模块进行加载.
limit: 13000,
name: 'img/[name].[hash:8].[ext]'
},
}
]
},
{
test: /\.js$/,
// exclude: 排除
// include: 包含
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
},
{
test: /\.vue$/,
use: ['vue-loader']
}
]
},
resolve: {
// alias: 别名
extensions: ['.js', '.css', '.vue'],
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
plugins: [
new webpack.BannerPlugin('最终版权归aaa所有'),
new HtmlWebpackPlugin({
template: 'index.html'
}),
new UglifyjsWebpackPlugin()
],
devServer: {
contentBase: './dist',
inline: true
}
}
十、路由router
10.1路由的创建
路由的目的
负责实现页面之间的跳转
两种模式
history模式和hash模式
history模式的url间隔是/,可以在路由创建时配置
hash模式的url间隔是#
history的pushState()和replaceState()
pushState()采用堆的方式,浏览器可以回退。
replaceState()采用替换的方式,浏览器不可以回退。
路由的创建
- 导入路由对象,调用Vue.use(VueRouter)
- 配置路由映射
- 在Vue实例中挂载Vue
Vue.use(VueRouter)代表使用插件VueRouter,会调用VueRouter的install方法前提是已经下载好了插件,可以用npm install 插件名或在package.json的dependencies中配置好后执行npm install命令
component: ()=>import(’…/components/Home’)//代表采用懒加载的方式
mode: ‘history’,//配置history模式
children是嵌套路由的部分
router.beforeEach((to,from,next)=>{}//全局导航守卫,类似spring中的全局AOP
keep-alive //保证了匹配到的视图组件会被缓存
路由配置文件
import VueRouter from 'vue-router'
import Vue from 'vue'
//通过Vue.use(插件), 安装插件
Vue.use(VueRouter)
const router = new VueRouter({
// 配置路由和组件之间的应用关系
routes,
mode: 'history',//配置history模式
// linkActiveClass: 'active'
})
// 创建VueRouter对象
const routes = [
{
path: '',
// redirect重定向
redirect: '/home'
},
{
path: '/home',
component: ()=>import('../components/Home'),//代表采用懒加载的方式
meta:{
title:"首页"
},
children:[
{
path:"first",
component: ()=>import('../components/HomeFirst')
},
{
path:"second",
component: ()=>import('../components/HomeSecond')
},
]
},
{
path: '/about',
meta:{
title:"关于"
},
component: ()=>import('../components/About')
},
{
path:"/zyp",
meta:{
title:"zyp"
},
component: ()=>import('../components/Zyp')
},
{
path:'/user/:id',
meta:{
title:"用户"
},
component:()=>import('../components/User')
}
]
//导航守卫的使用
router.beforeEach((to,from,next)=>{
document.title=to.meta.title
console.log(to)
next()
})
// 将router对象传入到Vue实例
export default router
main.js(Vue实例挂载路由)
import Vue from 'vue'
import App from './App'
import router from './router'
new Vue({
el: '#app',
router,//挂载路由
render: h => h(App)
})
10.2路由的使用
当我们使用Vue.use(VueRouter)时,Vue内部会调用VueRouter的install方法,这个install方法会去调用install.js配置
这个install.js会让所有的组件都拥有router和route属性,并且vue声明了组件RouterView和RouterLink
使用如下标签完成页面的路由使用
页面使用代码
<template>
<div id="app">
<!-- <h2>我是APP组件</h2> -->
<router-link to="/home" tag="button" replace active-class="active">首页</router-link>
<router-link to="/about" tag="button" >关于</router-link>
<!-- <router-link :to="{
path:'/Zyp',
query:{
name:'zzz',
age:'18'
}
}" tag="button" >zyp</router-link> -->
<button @click="zypClick">Zyp</button>
<router-link v-bind:to="'/User/'+id">我的</router-link>
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
</template>
<script>
export default {
name: 'App',
data(){
return {
id:"111"
}
},
methods: {
zypClick(){
// this.$router.push('/zyp')
// this.$router.replace('/zyp')
this.$router.push({
path:"/zyp",
query:{
name:'pp',
age:'20'
}
})
}
}
}
</script>
10.3路由跳转的两种方式
主要采用router-link跳转的方式和代码的方式
router-link跳转的方式
代码的方式
采用push方式后可以返回,replace方式后不能回退,采用query的方式可以在浏览器的url获得参数
<template>
<div id="app">
<button @click="zypClick">Zyp</button>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
zypClick(){
// this.$router.push('/zyp')
// this.$router.replace('/zyp')
this.$router.push({
path:"/zyp",
query:{
name:'pp',
age:'20'
}
})
}
}
}
</script>
10.4route和router的区别
- 使用$route为当前router跳转对象里面可以获取name、path、query、params等值
- 使用$router为VueRouter实例,可以跳转到不同的页面,如使用$router.push方法
10.5动态路由,参数传递
主要通过params方式和query方式
params方式
query方式
使用
获得传递的参数
十一、Vuex
11.1Vuex简介
- 是专门为vue.js应用开发的一个状态管理模式
- 采用了单例模式、观察者模式的思想
- 需要下载对应的插件再使用
11.2 Vuex状态管理
11.3Vuex的核心概念
State
Getters
Mutation
Action
Module
- state中存储了Vue的所有组件可以使用的数据,全局单例的。
- Getters类似computed属性,对State中的数据加工后返回。
- 使用Mutation可以修改State中的值,官方也推荐这么做。
- 使用Action可以异步的修改State中的值。
- 可以在Store中分割多个Module,每个Module中又有以上的属性。
使用Mutation修改state
// 1.安装插件
Vue.use(Vuex)
// 2.创建对象
const state = {
counter: 1000,
}
const store = new Vuex.Store({
state,
})
// 3.导出store独享
export default store
mutations: {
// 无参
increment(state) {
state.counter++
},
//可带参数,字符串或对象类型
incrementCount(state, payload) {
// console.log(count);
state.counter += payload.count
},
}
}
组件中的使用
<template>
<div>
<h2>{{$store.state.counter}}</h2>
<button @click="addCount(5)">+5</button>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
message: '我是App组件'
}
},
methods: {
addition() {
this.$store.commit('increment')
},
addCount(count) {
// payload: 负载
// 1.普通的提交封装
this.$store.commit('incrementCount', count)
// 2.特殊的提交封装(传对象)
this.$store.commit({
type: 'incrementCount',
count
})
},
}
</script>
采用Getter方式修改State
getters: {
powerCounter(state) {
return state.counter * state.counter
},
more20stu(state) {
return state.students.filter(s => s.age > 20)
}
}
使用
<template>
<div id="app">
getters方式
<h2>{{$store.getters.powerCounter}}</h2>
<h2>{{$store.getters.more20stu}}</h2>
</div>
</template>
Actions方式异步修改state
mutations: {
updateInfo(state) {
state.info.name = 'zyp'
}
},
actions: {
aUpdateInfo(context, payload) {
return new Promise((resolve, reject) => {
setTimeout(() => {
context.commit('updateInfo');//处理完dispatch后commit
console.log(payload);
resolve('1111111')
}, 1000)
})
}
},
使用
<template>
<div id="app">
<button @click="asyncUpdateName">异步方式</button>
</div>
</template>
<script>
export default {
name: 'App',
methods: {
asyncUpdateName() {
this.$store.dispatch('aUpdateName')
} }
}
</script>
十二、Axios
12.1使用axios目的
前后端分离开发时使用axios发送请求获取数据
12.2常见配置
- 请求地址:url:’/zyp’
- 请求类型:method:‘post’
- 请求根路径::baseURL:‘http:127.0.0.1/abc’
- 请求前的处理::transformRequest[function(data){}]
- 请求后的处理:transformResponse[function(data){}]
- 自定义请求头:headers:{‘x-Requested-With’:‘XMLHttpRequest’}
- URL查询对象:params:{id:1}
- 请求体:data:{key:‘1’}
- 超时设置:timeout:‘1000’
- 身份验证信息:auth:{name:‘zs’,pwd:‘zyp’}
- 响应的数据格式json/blob/document/arraybuffer/text/stream:responseType:‘json’
12.3使用axios
简单使用
axios({
url: 'http://127.0.0.1:8000/zyp'
}).then(res => {
this.result = res;
})
get方式
axios({
url: 'http://127.0.0.1:8000/zyp',
// 专门针对get请求的参数拼接
params: {
type: 'abc',
page: 1
}
}).then(res => {
console.log(res);
})
并发方式
axios.all([axios({
url: 'http://127.0.0.1:8000/zyp1'
}), axios({
url: 'http://127.0.0.1:8000/zyp2',
params: {
type: 'sell',
page: 5
}
})]).then(results => {
console.log(results);
console.log(results[0]);
console.log(results[1]);
})
12.3拦截器
使用场景
- 拦截不符合服务器要求的数据
- 每次请求时,都希望在界面中显示一个请求的图标
- 某些请求需要向后端传入一些信息,如token
常在脚手架中封装的request.js
import axios from 'axios'
export function request(config) {
// 1.创建axios的实例
const instance = axios.create({
//全局配置
baseURL: 'http://127.0.0.1:8000/zyp',
timeout: 5000
})
// 2.axios的拦截器
// 2.1.请求拦截的作用
instance.interceptors.request.use(config => {
// console.log(config);
// 1.比如config中的一些信息不符合服务器的要求
// 2.比如每次发送网络请求时, 都希望在界面中显示一个请求的图标
// 3.某些网络请求(比如登录(token)), 必须携带一些特殊的信息
return config
}, err => {
// console.log(err);
})
// 2.2.响应拦截
instance.interceptors.response.use(res => {
// console.log(res);
return res.data
}, err => {
console.log(err);
})
// 3.发送真正的网络请求
return instance(config)
}
使用
import {request} from "./request";
request({
url: '/zyp'
}).then(res => {
//请求成功的处理
console.log(res);
}).catch(err => {
//请求失败的处理
console.log(err);
})