前端—vue项目—版本介绍

介绍:MVVM数据双向绑定的js框架,UI组件,核心思想是:数据驱动、组件系统
一、基础:
2.x学习网址:https://cn.vuejs.org/v2/guide/ 2016年发版
3.x学习网址:https://v3.cn.vuejs.org/ 2019年发版(2020后使用)
区别:vue 2.0 dom渲染没有react好,打包文件不轻简、对未来必然流行的TS没有react支持得好

vue 3.0 性能更好,不在乎打包没有用到的模块、更友好的支持兼容TS

构成 :
指令 - 操作VDOM(操作虚拟DOM)
组件系统 - 项目模块化

工作中使用的版本
vue 2.6.11
element-ui 2.13.2 (只有1x和2x,新增 一些属性功能,而且兼容vue版本要求没那么高了)
vuex 3.5.1(与vue的版本是对应的,vue2对应vue3x vue3对应vue4x)
vue-router 3.1.3
axios 0.24.0
moment+ramda+qs+uuid+clipboard+echarts(使用的其他 技术 )
请求一般使用axios / fetch (基于标准 Promise 实现,支持 async/await)

搭建vue项目(一般会先生成秘钥对,用于和远程或其他计算机的连接,再进行全局名字和邮箱信息的设置)
下node.js:node.js是一个能够在服务器端运行的js的开放源代、跨平台js运营环境(偶数是 稳定版本,例如8.0) node -v查版本

