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配置

  • 创建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 销毁完成

组件数据共享

父传子

父元素值改变 子元素值也改变


子传父

父元素接收的数据与子元素互不影响

重新发送 重新接收







{{name}}

{{obj.a}}

ref引用

在不依赖jQuery的情况下,操作dom元素

 

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




动态组件

  • 当组件设置缓存时
  • 会触发两个周期函数
    • activated 激活时触发
    • deactivated 当组件缓存 触发


全局自定义指令

//全局自定义指令
// 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')
  • 声明路由 和 占位符

  • 声明匹配规则
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'},

嵌套路由


  • 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},

        ]},
    ]
});

动态路由





  • index.js
//创建路由实例对象
const router = new VueRouter({
    routes: [
        //接收数据
        {path: '/movie/:id/:name',component: Movie}
    ]
});

使用 props 接收参数




  • 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方法




展开运算符

//展开运算符
// ...  展开数组
// ...[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




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




Getters

计算属性

// 创建store对象
const store = new Vuex.Store({
    getters: {
        heCount(state) {
            return state.count + state.count;
        }
    }
});

mapGetters




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