vue2
Vue2
vue基础
什么是vue
构建用户界面的渐进式框架
渐进式框架的大概意思就是你可以只用我的一部分,而不是用了我这一点就必须用我的所有部分
MVVM
- model 数据
- view 页面
- ViewModel mvvm 模式的核心,它是连接 view 和 model 的桥梁
双向数据绑定
- 数据绑定:将后端传递的数据转化成所看到的页面
- DOM 事件监听: 将所看到的页面转化成后端的数据
基本使用
{{username.toUpperCase()}}
{{gender}}
{{age >= 18 ? '成年' : '未成年'}}
vue-指令
提升DOM的渲染效率 , 一套特殊的语法
内容渲染指令 {{}}
{{username}}
年龄:
性别:
属性绑定指令 v-bind
事件绑定指令 v-on
hello Word
hello Word
$event
修饰符
双向绑定指令 v-model
- 不操作dom的前提下 修改数据
- .trim 处理首尾空格
- .lazy 改变时更新
- .number 只能输入数字
条件渲染指令 v-if v-show
v-if和v-show
v-if使用
v-show<使用/p>
v-if-else
青年
中年
老年
列表渲染指令 v-for
v-for
- v-else-if 指令必须配合 v-if 指令一起使用,否则它将不会被识别!
- v-for="(item,index) in arr"
-
- item 每一项
- index 下标
- arr要循环的数组
- 索引:{{index}} id:{{item.id}} name:{{item.name}}
v-for简单操作
- 索引:{{index}} id:{{item.id}} name:{{item.name}}
过滤器
- 只在1 2版本 3版本剔除
{{username | ucfist}}
{{time | dataFormat('YYYY-MM-DD HH:mm:ss')}}
{{time | dataFormat('YYYY-MM-DD HH:mm:ss')}}
watch监听器
- 监听数据变化 从而针对数据的变化
判断用户名是否可用
侦听对象
let vm = new Vue({
el: '#app',
data: {
user: {
name: '张三',
age: 12,
sex: '男',
},
},
watch: {
//侦听的不是一个值 是属性
//不会触发选择器
//只有给this.user = 新值 才会触发侦听器
// user(xin) {
// console.log(xin.name);
// }
//解决方案1
// 'user.name'(newVal) {
// console.log(newVal);
// },
//解决方案2
user: {
//固定写法
handler(newVal) {
//监听对象所有 .
console.log(newVal.name);
},
//加入该项可以监听对象属性
deep: true ,
// 页面打开马上侦听
immediate: true
}
}
});
去掉温馨提示
// 去掉温馨提示
Vue.config.productionTip = false;
vm.$mount("#app"); //找元素app
计算属性
姓:
名:
您的姓名: {{xing + ming}}
您的姓名: {{ fullName }}
计算商品数量和总价
- 商品名:{{item.name}} 单价:{{item.price}} 数量"{{item.count}}
商品总数: {{ counts }}
商品总价: {{ total }}
单页面程序
网页只有一个HTML所有功能与交互都在一个界面完成
vue-cli
简化了webpack工程创建
# npm上的一个全局包
npm install -g @vue/cli
# 快速创建
vue create 项目名
vue组件化
把重用的ui组件化
- template
-
- 只能有一个根元素
- 其他元素只能是这个元素的子元素
- 不会被渲染成真正的dom元素
- script
-
- JavaScript
- 组件相关的data methods
- 写js 必须写 export default {}
- data须是函数 data(){}
- style
-
- 样式
- 支持less语法
体验
文档第一个vue项目
我的年龄: {{ age }}
修改vue配置
-
创建vue.config.js 文件
-
module.exports = { devServer: { //端口 port: 9000, //自动打开 open:true } }
注册组件
// 使用import 导入组件
import Left from './components/Left.vue'
// components 注册节点组件
components: {
Left: Left,
}
样式穿透
//加scoped 之后样式只对当前页面有影响
//css 父元素 >>> 子元素 {}
//less 设置语言 /deep/ 元素 {}
//需要安装 npm i less-loader@7.3.0 -D
//scss 设置语言 ::v-deep 元素 {}
//需要安装 npm i sass-loader@10 sass -D
全局变量
import Article from './components/Article.vue'
Vue.component('Article',Article)
组件的声明周期
生命周期
一个组件的 创建 运行 销毁 , 强调的是一个时间段
四大阶段,八大方法
- 初始化 beforeCreate created
- 挂载 beforeMount mounted
- 更新 beforeUpdate updated
- 销毁 beforeDestroy destroyed
new vue() 实例化对象
先初始化事件和生命周期函数
执行beforeCreate , 还没有初始化数据 此时不能访问data 和menthods
内部添加 data methods 的 数据
执行created 这里可以访问 data methods 可以获取数据
编译模板 : 是否有 el选项 有向下编译 没有停止生命周期
? 有el之后 判断是否有template
? 有 会将其变异成 render函数
? 没有 会将外部的html作为模板编译
执行beforeMount 此时 数据还没挂载到页面
执行 mounted 函数 此时实例挂载dom 可以获取真实dom $ref
组件数据更新时 调用 beforeUpdate 数据更新了 但页面没更新
执行updated 页面更新
组件销毁时 执行beforeDestroy 此时 实例完全可以用
执行destroyed 销毁完成
组件数据共享
父传子
父元素值改变 子元素值也改变
giao
name: {{ name }}
newName: {{ newName }}
obj: {{ obj.a }}
子传父
父元素接收的数据与子元素互不影响
重新发送 重新接收
{{name}}
{{obj.a}}
ref引用
在不依赖jQuery的情况下,操作dom元素
giao
更新数据 调用
giao
短路运算
// &&
true && false // false
false && true // false
true && true // true
动态类名
xxxxx
注册Vue的插件
//注册vue组件
let user = {name: 'giao',age:20}
// 对象格式注册
// Vue.use({
// vue.js插件应该暴露install方法
// install(Vue){
// //就是给Vue原型添加自定义属性
// Vue.prototype.lt = user;
// }
// });
//函数注册格式
Vue.use((Vue) => {
Vue.prototype.lt = user;
});
//调用
console.log(this.lt.name)
在项目中使用axios
//安装 npm i --save axios vue-axios
//导入
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios,axios);
//调用即可
this.axios({}).then(fn);
vue 使用 echarts
npm i echarts
导入echarts 需要点击按下导入 因为 echarts 太大了
import * as echarts from 'echarts/core'
import { GridComponent } from 'echarts/components'
import { LineChart } from 'echarts/charts'
import { UniversalTransition } from 'echarts/features'
import { CanvasRenderer } from 'echarts/renderers'
echarts.use([GridComponent, LineChart, CanvasRenderer, UniversalTransition])
//导出 echarts
export default {
install(Vue){
Vue.prototype.echarts = echarts;
}
}
//注册全局
import echarts_config from './utlis/echarts_config';
Vue.use(echarts_config);
this.echarts //调用
slot插槽
- 使用插槽 必须是父子组件
- v-slot 不可再标签使用 只能在template使用
- slot 有默认名字 default
具名插槽 有名字
默认插槽 名字默认default
作用域插槽
对应 具名插槽
对应 默认插槽
作用域slot{{obj.a}}
动态组件
- 当组件设置缓存时
- 会触发两个周期函数
-
- activated 激活时触发
- deactivated 当组件缓存 触发
giao
全局自定义指令
//全局自定义指令
// Vue.directive('指令名(不能v-)',{配置项});
Vue.directive('color',{
//函数名固定 第一次解析标签执行
//bind 的参数 el 指当前元素
//obj.value 就是指令传过来的值
bind(el,obj){
el.style.color = obj.vule
},
//更新组件的时候触发
update(el,obj){
el.style.color = obj.vule
},
});
//如果bind 和 update 一样可以简化代码
Vue.directive('color' ,(el,obj){
el.style.color = obj.vule
},)
//调用 gioa
data(){return{red:green}}
URL与Hash
- url地址: http://www.liulongbin.top:8083/images/cat.png?name=ls#abc
- # 后面的就是Hash地址
- Hash地址变化不会刷新浏览器
前端路由
- 访问不同的Hash 地址 会显示不同的组件
- SPA指单页面
- 不同组件切换都要依赖前端路由完成
路由工作原理
① 用户点击了页面上的路由链接
② 导致了 URL 地址栏中的 Hash 值发生了变化
③ 前端路由监听了到 Hash 地址的变化
④ 前端路由把当前 Hash 地址对应的组件渲染都浏览器中
简单实现路由
data() {
return {
comName: 'Home'
}
},
created() {
//注册window的onhashchange事件 当hash地址变化触发事件
window.onhashchange = () => {
console.log(location.hash); //获取hash地址
let hash = location.hash;
this.comName = (hash == '#/home' ) ? 'Home' :
(hash == '#/movie') ? 'Movie' :
(hash == '#/about') ? 'About' : '';
}
}
//html
首页
电影
关于
vue-router
安装路由 npm i vue-router@3.5.2
创建路由 在src 创建 router/index.js
//导入vue和router
import Vue from "vue";
import VueRouter from 'vue-router';
//调用 vue.use函数 把VueRouter 安装成vue插件
Vue.use(VueRouter)
//创建路由实例对象
const router = new VueRouter();
//共享路由实例
export default router
- 导入挂载路由 在main.js
import router from './router'
new Vue({
render: h => h(App),
//挂载 路由
router: router
}).$mount('#app')
- 声明路由 和 占位符
App 根组件
首页
电影
关于
- 声明匹配规则
import Home from '../components/Home.vue'
import Movie from '../components/Movie.vue'
import About from '../components/About.vue'
//调用 vue.use函数 把VueRouter 安装成vue插件
Vue.use(VueRouter)
//创建路由实例对象
const router = new VueRouter({
routes: [
// 在数组中匹配规则
{path: '/home',component: Home},
{path: '/movie',component: Movie},
{path: '/about',component: About}
]
});
重定向
//redirect 重定向
{path: '/' , redirect: '/home'},
嵌套路由
About 组件
tab1
tab2
- index.js
//index.js
import Tab1 from '../components/tabs/Tab1.vue'
import Tab2 from '../components/tabs/Tab2.vue'
//创建路由实例对象
const router = new VueRouter({
routes: [
{path: '/about',component: About, children: [
//{path:hash地址 , component: 组件}
//path值不能加斜杠
{path: 'tab1' , component: Tab1},
{path: 'tab2' , component: Tab2},
]},
]
});
动态路由
App2 组件
复联
长津湖
giao
Movie 组件
电影:{{$route.params.name}}
ID值:{{$route.params.id}}
- index.js
//创建路由实例对象
const router = new VueRouter({
routes: [
//接收数据
{path: '/movie/:id/:name',component: Movie}
]
});
使用 props 接收参数
Movie 组件
电影:{{name}}
ID值:{{id}}
- index.js
//创建路由实例对象
const router = new VueRouter({
routes: [
//props: true 表示接收动态的id和name
{path: '/movie/:id/:name',component: Movie,props:true}
]
});
vue-router 导航API
- this.$router.push('hash地址');
-
- 跳转地址并 增加一条历史记录
- this.$router.go('数值')
-
- 实现导航历史前进后退
- -1 后退 1前进
methods: {
back() {
this.$router.go(-1);
}
}
methods: {
tiao(){
this.$router.push('/about')
}
}
全局前置守卫
- 判断有没有token
- 在创建路由实例对象后
//全局前置守卫 发生跳转触发
router.beforeEach((to,from,next) => {
//to 即将跳转
//to.path 表示跳转的地址
//from 表示当前页
//next() 函数 是否放行
if(to.path == '/login'){
next()
}else{
//判断是否登录
if (localStorage.getItem('token')) {
next()
} else {
next('/login');
}
}
})
懒加载
//导入的组件 如果一下子全部加载影响性能 在这里临时加载
// import Login from '@/components/MyLogin.vue'
//实例VueRouter对象
const router = new VueRouter({
routes: [
//这里写规则 对应的组件会放到App.vue占位符
//懒加载 component 后面写箭头函数 返回import('@/components/MyLogin.vue')
{path: '/login',component: () => import('@/components/MyLogin.vue')},
]
});
Vuex
vuex简介
- 实现大范围数据共享
- 能够方便,高效的数据共享
- 数据存取一步到位
- 数据流动非常清晰
- 数据驱动视图
安装
npm i vuex@3.6.2
Store创建
创建store/index.js
//导入vue
import Vue from "vue";
//导入vuex
import Vuex from 'vuex'
// 注册插件
Vue.use(Vuex);
// 创建store对象
const store = new Vuex.Store({});
//导出向外共享的store对象
export default store
main.js
//导入store
import store from './store'
new Vue({
render: h => h(App),
//挂载
store,
}).$mount('#app')
count 值:{{$store.state.count}}
mapState方法
count 值:{{ count }}
展开运算符
//展开运算符
// ... 展开数组
// ...[1,2,3] //1,2,3
// ...'hello' //'h','e','l','l','o'
/*
let arr1 = [1,2,3];
let arr2 = [4,5,6];
let arr3 = [...arr1,...arr2]
*/
/*
let obj1 = {name: 'zs', age:20};
let obj2 = {sex:'男',height:'180cm'};
let obj3 = [...arr1,...arr2]
*/
store严格模式
- 防止误修改数据
- 想要修改需要在用Mutation
// 创建store对象
const store = new Vuex.Store({
//开启严格模式
strict: true,
//全局共享数据
state : {
count: 100,
name: '张三'
},
});
Mutation
专门修改Store中的数据
只能写同步任务
// 创建store对象
const store = new Vuex.Store({
//只能写同步代码
mutations: {
//修改数据只能通过mutations
//这里的方法 第一个参数 都是state
changeCount(state,n) {
state.count ++;
}
}
});
mapMutations
count 值:{{ count }}
Actions
写异步任务
// 创建store对象
const store = new Vuex.Store({
mutations: {
//修改数据只能通过mutations
//这里的方法 第一个参数 都是state
//只能写同步代码
changeCount(state,n=1) {
state.count += n;
}
},
//异步操作
actions: {
gaiCount(ctx) {
setTimeout(() => {
// ctx.state.count = 150; 修改数据只能在mutations
ctx.commit('changeCount')
},1000);
}
}
});
mapActions
count 值:{{ count }}
Getters
计算属性
// 创建store对象
const store = new Vuex.Store({
getters: {
heCount(state) {
return state.count + state.count;
}
}
});
mapGetters
count 值:{{ count }} {{heCount}}
Module
所有数据都放在一起数据会乱
把数据模块化,把数据和方法按照彼此的关联关系进行封装
import Vue from "vue";
import Vuex from 'vuex'
import carModule from '@/store/cart.js'
Vue.use(Vuex);
export default new Vuex.Store({
//开启严格模式
strict: true,
//注册vuex的模块
modules: {
//模块名
cart: carModule
}
});
cart.js
//购物车案例
export default {
state(){
return {
list: []
}
},
mutations: {
show(){
console.log('调用count里的show');
}
},
actions: {},
getters: {},
}
namespaced
- 命名空间
- 解决模块之间命名冲突问题
- 加在模块里
export default({
//开启命名空间
namespaced: true,
});
count 值:{{$store.state.cart.count}}
访问开启命名空间的数据
count 值:{{$store.state.cart.count}}
count 值:{{$store.getters['cart/pingfang']}}
模块简调用
import { mapState,mapMutations,mapGetters,mapActions } from 'vuex'
export default {
name: 'Right',
//计算属性
computed:{
...mapState('cart',['count']),
//如果属性冲突 使用对象赋值
...mapState('cart',{ cardCount: 'count' }),
...mapGetters('cart',['pingfang'])
},
//方法
methods: {
...mapMutations('cart',['updateCount']),
...mapGetters('cart',['xiugai'])
}
}
vue组件库
严格检查ESLint
不支持 函数后面加空格
修改eslintrc.js
rules: {
//在rules里添加
// 控制函数名和小括号之间,不需要空格
'space-before-function-paren': [
'error',
{
anonymous: 'always', // 普通的匿名函数,always表示需要空格;never表示不需要空格
named: 'never', // 普通的命名函数
asyncArrow: 'always' // 针对箭头函数
}
]
}
配置Axios
npm i axios
//requet/request.js
import axios from 'axios'
// 创建axios实例
const obj = axios.create({
// 配置axios全局路径
baseURL: 'http://www.liulongbin.top:3006'
})
export default obj