// 常用vue实例的属性和方法 new Vue({实例方法和属性})
export  default {
name: 'Home', // 设置name属性,即给组件命名,该组件是一个命名组件
el: '#example', // 绑定dom元素,即绑定模版中的标签,该vue实例只在该标签下可用,渲染在该标签下(vue项目中都绑定在跟实例中的跟dom中,根据路由嵌套关系,将一个个组件依次渲染,而一个组件一个index.vue,他们的模版与实例是绑定的,不同在模版中即实例中相互绑定)
props:{ // 接收组件传参,即父组件调用该组件时传的参数
	title: {
	      type: String,
	      require: false,
	      default: '',
	    },
	    content: {
	      type: String,
	      require: false,
	      default: '',
	    }
},

//props: [ // 直接接传过来的参数
//    'loadTaskManagementList',
//    'appList',
//  ],

 components: {
    // 页面标题子组件
    ContentHeader,
  },
data () {  // 数据,刚开始放页面的初始值,是一个方法,返回数据对象,因为组件可能会复用(即创建多个实例),直接写成对象,即所有的实例同用一个             引用类型的对象。使用函数没创建一个新实例都会返回新的对象,只作用当前调用的组件中。
    return {
      name: 'xuehua',
      age: 98,
      type: 'a',
      ty: 'b',
      user: { // 父数据 要传给子的
        name: 'xuehua.zhao111',
        age: 18
      },
      bbbb: undefined
    }
  },
computed:{ // 计算属性方法 汇总,模版中一般渲染,可以放简单的js表达式,对于复杂的计算,可以放在计算属性中。不同的是计算属性是基于响应动态更新 的,而函数方法需要触发
	// 计算属性的 getter
    reversedMessage () {
      // `this` 指向 vm 实例
      return this.message.split('').reverse().join('')
    }// 计算属性默认只有 getter,不过在需要时你也可以提供一个 setter:
    fullName: {
    // getter
    get: function () {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set: function (newValue) {
      var names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
  当给fullName进行赋值时set会被调用
    
},

watch: { // 设置watch监听,观察和响应 Vue 实例上的数据变动侦听属性(当基于其他数据的变动而变动时,可以用计算属性也可以用真听属性)
         // 当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的,因为computed只是简单的属性监听计算,方法需要触发
         //  <input v-model="question">
         question: function (newQuestion, oldQuestion) {
           this.answer = 'Waiting for you to stop typing...'
           this.debouncedGetAnswer() // 具体逻辑在方法中写
        }
  },

// 生命周期方法 (每个实例被创建时都需要经历一系列的过程,例如初始化,将实例挂在到对应的dom,响应数据的变化)
  beforeCreate() { // vue实例被创建前的钩子,此时实例的数据data还没执行,一般不在此函数中设置逻辑
  },
  created() { // 实例被创建后调用的钩子,此时已完成数据观测数据及计算。一般用于接口请求或更改data初始值
    this.date = this.day ? this.day : moment().format('YYYY-MM-DD');
  },
  beforeMount() { // 实例未挂在到对应的dom上调用
  },
  mounted() { // vue实例已挂在到对应的dom(即绑定的模版标签中)
    this.target = $(this.$el).find('.chart');
    this.loadChart();
  },
  beforeUpdate() { //当data中数据发生改变时调用,但此时dom中还未更新
  },
  updated() { // 新数据更新后调用
  },
  activated() {
  },
  disactivated() {
  },
  beforeDestroy() { // 销毁前的调用
  },
  destroyed() { // 组件销毁
  },
methods:{ // 实例方法

}
}

// 如何获取实例上的属性和方法
// 方法1、
    var vm = new Vue({
       // 选项
    })
     vm.a //可获取data中属性 、computed中计算方法等等

// 方法2、  设置 ref属性(在组件(或者dom上)增加ref属性即可),一般用来访问子组件实例
通过 this.$refs.设置的ref字符串拿到dom或组件实例,可获取设置组件中的属性值及调用方法
$refs 只会在组件渲染完成之后生效(即mounted后),并且它们不是响应式的。这仅作为一个用于直接操作子组件的“逃生舱”——你应该避免在模板或计算属性中访问 $refs,可以放在方法中,方法一般是渲染后通过动作触发的
// 获取根实例(一般不用,除非对于就几个组件的小型应用,否则用vuex进行状态管理,将多个组件都用到的数据放在vuex中)
this.$root

// 获取父实例(一般不用,直接用父将属性或方法传给子的,子通过props接收的方式实现)因为这样实现不容易进行 调试和状态管理,层级较多时都不知道变更从哪里发起
this.$parent

vue提供的特殊标签属性 :
(1)v-modal(同value属性),双向数据绑定,一般用在交互标签或组件上(即代表绑定数据value和触发输入事件input)

<input type="text" :value="username" @input="username=$event.target.value">

(2)v-if=‘布尔值’(条件渲染,基于真正的dom渲染,false则不做渲染,若是对应频繁切换显隐时v-show好,他是基于样式,实质就是display:hidden)v-else-if=‘’ v-else
(3)v-show=‘布尔值’ (控制显隐)
(4)v-for(循环,一般用于 列表渲染,注意绑定:key属性,代表唯一标识 ,key绑定 值不要使用数组对象等非基本元素 ,也可 用于遍历对象,注意不推荐与v-if一起使用,但对于只想渲染满足条件的部分时这种方式适用)

 <ol>
    <li v-for="(todo,index,array) in todos">
      {{ todo.text }}
    </li>
  </ol>
var app4 = new Vue({
  el: '#app-4',
  data: {
    todos: [
      { text: '学习 JavaScript' },
      { text: '学习 Vue' },
      { text: '整个牛项目' }
    ]
  }
})

(5) v-on:事件名(简写@事件名=‘事件名’) 浏览器事件/鼠标事件/键盘事件/表单事件/触摸事件

// 1、直接绑定一个方法 
<a @click="doSomething">...</a>
doSomething(event){
// 可写逻辑和操作事件对象属性及方法
}

// 2、调用方法(),即有传参数时用,方法接收参数的最后一个参数可写事件对象,即原始的dom事件对象
 <button v-on:click="say('hi',$event)">Say hi</button>
 methods: {
    say: function (message,event) {
      alert(message)
    }
  }


// vue中扩展事件修饰符
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
// e.stopPropagation()  阻止事件的传播
// e.preventDefault()  阻止默认行为

<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>

<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

// 扩展按键修饰符,只有keyup keydown事件时的修饰符.enter.tab.delete (捕获“删除”和“退格”键).esc.space.up.down.left.right
// 当不使用这些修饰符时就可以利用判断按键码来执行对应的逻辑
<!-- 只有在 `key``Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">


// 键盘修饰符
.ctrl
.alt
.shift
.meta
// 鼠标修饰符
.left
.right
.middle

// 什么是事件对象:就是当你触发了一个事件,对该事件的信息描述。每一个事件都有对应的事件对象来描述信息  兼容写法: e=e||window.event

// 事件对象上的属性和方法 
  // (1)属性 
         offsetX 和 offsetY 是指鼠标相对于触发事件元素的相对位置(计算的起点包不包含边框bordre值,不同的浏览器不同)
         clientX 和 clientY 是相对浏览器窗口来计算的,从浏览器可视区域左上角开始,即是以浏览器滑动条此刻的滑动到的位置为参考点,不随滑动条移动而变化(不包含窗口自身的控件如地址拦和滚动条):即当前可视区域内鼠标的相对位置,不包含滚动条包含的宽、高
         screenX 和 screenY:是鼠标相对用户屏幕(显示器)的距离,是绝对位置。跟滚动条和浏览器窗口、窗口的可视区域都没啥关系
         pageX 和 pageY:鼠标相对当前整个网页的坐标值,即pageX = clientX+滚动进去的距离
         x 和 y 其值同clientX 和 clientY,都是相对浏览器的可视区域
         type 事件的类型,即是什么事件触发的   ‘click’
         target  触发事件的目标元素,是一个对象
         timeStamp 事件创建的时间戳(毫秒值)不是触发事件的时间

  // (2)方法
  e.preventDefault()
  e.stopPropagation()  阻止事件的传播,主要用于阻止事件的mao

在这里插入图片描述
补充三大 家族的学习(以dom属性的形式存在的,用于获取自身节点的更多信息)

//(1)offest  家族(获取的是元素自身的,与其他元素无关,目的是方便获取元素尺寸)
      offsetWidth offsetHeight 自身盒子的宽高   width|height + padding + border
      offsetLeft offsetTop 距离第一个有定位的父级盒子左边和上边的距离,注意:父级盒子必须要有定位,如果没有,则最终以body为准,它是以父级定位盒子的padding开始计算的,不包含border (应该是边框与边框的距离)
      offsetParent 返回有定位的父级盒子,如果都没有定位即为body
      offsetTop style.top 的区别:返回的类型,style.top只能是行为样式中设置了定位和top

// (2) scroll 家族
        scrollWidth 元素内容真实的宽度,内容不超出盒子高度时为盒子的clientWidth,超出时加上超出的(width+padding+滚动的)
        scrollHeight 元素内容真实的高度,内容不超出盒子高度时为盒子的clientHeight,超出时加上超出的
        scrollTop scrollLeft 滚动条中网页隐藏的距离
        (兼容写法:var scrollTop = window.pageYOffset ||document.documentElement.scrollTop||document.body.scrollTop ||0;)
        scrollTo(x,y) 把内容移动到指定的坐标

// (3) client 家族
       clientWidth和clientHeight 盒子的可见区域宽|高 (不是盒子内容真实的)  clientWidth=width+padding
       clientLeft和clientTop。不用,获取左边框的宽度


//  扩展:获取屏幕的瞌睡区域

****** Window视图属性(低版本IE浏览器[<IE9]不支持) 【自测包含滚动条,但网络教程都说不包含???】
     * innerWidth 浏览器窗口可视区宽度(不包括浏览器控制台、菜单栏、工具栏) 
     * innerHeight 浏览器窗口可视区高度(不包括浏览器控制台、菜单栏、工具栏)
* ***** Window视图属性结束
    
****** Document文档视图
     * (低版本IE的innerWidth、innerHeight的代替方案)
     * document.documentElement.clientWidth 浏览器窗口可视区宽度(不包括浏览器控制台、菜单栏、工具栏、滚动条)
     * document.documentElement.clientHeight 浏览器窗口可视区高度(不包括浏览器控制台、菜单栏、工具栏、滚动条)
     * 
     * document.documentElement.offsetHeight 获取整个文档的高度(包含body的margin)
     * document.body.offsetHeight 获取整个文档的高度(不包含body的margin)
     * 
     * document.documentElement.scrollTop 返回文档的滚动top方向的距离(当窗口发生滚动时值改变)
     * document.documentElement.scrollLeft 返回文档的滚动left方向的距离(当窗口发生滚动时值改变)****** Document文档视图结束

window.screen.height:屏幕分辨率的高(屏幕的高度 )
window.screen.width:屏幕分辨率的宽 (屏幕的宽度 )      window.screen.availHeight:屏幕可用工作区的高
window.screen.availWidth:屏幕可用工作区的高
window.screenTop:浏览器窗口距离电脑屏幕上边界的距离
window.screenLeft:浏览器窗口距离电脑屏幕左边界的距离

window. innerWidth :浏览器可视区域的内宽度,包含滚动条
window.innerHeight:浏览器可视区域的内高度,包含滚动条
window.outerWidth:浏览器宽度
window.outerHeight:浏览器高度

(6)v-bind:属性名(缩写:属性名。给标签绑定属性,因为模版不能作用在属性上,所以属性要动态绑定值,就需要使用v-bind:)

<button v-bind:disabled="isButtonDisabled">Button</button>
// v-bind的工作形式略有不同,如果 isButtonDisabled 的值是 null、undefined 或 false,则 disabled attribute 甚至不会被包含在渲染出来的 <button> 元素中

(7)v-once 只渲染一次,即时改变该标签都不会 再重新渲染 (一般不用 ,会影响该节点其他数据的绑定)

<span v-once>这个将不会改变: {{ msg }}</span>

(8)v-html (模版{{}双大括号会将数据解析成普通文本,即使是标签也会当成字符串渲染})

<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
Using mustaches: <span> gg </span>
Using v-html directive:gg
// 若有样式直接样式也会渲染对应的样式,在模版中可以使用js表达式

补充style与class属性 (他们都是属性 可以 用 v-bind绑定,只要得到我们需要的结果即可,Vue.js 做了专门的增强,表达式结果的类型除了字符串之外,还可以是对象或数组)

// 1、普通用法(没有vue扩展前的用法),直接在样式文件中通过类选择器设置样式属性即可,多个类名用空格分割 .static{样式属性:值}
<div class="static active"></div>

// 2、给 v-bind:class 一个对象,以动态地切换 class,有无对应的样式取决于属性的值是否为真,最终的实质还是class='active text-danger'(都为真的情况)
<div :class="{ active: isActive, 'text-danger': hasError }"></div>
data: {
  isActive: true,
  hasError: true
}
// 对象不一定非在模版标签中 ,可以是data中 属性或计算属性
<div v-bind:class="classObject"></div>
data: {
  classObject: {
    active: true,
    'text-danger': false
  }
}

computed: {
  classObject: function () {
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error && this.error.type === 'fatal'
    }
  }
}

// 3、给 v-bind:class 一个数组
<div v-bind:class="[activeClass, errorClass]"></div>  //直接字符串的写法 ,数组中的元素支持三元表达式
data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}
最终<div class="active text-danger"></div>  //直接字符串的写法 
// 内联样式
// 1、标签通用的原写法 (直接字符串,css中样式的写法)
<div style="color: red, font-size: 15px"></div>
// 2、对象(返回一个对象样式即可),他是一个js对象,不是 css对象
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
  activeColor: 'red',
  fontSize: 30
}
或者写成直接样式对象
<div v-bind:style="styleObject"></div>
data: {
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}

// 3、数组
<div v-bind:style="[baseStyles, overridingStyles]"></div> // 多个样式对象应用在标签上
data: {
  baseStyles: {
    color: 'red',
    fontSize: '13px'
  },
  overridingStyles:{
}

// 扩展多重值,以为 style 绑定中的 property 提供一个包含多个值的数组,这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染 display: flex
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

==表单输入绑定 ==

表单输入绑定 v-modal,会忽略所有表单元素的 value、checked、selected attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的 data 选项中声明初始值
// 修饰符
.lazy。在change事件后才进行同步(input 事件触发后就会更新)
.number 将用户输入转为数值型
.trim 自动过滤用户输入的首尾空白
// 事件的修饰符 .prevent 调用event.preventDefault()阻止事件的默认行为
<form v-on:submit.prevent="onSubmit">...</form>

总结vue实例的生命周期
在这里插入图片描述

二、路由(vue框架的插件,让构建单页面应用变的简单,项目只有一个index.html页面)

就是将组件映射到路由,然后告诉vueRouter在哪渲染,即路由出口
1、路由的安装

// 1、在工程中下载 
npm install vue-router
// 2、创建路由文件夹,配置路由 。一般放在src下的router文件夹的index.js中
import Vue from 'vue'
import VueRouter from 'vue-router' // vue的路由插件
Vue.use(VueRouter)  // 明确安装路由功能
const toutes=[// 进行路由配置
{
    path: '/home',
    name: 'Home',
    component: () => import('../views/Home'),  // 按需加载,性能更好
    children:[ // 配置一个个子路由,即Home组件中有路由出口,渲染嵌套的子路由匹配组件
    {
    }
    ]
}
]
const router = new VueRouter({ // 创建路由实例router
  routes
})

export default router // 导出供项目使用
// 将router实例注入根实例,所有项目组件都可用路由 的方法及属性(在main.js中 将路由注入根实例,并绑定在根组件上)
new Vue({
  router, // 将创建的路由实例注入跟实例,供整个项目组件使用
  store,
  render: h => h(App) // 渲染的是跟组件APP
}).$mount('#app') // 根入口页面为App组件,挂在在#app盒子上(在public=>index.html中)

2、在项目中配置路由(一般创建单独的路由文件,在main.js中引入供全局使用)
3、路由
(1)动态路由 匹配,主要看:匹配的动态路由及*匹配的所有路径
(2)嵌套路由:即一个路由匹配的组件中又有路由出口,渲染对应的子路由匹配,利用children配置子路由
(3)编程式导航(除了使用声明式 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现)
(4)命名路由:就是对应 一个路由匹配,在跳转等时使用命名路由更方便,否则就得传path

router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123

(5) 命名视图(如果 router-view 没有设置名字,那么默认为 default),当想同时同级展示多个组件时用到

    {
      path: '/', // 写路由路径,且该路径同级渲染几个组件用components:对象
      components: {
        default: Foo,
        a: Bar,
        b: Baz
      }
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>

(6)重定向和 别名

1、重定向访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b,redirect可以是字符串path也可以是对象参数描述路径,也可以 是方法
{ path: '/a', redirect: '/b' }
2、别名 /a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。
 { path: '/a', component: A, alias: '/b' }

(7)路由组件传参
使用 props 将组件和路由解耦,使得组件在任何地方可引入复用
props可以是布尔模式、对象模式、函数返回props模式
(8)HTML5 History 模式
const router = new VueRouter({
mode: ‘history’, // 默认是hash模式,即带#的,当设为history时为正常的url但是 不好管理
routes: […]
})

进阶篇

(1)导航守卫

// 全局前置守卫:当导航发生变化时调用,一般用于对从一个路由跳转至另一个时的检验,例如:如果没有登录过则不让 去跳转别的页面,强制去登录页面
// 全局前置守卫一般放在路由配置文件中,对所有的配置的路由进行校验(参数是对象,同路由配置的对象)
router.beforeEach((to, from, next) => {
  if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
  else next()
})

router.beforeEach((to, form, next) => { // 导航守卫,看是否已登陆
  if (localStorage.getItem('userName')) { // 若用户已经登陆过
    if (to.path === '/login') {
      next('/home') // 去首页
    } else {
      next()
    }
  } else {
    if (whiteList.includes(to.path)) { // 如果在白名单中
      next()
    } else { // 没登录过且不在白名单中则必须先到登陆页登陆
      next('/login')
    }
  }
})

// 全局 解析守卫(不怎么用,用法同router.beforeEach,只是调用的时间不同 )
// 全局后置钩子
// 路由独享的守卫,可以单独给路由设置
{
      path: '/foo',
      component: Foo,
      beforeEnter: (to, from, next) => {
        // ...在真正进入组件渲染前执行的逻辑
      }
    }
// 组件内的守卫
const Foo = {
  template: `...`,
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    // 不!能!获取组件实例 `this`
    // 因为当守卫执行前,组件实例还没被创建
  },
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问组件实例 `this`
  }
}

注意:
1、导航被触发。
2、在失活的组件里调用 beforeRouteLeave 守卫。
3、调用全局的 beforeEach 守卫。
4、在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)5、在路由配置里调用 beforeEnter。
6、解析异步路由组件。
7、在被激活的组件里调用 beforeRouteEnter。
8、调用全局的 beforeResolve 守卫 (2.5+)9、导航被确认。
10、调用全局的 afterEach 钩子。
11、触发 DOM 更新。
12、调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

(2)路由元信息:设置路由meta,并通过this. r o u t e . m a t c h e d 遍历访问( 3 )过渡动效:通过 t r a n s i t i o n 结合 r o u t e r − v i e w 实现( 4 )数据获取:利用 t h i s . route.matched遍历访问 (3)过渡动效:通过transition结合 router-view实现 (4)数据获取:利用this. route.matched遍历访问(3)过渡动效:通过transition结合routerview实现(4)数据获取:利用this.route对象 的属性获取参数,或利用路由的钩子函数获取路由
(5)路由懒加载

{
    path: '/home',
    name: 'Home',
    component: () => import('../views/Home') // 路由懒加载,用时才用
  },

(6)导航故障
当next(false)或导航抛出错
用时查:https://router.vuejs.org/zh/guide/advanced/navigation-failures.html#%E6%A3%80%E6%B5%8B%E5%AF%BC%E8%88%AA%E6%95%85%E9%9A%9C

4、路由实例上的方法 this.$router拿到路由实例(原先都是通过a标签、window.open打开新页面或当前页面打开,现在通过路由实例上的方法)

// 实例方法
// 1、this.$router.push()
// 参数是字符串类型 this.$router.push('/home')  直接写路由匹配的path,即在浏览器中渲染的url域名后的路径,页面会渲染该路径对应的匹配组件
// 参数是对象的形式:1this.$router.push({path:'/home'})
    (2)  this.$router.push({name:'Home',params:{id:123}})    (对于命名路由,若有动态参数则传params对象,例如命名路由对应的path为 '/home/:id') 
    (3)  this.$router.push({name:'Home',query:{id:123}})this.$router.push({path:'/home',query:{id:123}}) 传查询参数即?后的
    
    注意:若提供了path则params会被忽略,因为path就包括了动态参数(path就是路径,已经将动态参数包含了)

// 2、this.$router.replace(). // this.$router.replace(`?${queryString}`)例如替换查询参数
     使用完全同this.$router.push()实例方法,只是它只是替换当前的路由为新的,渲染新路由对应匹配的组件,不会添加进history的记录,即不能通过。  $router.back()   $router.go()再进行操作前进回退该页面,它就不在历史记录中,没有前后url路径
     或这种对象格式的替换参数
     his.$router.replace({
        query: { // 只替换查询参数
          ...this.$route.query,
          shopCode: this.shopCode,
          shopName: this.shopName,
        },
      });

// 3、this.$router.back() 同window.history.back() 在window的history历史记录中后退记录(即可以直接跳到之前渲染的页面)

// 4、this.$router.go() 同window.history.go() 在window的history历史记录中前进记录(即可以直接跳到之前在历史中渲染过的页面)
// 5、this.$router.resolve() // 传的参数同push方法,一般利用此方法构造一个新的完整的url在 新窗口中打开 (同             window.open(window.location.href,'_blank'))
        const {href} = this.$router.resolve({
                    path: `/user_details/${userId}`,
                    query:{}// 有查询参数时这样操作
                });
                window.open(href, '_blank');

5、路由对象 this.$route(同window.location对象可以拿url中各个部分的值):拿当前路由中各个属性值

// 路由对象上的属性
// (1) 查path中的动态片段 就是path中 :id等
this.$route.params  // 动态参数都在此对象中。例如this.$route.params.id
// (2) 查路中的查询参数 ?后的
this.$route.query // 拿到的是查询参数对象  {a:1,b:2}
// (3) 获取哈希,#后的无则'' http://local.wormpex.com:8887/#/basicServices/taskManagement
this.$route.hash  // ''
// (4) 页面组件路径 http://local.wormpex.com:8887/#/basicServices/taskManagement
this.$route.path(只是组件匹配的path)    // '/basicServices/taskManagement'
// (5) http://local.wormpex.com:8887/#/basicServices/taskManagement
this.$route.name    // '/shop-admin/basicServices/taskManagement'


回顾:window.location对象(用于获得当前页面的地址 (URL),并可以将浏览器重定向到新的页面)

// 1、获取完整的url(包含协议域名查询参数等,就是浏览器中完整的url,跟浏览器窗口的一致)
window.location.href
// 2、获取协议
window.location.protocol   // 'http:' 或 'https:' 
// 3、获取域名及端口
window.location.host    //"local.wormpex.com:8887"
// 4、只获取域名
window.location.hostname.   // "local.wormpex.com"
// 5、只端口
window.location.port   // "8887"
// 6、路径名 http://local.wormpex.com:8887/#/basicServices/taskManagement  http://w3.opc.dev.wormpex.com/shop-admin#/businessconfig/storeInfoDetails
window.location.pathname  // ‘/’ 或锚点前的 ‘shop-admin’
// 7、哈希(锚点及后的所有,无则返回'')
window.location.hash  //  ‘#/businessconfig/storeInfoDetails’
// 8、获取查询参数
window.location.search   //"?a=1"
// 方法二获取查询参数(处理完整的url处理字符串,location.href,获取url中最后一个一个?的索引,截取之后的)
const getQueryString = (url:location.href) => {
  if (!url || !url.includes('?')) {
    return '';
  }
  const index = url.lastIndexOf('?');
  const len = url.length;
  return url.substring(index + 1, len); // 得到a=1&b=3,再利用字符串方法处理参数值,或利用js库qs进行序列和对象的相互转换
};

回顾:window.history对象(用于向前向后到页面)
回顾:window.open() 方法
回顾:window.close() 方法

三、组件间通信
1、父子组件间的通信
(1)父传子
通过绑定属性的形式将子组件需要的数据或方法传递 :propPqrams=‘父中的数据’
子通过props:[] 或{} 接收,不允许改props传过来的值(传过来的数据用法同data中数据的用法)

 props: {
    title: {
      type: String,  // 接收参数的类型
      require: false,   // 是否必传字段
      default: '', // 默认值
    },
  },
  
props: [
    'title',
    'visible'
  ],

(2)子传父
在子组件中某触发式传递 this.$emit(‘methodsName’, 传的子数据)
在父组件的调用子组件上接收 @methodsName=‘自己随意起的名’ 在js中自己起名方法的参数就是传过来的参数

2、其他形式的通信,一般用vuex来管理状态 (看下节)

四、集中式状态管理Vuex(也是组件间的通信):vue提供的插件,进行公共数据的状态管理,适合存放多个组件共享的数据或不同视图要变更同一状态
特点:不能直接更改状态管理中的state,必须显示提交mutation
1、安装

// 1、下载插件
npm install vuex
// 2、创建store,并显示安装vuex,创建的stora导出供全局使用
import Vue from 'vue'
import Vuex from 'vuex'
import list from './modules/list'
Vue.use(Vuex)
export default new Vuex.Store({
  // 根级别的store
  state: { // 一般放公用数据
  },
  getters: {
  },
  mutations: {
  },
  actions: {
  },
  modules: { // 模块,里面的每个模块也是一个store
    list: list// 封装模块的store,访问时得加模块名list
  }
})

// 3、将store注入根组件,供全局都可使用(在main.js)
  import store from './store'
  new Vue({
	  router, // 将创建的路由实例注入跟实例,供整个项目组件使用
	  store, // 将状态管理注入根实例,供整个项目使用
	  render: h => h(App)

2、原理
在这里插入图片描述
描述:用户触发动作触发action,action中提交mutations,对应的mutations中更改状态,状态 的更改导致视图层渲染变更

3、模块化的使用(只是在配置store时家了modules,将一个个store分割开来)

export default new Vuex.Store({
  // 根级别的store
  state: { // 一般放公用数据
  },
  getters: {
  },
  mutations: {
  },
  actions: {
  },
  modules: { // 模块,里面的每个模块也是一个store
    list: list// 封装模块的store,访问时得加模块名list
  }
})
// 在组件中借助辅助函数拿取store的状态state
import { mapState } from 'vuex';
...mapState('shopTags', {
      cityConfigList: state => state.cityConfigList,  // 或直接写成cityConfigList:‘cityConfigList’ // 就代表shopTags命名store中的state.cityConfigList
      countState(state){return state.cityConfigList,}
    }),
    一般为了可以获取组件内的属性,用普通函数,否则this会拿不到实例中值
  // 原组件中的计算属性正常写,访问都是一样的,没有模块名时省略第一参数
  // 若计算属性名与拿状态的名相同,也可以直接数组的形式
  ...mapState(['cityConfigList'],)   有模块放入第一参数
// 在组件中借助辅助函数拿store的状态getters
import { mapGetters} from 'vuex';
 ...mapGetters({
      shopCodeList: 'list/shopCodeList',
      shopCityList: 'list/shopCityList',
      schedulePlanStatus: 'list/schedulePlanStatus', // 模块list下的状态schedulePlanStatus
    }),
 // 会将模块名写在第一个参数中,不用每个去写路径
 ...mapGetters('list', {
      businiessStateOption: 'businessStatus', // 该模块下的getters下的businessStatus方法
      shopStateOption: 'shopStatus',
      storeType: 'storeType',
    }),
 // 若计算属性名和getters下的方法名一致可以使用数组
 ...mapGetters('list', [
      'shopCodeList', // 即list模块下的getters中的shopCodeList方法
      'shopCityList',
      'shopLabels',
    ]),
// 在组件中借助辅助函数拿store的mutations方法来进行状态的更改(在方法中)
 ...mapMutations('staffManage', {
      setSearchData: 'SET_SEARCH_DATA', //staffManage模块下的mutations下的方法SET_SEARCH_DATA
      setStartTime: 'SET_START_TIME',
    }),
    // 相当于在组件实例中添加了两 方法setSearchData与setStartTime
    // 同名时也可以是数组形式
// 在组件中借助辅助函数拿store的actions方法
...mapActions({
      queryShopList: 'list/queryShopList',
      loadShopCity: 'list/loadShopCity',
      querySchedulePlanStatus: 'list/querySchedulePlanStatus',
    }),...mapActions('codeList', [
      'getStoreTypeList',
    ]),
或直接将模块放在第一参数,后面对象属性值(宗旨就是将所有的store都在store的模块中对应引入)

// 不借助辅助函数在组件实例中如何获取store状态
//  在computed中借助方法通过this.$store.state.来获取状态,组件模版使用时直接调用计算属性
//  在computed中借助方法通过this.$store.getters.来获取状态,组件模版使用时直接调用计算属性
//  在组件的methods对应方法中提交mutations以调用store中对应的mutations进行状态更改 this.$store.commit('名字',参数)   也可以写成对象的形式{type: 'SET_LIST',name: ,data:}
//  在组件的methods对应方法中触发action 以调用store中对应的action  this.$store.dispatch('名字',参数)

五、深入学习插槽:当想用给封装好的组件加内容时使用(否则就只能用封装好的组件内容,不能根据所需传不同的渲染内容)
⚠️:v-slot(v-slot:名 =‘参数对象’)是替代了原来的slot(就是起的名)与slot-scope属性(拿接过来的参数对象),不过在用组件库时还用的原来的属性实现形式
插槽的实现是我们在调用 子组件时:可传内容,并在组件内部可实现一一对应(利用命名插槽),并可访问内部子元素的数据(作用域插槽)

// 1、最简单的使用,在子组件的模版中在想放传的内容中用<slot> </ slot> 占位置,即内容出口。在调用此组件中,在组件标签中传html结构即可,数据可以是当前所在组件的数据(即父实例中的数据,就是通常所说的编译作用域,当前所在的组件中)  

// 2、后备内容:适合当调用子组件时不传插槽内容时,想默认渲染的。当传了插槽内容就会覆盖后备内容(就是备胎的意思)
     // 在子组件的占位slot中设内容
     <slot> 
	     <div>  // 后备内容块
	     </div>
     </slot>
     
// 3、命名插槽:以上插槽内容只有一个出口,意思传的插槽内容只能在子组件的某个位置展示。当需要不同位置渲染时需要命名插槽,一一对应
     // 例如在组件模版中多个位置占位并命名
	.content-header
	  .left
	    slot(name='left')
	  .center
	    slot(name='center')
	  .right
	    slot(name='right')
	// 在父组件调用时(当用v-slot:名 时将插槽内容用templete包起来)
	ContentHeader
       p(slot='left') 消息管理
    或
    ContentHeader
       templete(v-slot:'left') 消息管理


// 4、作用域 插槽:以上父组件中传的插槽内容只能使用父组件实例中的数据(所在作用域数据)。当插槽内容 想使用 自己组件中的数据时使用作用域插槽
	// 在模版子组件中通过在slot标签上的属性 上
	      <slot   name='left'    :user="userData">  </slot>  //userData是原组件中的数据,例如{lastname:}
    // 在调用子组件处:
        ContentHeader
             p(slot='left'   slot-scopt='随便起名') 消息管理   // 此时传过来的数据,都在这个对象下  随便起名.user.lastname
             
         ContentHeader
               templete(v-slot:left='随便起名') 消息管理
     ⚠️ 使用 v-slot时将插槽内容用templete上,v-slot在templete上,当使用属性slot与slot-scope时可作用在任何标签上

⚠️ vue学习网址: https://cn.vuejs.org
组件通信学习网址:https://segmentfault.com/a/1190000019208626?utm_source=tag-newest
vuex学习网址:https://vuex.vuejs.org/zh/
router路由学习网址:https://router.vuejs.org/zh/guide/
ElementUI组件库学习网址:https://element.faas.ele.me/#/zh-CN/component/select(封装的一个个组件,一个组件都是一个vue实例)
插槽的学习(当想给封装组件添加内容是使用插槽的知识,elementui中组件大多有用到sloat sloat-scope的知识,后期写法v-slot替换)
动画的实现:https://cn.vuejs.org/v2/guide/transitions.html

vue版本(1.x | 2.x | 3.x)
1、vue 2.0:MVVM数据双向绑定的库,专注于UI层面(数据驱动、组件系统)
(1)数据驱动:getter、setter、watcher、更新dom(watcher对象中关联的DOM改变渲染)
(2)组件系统

	1、Template(模板)声明了数据和最终展现给用户的DOM之间的映射关系。
	2、data(初始数据)
	3、props(接受的外部参数)
	4、methods(方法)
	5、lifecycle hooks(生命周期钩子函数)
	6、assets(私有资源)
// 2.0优点:将模板、样式、逻辑三要素整合在同一个文件中,以.vue文件后缀形成单文件组件格式,方便项目架构和开发引用

// 2.0缺点:
	性能比react低。(低在dom渲染上,低在watcher的监听不如react设计得高效)
	打包文件没有react轻简。
	对未来必然流行的TS没有react支持得好

2、vue 3.0

	1、性能更比Vue 2.0强(diff算法优化,不用diff所有节点分层)
	2、打包更科学不再打包没用到的模块
	3、Composition API(组合API4、Fragment, Teleport, Suspense
	5、更友好的支持兼容TS
	6、Custom Renderer API(自定义渲染API
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值