vue

B站 - Vue 学习笔记

0 课程介绍


  • 邂逅Vue.js
  • Vue基础语法
  • 组件化开发
  • Vue CLI详解
  • vue-router
  • vuex详解
  • 网络封装
  • 项目实战

1 邂逅Vue.js


Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的 渐进式框架

1.1 MVVM架构

  • MVVM架构

    • MVC与MVP

      image-20210624095605298

    • MVVM

      image-20210624095928516

  • Vue.js的定位

    • Vue.js在MVVM架构中的定位

      image-20210624100130116

      image-20210722111008222

    • Vue.js的功能定位

      image-20210624100230560

  • Vue.js的核心思想与特点

    • Reactive Components for Modern Web Interfaces(数据驱动的组件,为现代的 Web 界面而生)

      • 数据驱动
      • 组件化
    • 特点:侵入性低、鼓励模块化、轻量、高性能
  • 数据驱动的 Web 开发

    • Vue.js 安装

      • 下载Vue.js,通过
      • NPM安装
      • vue-cli:配套路由等灵活的命令行框架
    • 传统视图驱动 Web 开发:通过原生js/jquery操作DOM元素

      image-20210624101850057

    • 数据驱动的 Web 开发:将Vue实例中数据和方法等,通过Vue指令的方式绑定到html中

      image-20210624102334969

1.2 Vue初体验

  • HelloVue.html

    
    
        
            
            TestVue
        
        
            
    {{message}}
  • Vue列表展示

    
    
        
            
            Vue列表展示
        
        
            
            
            
    • {{item}}
  • Vue案例-计数器

    
    
        
            
            
            
            计数器
        
        
            

    当前计数:{{counter}}

image-20210722111638370

1.3 Vue生命周期

在github中下载vue源码(tag2.6.14)后,用vscode打开src --> core --> index.js,发现import Vue from './instance/index'

打开./instance/index后就可以看到Vue函数,==options表示new Vue({})传入的el、data、methods==

import { initMixin } from './init'
function Vue (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

进入./init后,发现生命周期

// expose real self
vm._self = vm
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created')
  • Vue官网生命周期流程

    Vue 实例生命周期

  • 理解Vue生命周期

    image-20210722111728411

    image-20210722113055106

2 Vue基础语法


  • vscode前端代码规范缩进设置为2

    image-20210714113742336

    image-20210714113844426

2.1 Mustache语法

  • Mustache中可以写简单的表达式,如果是复杂的表达式推荐使用computed计算属性。==Mustache也是响应式的==。Mustache作用在显示内容本身。

{{message}}

{{firstName + lastName}}

{{firstName + ' ' + lastName}}

{{firstName}} {{lastName}}

{{counter*2}}

2.2 v-once语法

  • ==v-once是非响应式的==,不希望随意更改数据或界面。v-once作用在标签上。

{{message}}

{{message}}

2.3 v-html语法

  • v-html用来按照html格式进行解析显示,v-html作用在标签上。
  • 历史遗留问题: {{{}}}以前可以使用三大括号来处理html格式解析,现在不再支持了。

2.4 v-text语法

  • v-text与Mustache比较相似,但是v-text作用在标签上,并且会覆盖掉原来的内容。==不推荐使用==

{{message}}, zfcer

, zfcer

2.5 v-pre语法

  • v-pre用于跳过这个元素和它子元素的编译过程,用于==显示原本的Mustache语法==。

{{message}}

{{message}}

2.6 v-cloak语法

  • 当Vue加载前,v-cloak存在;当Vue加载后,v-cloak被移除。
                    v-cloak语法                        
{{message}}

2.7 v-bind语法

  • v-bind基本用法:==作用于标签属性上==,语法糖:
  • v-bind动态绑定class对象:通过v-bind:class绑定标签上的class属性

    • 在v-bind:class属性中传入对象{style1: boolean1, style2: boolean2},可以做到==自动根据boolean来进行拼接==
    • 在普通class上定义公共style,最终会实现将普通class与v-bind:class进行拼接
    • v-bind:class也可以通过函数的方式传入对象
                    v-bind动态绑定class(对象语法)                        

Hello Vue (对象)

Hello Vue (对象)

  • v-bind绑定class数组:与v-bind绑定class对象类似
                    v-bind动态绑定class(数组语法) - 不推荐                        

Hello Vue (数组)

Hello Vue (数组)

  • 练习:v-for与v-bind结合
                    作业 - v-for和v-bind                        
  • {{index}} - {{m}}



  • {{index}} - {{m}}
  • v-bind动态绑定style对象:使用驼峰命名
          v-bind动态绑定style(对象语法)        

Hello Vue (对象)

Hello Vue (对象)

  • v-bind动态绑定style数组
                    v-bind动态绑定style(数组语法)                

Hello Vue (对象)

Hello Vue (对象)

2.8 computed属性

  • computed基本语法

{{firstName +' '+ lastName}}

{{firstName}} {{lastName}}

{{getFullName()}}

{{fullName}}

  • computed复杂操作
总价格为:{{totalPrice}}
  • computed的setter和getter

{{fullName}}

  • computed与methods属性对比:computed有缓存,methods没有缓存

{{getFullName()}}

{{getFullName()}}

{{getFullName()}}

{{getFullName()}}

{{getFullName()}}

{{getFullName()}}

{{fullName}}

{{fullName}}

{{fullName}}

{{fullName}}

{{fullName}}

{{fullName}}

2.9 v-on语法

  • v-on时间监听基本语法:==在事件监听时,如果方法没有参数,可以省略(); 但是在Mustache语法中是不能省略的==。v-on语法糖@

当前计数:{{counter}}



  • v-on时间监听参数问题:浏览器参数可以通过$event获得;当函数只需要event一个参数时,可以通过省略()的方式获得浏览器产生的event
  • v-on事件监听修饰符

    • .stop - 调用 event.stopPropagation()。
    • .prevent - 调用 event.preventDefault()。
    • .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
    • .native - 监听组件根元素的原生事件。
    • .once - 只触发一次回调。
aaaaa






2.10 v-if/v-else-if/v-else语法

  • v-if与v-else使用:==v-if与v-else作用在标签上==

aaa bbb ccc {{message}}

isShow为false,不显示...

  • v-else-if

优秀

良好

及格

不及格

成绩表现:{{result}}

  • 练习:用户登录方式切换。

    • 注意:==由于虚拟DOM的存在,导致两个input控件会复用。==这里需要特别使用key来做区分,保证登录方式切换后,input不被复用(密码清空)
  • v-if与v-show的区别

    • v-if是真正把标签元素移除了、
    • v-show只是加了个display: none

    注意:==当元素在显示与隐藏之间频繁切换时,推荐使用v-show当元素就是一次切换,推荐使用v-if==

{{message}}

{{message}}

2.11 v-for语法

  • v-for遍历数组&对象
  • {{item}}
  • {{index}} -> {{item}}

  • {{value}}
  • {{key}} -> {{value}}
  • {{index}} -> {{key}} -> {{value}}
  • v-for中绑定key:绑定唯一的key后让v-for操作更加高效---DIff算法
  • {{item}}

2.12 数组的响应式操作

  • 数组响应式函数:push、pop、shift、unshift、splice、sort、reverse

    • 注意:==直接根据数组下标修改数组元素不是响应式的==
    • 非响应式操作改进手段:用splice/set代替
  • {{item}}

2.13 书籍购物车案例

  • style.css
table {    border: 1px solid #e9e9e9;    border-collapse: collapse;    border-spacing: 0;}th,td {    padding: 8px, 16px;    border: 1px solid #e9e9e9;    text-align: left;}th {    background-color: #f7f7f7;    color: #5c6b77;    font-weight: 600;}
  • main.js:==过滤器属性filters==
const app = new Vue({    el: '#app',    data: {        books: [            {                id: 1,                name: 'java study',                date: '2021-7-15',                count: 1,                price: 127.00            },            {                id: 2,                name: 'java study',                date: '2021-7-15',                count: 1,                price: 100.00            },            {                id: 3,                name: 'java study',                date: '2021-7-15',                count: 2,                price: 152.00            },            {                id: 4,                name: 'java study',                date: '2021-7-15',                count: 3,                price: 59.00            }        ]    },    computed: {        totalPrice(){            let allPrices = 0;            // for循环的三种写法            // for(let book of this.books)            //   allPrices += book.price * book.count;            // for(let i = 0; i preValue + book.price * book.count, 0)            return allPrices;        }    },    methods: {        showFixedPrice(price){            return '¥'+price.toFixed(2); //toFixed(2)保留两位小数        },        decrement(index){            if(this.books[index].count == 1)                return;            this.books[index].count--;        },        increment(index){            this.books[index].count++;        },        removeBook(index){            this.books.splice(index, 1);        }    },    //  过滤器:注意它的使用 {{value | showPrice}}    filters: {        showPrice(price){            return '¥'+price.toFixed(2); //toFixed(2)保留两位小数        }    }})
  • index.html
                    书籍购物车案例                        
编号 书籍名 出版日期 价格 数量 操作
{{book.id}} {{book.name}} {{book.date}} {{book.price | showPrice}} {{book.count}}

总价格为:{{totalPrice | showPrice}}

购物车为空

2.14 v-model语法

  • 表单双向绑定
{{message}}
  • v-model原理:==v-bind 与 v-on==

{{message}}

  • v-model与radio结合使用

{{sex}}

  • v-model与checkbox结合使用

{{isAgree}}



篮球 足球 乒乓球 羽毛球

{{hobbits}}

  • v-model与select结合使用

{{fruit}}




{{fruits}}

  • v-model与v-bind值绑定:就是动态的给value赋值,如果不使用v-bind:value就会导致value=“ f ”值就是f字符串,而不是fruit



{{fruits}}

  • v-model修饰符的使用

    • lazy懒加载
    • number修饰符
    • trim修饰符
{{message}}


{{age +' age的类型为:'+ typeof(age)}}


{{message}}

3 Vue组件化开发


组件化是Vue.js中的重要思想:组件树

image-20210722164528557

3.1 组件化基本使用

  • 组件化使用步骤:1 创建组件构造器对象; 2 注册组件; 3 使用组件

    image-20210722164716143

3.2 全局组件&局部组件

3.3 父组件与子组件

3.4 组件注册语法糖

  • 将Vue.extend({})省略掉,直接在注册组件时传入template

3.5 组件模板的分离写法

  • 推荐使用模板分离template的方式进行模板分离

3.6 组件中数据存放问题

  • 组件中数据使用函数方式存放:避免多个组件实例之间数据共享导致混乱

3.7 父子组件通信

  • 父传子(props)
  • 父传子的驼峰标识问题:v-bind:props属性时,必须把props属性改为驼峰命名
  • 子传父

    • 子组件emit发射出数据
    • 子组件标签中通过属性将数据传递给父组件
{{result}}
  • 父子通信案例:通过props和emit实现版
  • 父子通信案例:通过watch实现版

3.8 组件访问

  • 父访问子($childern、\$refs)

    • 在组件标签上设置ref属性名后,就可以通过$childern、\$refs完成对子组件数据的访问。 ==推荐使用$refs==。
  • 子访问父($parent、\$root)

3.9 slot插槽

  • slot基本使用
haha hehe

插槽标签1

插槽标签2
  • slot具名插槽
haha left center right
  • 作用域插槽

    • 编译的作用域:==父组件模板的所有东西都会在父级作用域内编译;子组件模板的所有东西都会在子级作用域内编译==
    • 作用域插槽的使用:1 template标签上绑定数据languages; 2 组件标签上使用slot-scope获取slotProps

4 Vue CLI详解


4.1 ES6模块化实现

  • 导入方式
// 1.导入的{}中定义的变量import {flag, sum} from "./aaa.js";if (flag) {    console.log('小明是天才, 哈哈哈');    console.log(sum(20, 30));}// 2.直接导入export定义的变量import {num1, height} from "./aaa.js";console.log(num1);console.log(height);// 3.导入 export的function/classimport {mul, Person} from "./aaa.js";console.log(mul(30, 50));const p = new Person();p.run()// 4.导入 export default中的内容, 可以省略{}import defaultname from "./aaa.js";defaultname('你好啊');// 5.统一全部导入// import {flag, num, num1, height, Person, mul, sum} from "./aaa.js";import * as aaa from './aaa.js'console.log(aaa.flag);console.log(aaa.height);
  • 导出方式
var name = '小明'var age = 18var flag = truefunction sum(num1, num2) {  return num1 + num2}if (flag) {  console.log(sum(20, 30));}// 1.导出方式一:export {  flag, sum}// 2.导出方式二:export var num1 = 1000;export var height = 1.88// 3.导出函数/类export function mul(num1, num2) {  return num1 * num2}export class Person {  run() {    console.log('在奔跑');  }}// 4.export default// 一个模块内只能有一个export default,不然导出的时候就乱套了const address = '北京市'export default addressexport default function (argument) {  console.log(argument);}

4.2 webpack使用

  • webpack起步

    • 安装webpack,需要node.js的环境

      1. node -v #查看node版本
      2. npm install [email protected] -g #全局安装webpack3.6.0
      3. npm install [email protected] --save-dev #局部安装webpack3.6.0
    • 注意:在终端直接执行webpack命令,使用的全局安装的webpack;当在package.json中定义了scripts时,其中包含了webpack命令,那么使用的是局部webpack。
    • webpack打包指令:webpack src/main.js dist/bundle.js
//1. webpack导入方式const {add, mul} = require('./mathUtils.js')//2. webpack导出方式function add(num1, num2){  return num1+num2}function mul(num1, num2){  return num1*num2}// webpack方式导出module.exports = {  add,  mul}
  • webpack配置

    • 通过npm init生成package.json文件, 并配置脚本

      {    "name": "meetwebpack",    "version": "1.0.0",    "main": "index.js",    "scripts": {        "test": "echo \"Error: no test specified\" && exit 1",        "build": "webpack"    },    "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",        "less": "^3.9.0",        "less-loader": "^4.1.0",        "style-loader": "^0.23.1",        "url-loader": "^1.1.2",        "webpack": "^3.6.0"    },    "description": ""}
    • 创建webpack.config.js文件, 配置入口、出口

      // 这里导入的path是node.js中的path: 通过npm init获取node中的path环境const path = require('path')module.exports = {    entry: './src/main.js',    output: {        // __dirname的下划线是两个        path: path.resolve(__dirname, 'dist'),        filename: 'bundle.js'    }}// 通过npm install [email protected] --save-dev 安装局部开发webpack,// 最后会生成package.json、package-lock.json文件
  • webpack的loader:在开发中我们不仅仅有基本的js代码处理,我们也需要加载css、图片,也包括一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等等。给webpack扩展对应的loader就可以实现上述的功能。

    • loader使用过程:1 npm安装对应的loader(loader可以在webpack官网上找到);2在webpack.config.js中的modules关键字下进行配置;
    • 安装的loader:css-loader、style-loader、less-loader、url-loader、file-loader、ES6语法处理loader(babel-loader、babel-core、babel-preset-es2015)
//package.json中的devDependencies"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",    "less": "^3.9.0",    "less-loader": "^4.1.0",    "style-loader": "^0.23.1",    "url-loader": "^1.1.2",    "webpack": "^3.6.0"  },      // webpack.config.js中的moudlemodule: {    rules: [        {            test: /\.css$/i,            // css-loader只负责将css文件进行加载            // style-loader负责将样式添加到DOM中            // 使用多个loader时,是从右往左加载 -- 注意先后顺序            use: ["style-loader", "css-loader"],        },        {            test: /\.less$/i,            loader: [                // compiles Less to CSS                "style-loader",                "css-loader",                "less-loader",            ],        },        {            test: /\.(png|jpg|gif)$/i,            use: [                {                    loader: 'url-loader',                    options: {                        // 当加载的图片,小于limit时,会将图片编译为base64字符串形式 -- 不需要打包到dist中                        // 当加载的图片,大于limit时,需要使用file-loader模块进行加载 -- 需要打包到dist中                        limit: 5632,                        // 人为设置打包到dist文件夹下的图片路径, hash:8标识截取hash的前8位做图片名;ext是图片后缀                        name: 'img/[name].[hash:8].[ext]'                    },                },            ],        },        {            test: /\.js$/,            exclude: /(node_modules|bower_components)/,            use: {                // 利用babel将es6转为es5,                // 安装命令如下:npm install --save-dev [email protected] [email protected] [email protected]                loader: 'babel-loader',                options: {                    presets: ['es2015']                }            }        }    ],},    //main.js中导入css、less// 导入base.css文件require('./css/base.css')// 导入.less文件require('./css/special.less')
  • webpack配置vue

    1. 安装vue:npm install vue --save
    2. runtime-only问题:在webpack.config.js中配置

      // 添加vue:runtime-compiler环境resolve: {    alias: {        'vue$': 'vue/dist/vue.esm.js' // 用 webpack 时需用'vue/dist/vue.common.js'    }}
    3. .vue文件封装处理::安装vue-loader、vue-template-compiler
  • webpack配置plugin:loader主要用于转换某些类型的模块,它是一个转换器;plugin是插件,它是对webpack本身的扩展,是一个扩展器。

    • plugin的使用过程:1通过npm安装需要使用的plugins;2在webpack.config.js中的plugins中配置插件
//webpack.config.js// 引用插件plugins: [    new HtmlWebpackPlugin({        template: 'index.html' //为了在dist index.html中配置index.html中的div#app    }),    new UglifyJsPlugin(), //压缩dist中的bundle.js    new webpack.BannerPlugin('最终版权归zfcer所有'),]
  • webpack-server配置

    • 安装webpack-server: npm install --save-dev [email protected]
    • 在webpack.config.js中配置

      devServer: {    contentBase: './dist',    inline: true //inline表示页面实时刷新}
  • 配置分离

    • 配置base.config.js,在dev.config.js和pro.config.js中导入基本配置

    image-20210723101506125

    • 在package.json中使用配置

      "scripts": {    "test": "echo \"Error: no test specified\" && exit 1",    "build": "webpack --config ./build/pro.config.js",    "dev": "webpack-dev-server --open --config ./build/dev.config.js"},

4.3 Vue CLI2

  • 安装Vue CLI: npm install -g @vue/[email protected]npm install -g @vue/cli-init按照Vue CLI2的方式初始化项目
  • 初始化项目:vue init webpack my-project

    image-20210723103218508

  • 目录结构

    image-20210723103253275

  • Runtime-Compiler和Runtime-only的区别

    image-20210723103538955

    • Vue程序运行过程: template --> ast --> render --> VDOM --> UI

      image-20210723103637418

    当我们在使用.vue文件时,==.vue中的template是由vue-template-compiler来处理的==,所以可以直接使用render来渲染。runtime only ,比runtime compiler少6k空间 (效率更高,空间更小)。

  • npm run build

    image-20210723105330581

  • npm run dev

    image-20210723105339054

  • webpack.base.conf.js起别名

    image-20210723105419622

4.4 Vue CLI3

  • Vue CLI3 与 Vue CLI2区别

    • vue-cli 3 是基于 webpack 4 打造,vue-cli 2 还是 webapck 3
    • vue-cli 3 的设计原则是“0配置”,移除的配置文件根目录下的,build和config等目录
    • vue-cli 3 提供了 vue ui 命令,提供了可视化配置,更加人性化
    • 移除了static文件夹,新增了public文件夹,并且index.html移动到public中
  • 创建Vue CLI3项目: npm create my-project

    image-20210723105652187

  • 目录结构

    image-20210723105712074

  • vue ui上查看配置:一大堆配置文件被放在node_modules/@vue/cli-service/lib/Service.js文件下

    image-20210723105747159

  • 起别名,在项目目录下创建vue.config.js文件

    image-20210723111444472

5 vue-router


5.1 vue-router的使用

  • 后端路由&前端路由

    • 后端路由:早期的网站开发整个HTML页面是由服务器来渲染的(JSP)。当我们页面中需要请求不同的路径内容时, 交给服务器来进行处理, 服务器渲染好整个页面, 并且将页面返回给客户端.p这种情况下渲染好的页面, 不需要单独加载任何的js和css, 可以直接交给浏览器展示, 这样也有利于SEO的优化.
    • 前端路由:

      1. 前后端分离阶段:后端只提供API来返回数据, 前端通过Ajax获取数据, 并且可以通过JavaScript将数据渲染到页面中。(根据Ajax请求从静态服务器中获取对应的静态资源)
      2. 单页面富应用SPA阶段:SPA最主要的特点就是在前后端分离的基础上加 了一层前端路由。(根据axios路由请求一次性把所有静态资源获取(路由lazy加载))
  • URL变更

    • location.href来修改url
    • history.pushState({}, '', '/foo')相当于压栈,在浏览器中可以点击返回按钮
    • history.replaceState({}, '', '/foo'), 在浏览器中不能点击返回按钮
    • history.go(-1)弹栈一个元素,等价于history.back() (并不是真正弹栈)
    • history.forward() 则等价于 history.go(1)
  • 安装vue-router:npm install vue-router --save
  • 使用vue-router:1创建路由组件;2配置路由映射:组件与路径映射关系;3使用路由:通过

    • 路由嵌套:children: [ ]
    • 参数传递:动态url,'/user/:userId'传递参数userId。在组件中通过this.$route.params.userId来获取
    • 导航守卫:通过在beforeEach中利用to来获取meta来传递导航栏标题, 通过to.matched[0].meta.title来获取meta参数
    • kepp-alive:keep-alive包裹router-view设置访问缓存, 这样可以让组件created只执行一次(缓存)。组件内的 activated 和 deactived 生命周期函数必须在设置keep-alive标签的包裹下来生效

      • : 该标签是一个vue-router中已经内置的组件, 它会被渲染成一个标签.
      • : 该标签会根据当前的路径, 动态渲染出不同的组件.
    //index.jsimport Vue from 'vue'import Router from 'vue-router'// 路由懒加载: 不要直接注册组件const Home = () => import('@/components/Home')const HomeMessages = () => import('@/components/HomeMessages')const HomeNews = () => import('@/components/HomeNews')const About = () => import('@/components/About')const User = () => import('@/components/User')const Profile = () => import('@/components/Profile')// 1. 通过Vue.use(插件),安装插件Vue.use(Router)// 源码分析:Vue.use(Router)的内部操作是install(Vue类), 在install内部全局注册了RouterView 和 RouterLinkconst routes = [   {      path: '/',      redirect: '/home',      meta: {        title: '首页'      },    },    {      path: '/home',      component: Home,      meta: {        title: '首页'      },      children: [        {          path: '',          component: HomeNews        },        {          path: 'news', //children中的path一定不能加'/', routes中的path可以加'/'          component: HomeNews        },        {          path: 'messages',           component: HomeMessages        }      ]    },    {      path: '/about',      component: About,      meta: {        title: '关于'      },    },    {      path: '/user/:userId', //注册动态url      component: User,      meta: {        title: '用户'      },    },    {      path: '/profile',      component: Profile,      meta: {        title: '档案'      },    }]// 2. 创建Router对象, 并导出Routerconst router =  new Router({  routes,  mode: 'history', //默认使用的是hash, 这里替换为history方式没有#  linkActiveClass: 'active', //linkActiveClass在路由上设置默认激活样式; active是App.vue中定义的style})router.beforeEach((to, from, next) => {  document.title = to.matched[0].meta.title //获取meta.title  next() //释放router,类似filter效果  console.log(to) // 当存在children时,直接取meta是没有值的。通过打印发现,在matched数组中有要的meta.title})// 3. 将router对象传入的Vue实例中export default router
    //main.jsimport Vue from 'vue'import App from './App'import router from './router' //自动找router/index.jsVue.config.productionTip = false/* eslint-disable no-new */new Vue({  el: '#app',  router, //将router传给Vue类中的$router, 所以router 与 $router是同一个对象  render: h => h(App)})
  • $router 和 $route 说明

    1. $router 和 $route 是Vue类的原型中定义的:源码中的install.js中通过object.defineProperty(Vue.prototype, '$router', ...)完成​$router 和 $route的注册
    2. 所有自己创建的组件都继承自Vue类,所以都有$router 和 $route
    3. 将router (main.js中定义的)传给Vue类中的$router, 所以router 与 $router是同一个对象
    4. $route 表示当前被激活的route
    5. $router 与 $route 都来自Vue类中的this._routerRoot对象

5.2 案例tabbar

学会封装组件

image-20210723135925825

6 Vuex详解


6.1 Promise语法

// Promise基本使用new Promise((resolve, reject) => {    setTimeout(() => {        // 成功的时候调用resolve        resolve("Hello World");        // 失败的时候调用reject        // reject("error message");    }, 1000);})    .then((data) => {    // data是resolve传过来的数据    // 1.100行的处理代码    console.log(data);    console.log(data);    console.log(data);    console.log(data);    console.log(data);})    .catch((err) => {    // err是reject传过来的数据    console.log(err);});// Promise all 实现两个请求同时完成后再进行下一步操作Promise.all([    new Promise((resolve, reject) => {        setTimeout(() => {            resolve({ name: "why", age: 18 });        }, 2000);    }),    new Promise((resolve, reject) => {        setTimeout(() => {            resolve({ name: "kobe", age: 19 });        }, 1000);    }),]).then((results) => {    console.log(results);});

6.2 Vuex使用

Vuex就是为了提供这样一个在多个组件间共享状态的插件,Vuex扮演着大管家的角色(全局单例模式)

image-20210723142708210

  • vuex安装:npm install vuex --save
  • vuex使用步骤:1注册插件; 2创建对象并导出store; 3使用store

    //index.jsimport Vue from 'vue'import Vuex from 'vuex'import {INCREMENT} from '@/store/mutations-types.js'const moduleA = {    state: {      // 模块中的state调用:this.$store.state.a.name      name: 'zfcer'    },    mutations: {      // 模块中的mutations调用: this.$store.commit('mutations名字'), 调用方式不变      updateName(state, payload){        state.name = payload      }    },    actions: {      aUpdateName(context) {        setTimeout(() => {          console.log('模块内actions执行了')          // 模块内的actions只能调用模块内的mutations          context.commit('updateName', '模块内的actions调用了模块内的mutations')        })      }    },    getters: {      // 模块中的getters调用: this.$store.getters.fullName 调用方式不变。所以方法名不要与模块外的方法名重复      fullName(state){        return state.name + '111'      },      fullName2(state, getters){        return getters.name + '222'      },      fullName3(state, getters, rootState){        // rootState获取Root的state        return getters.fullName2 + rootState.counter      }    },     modules: {          }}// 1. 注册插件Vue.use(Vuex)// 2. 创建对象, 并导出export default new Vuex.Store({  state: {    // 共享变量    counter: 1000,    students: [      {id: 110, name: 'zfcer', age: 23},      {id: 111, name: 'best', age: 26},      {id: 112, name: 'one', age: 18},    ],    info: {      name: 'zfcer',      age: 23,      height: 1.87    }  },  mutations: {    // Vuex的store状态的更新唯一方式:提交Mutations    // 方法中是 默认传入state参数的    // mutations中提交参数可以通过payload提交对象    [INCREMENT](state){      state.counter++    },    decrement(state){      state.counter--    },    incrementCountOne(state, payload){      console.log(payload) //payload是一个对象    },    incrementCount(state, payload){      console.log(payload.cnt1 + payload.cnt2)      state.counter += payload.cnt1    },    addStudent(state, stu){      state.students.push(stu)    },    updateInfo(state){      // 直接修改info中已有的属性是响应式的,这是因为Vue对属性做了监听可以做到响应式      state.info.name = 'zfcer best'      // 直接在info中添加新属性不是响应式的      // state.info['address'] = '苏州'      // Vue.set(state.info, 'address', '苏州') //利用Vue.set实现响应式      // 直接删除info中属性不是响应式的      // delete state.info.age      // Vue.delete(state.info, 'age') //利用Vue.delete实现响应式    }  },  actions: {    // actions用来处理异步操作    // 方法一    // context上下文,可以理解为就是store对象    // payload传递参数    // aUpdateInfo(context, payload){    //   console.log("---------------")    //   setTimeout(() => {    //     context.commit('updateInfo')    //     console.log(payload.message)    //     payload.success() //执行回调函数    //   }, 1000)    // }    // 方法二    aUpdateInfo(context, payload){      return new Promise((resolve, reject) => {        setTimeout(() => {          context.commit('updateInfo')          console.log(payload)                    resolve('内部执行成功') //传递信息可以被外部then获取        }, 1000)      })    }  },  getters: {    // 与计算属性类似    powerCounter(state){      return state.counter * state.counter    },    more20Stus(state){      return state.students.filter(s => s.age >= 20)    },    more20StusLength(state, getters){      // 在getters中可以定义getters参数来获得getters中其他函数      return getters.more20Stus.length    },    moreAgeStus(state){       // 通过内部创建函数来获得moreAgeStus传过来的参数      // return function(age){      //   return state.students.filter(s => s.age >= age)      // }      return age => state.students.filter(s => s.age >= age)    }  },  modules: {    // 模块最终会被加载到state中,还是一个实体    a: moduleA  }})// 对象的解构const obj = {  name: 'zfcer',  age: 18,  height: 1.87}const {name, height, age} = obj// 数组解构const names = ['zfcer', 'best', 'one']const [name1, name2, name3] = names
    // main.jsimport Vue from 'vue'import App from './App'import router from './router'import store from './store'Vue.config.productionTip = false/* eslint-disable no-new */new Vue({  el: '#app',  router,  store, //3. 使用store  render: h => h(App)})
  • vuex项目结构

    image-20210724090545253

7 axios


  • 全局Axios
// 一、直接用axios是用的全局Axios// axios全局配置axios.defaults.baseURL = 'http://152.136.185.210:7878/api/m5'axios.defaults,headers.post['Content-Type'] = 'application/x-www-form-urlencoded'axios.defaults.timeout = 5000// 1. axios基本使用// 指定method的请求,默认是get请求axios({  // 局部配置  baseURL: 'http://152.136.185.210:7878/api/m5',  url: '/home/multidata',  method: 'get'}).then(res => console.log(res))// get请求axios.get('/home/multidata')// 带参数的get请求axios({  url: '/home/data',  // 针对get请求的参数拼接  params: {    type: 'pop',    page: 1  }}).then(res => console.log(res))// 2. axios并发使用// then中获取结果集axios.all([axios({  url: '/home/multidata',}), axios({  url: '/home/data',  // 针对get请求的参数拼接  params: {    type: 'sell',    page: 5  }})]).then(res => {  //合并后的结果  console.log(res)})// then中获取分别的结果axios.all([axios({  url: 'http://123.207.32.32:8000/home/multidata',}), axios({  url: 'http://152.136.185.210:7878/api/m5/home/data',  // 针对get请求的参数拼接  params: {    type: 'sell',    page: 5  }})]).then(axios.spread((res1, res2) => {  //两个异步请求分别的结果  console.log(res1)  console.log(res2)}))
  • 局部Axios
//  二、axios实例创建与使用 const instance = axios.create({  baseURL: 'http://152.136.185.210:7878/api/m5',  timeout: 5000,  headers: {    'Content-Type': 'application/x-www-form-urlencoded'  }})instance({  url: '/home/data',  method: 'get'}).then(res => {  console.log(res)}).catch(err => {  console.log(err)})
  • 封装axios:创建network文件夹-->request.js工具类,在main.js中调用封装的request
//--------------------request.js---------------------------import axios from 'axios'export function request1(config, success, failure){  // 1.创建axios实例  const instance = axios.create({    baseURL: 'http://152.136.185.210:7878/api/m5',    timeout: 5000  })  // 2.1.axios拦截器  instance.interceptors.request.use(config => {    console.log(config)    // (1)config中一些信息不符合服务器要求需要拦截    // (2)每次发送网络请求时,都希望在界面中显示一个请求的图标    // (3)某些网络请求(比如登录token),必须携带一些特殊信息    return config //释放拦截,如果不释放拦截就无法继续执行  }, err => {    console.log(err)  })   // 2.2.axios响应拦截  instance.interceptors.response.use(res => {    console.log(res)    // 做一些响应处理拦截    return res.data //只需要把data信息返回即可  }, err => {    console.log(err)  })  // 3.发送真正的网络请求  instance(config)  .then(res => {    // console.log(res);    success(res)  })  .catch(err => {    // console.log(err)    failure(err)  })}export function request2(config){  // 创建axios实例  const instance = axios.create({    baseURL: 'http://152.136.185.210:7878/api/m5',    timeout: 5000  })  // 发送真正的网络请求  instance(config.baseConfig)  .then(res => {    // console.log(res);    config.success(res)  })  .catch(err => {    // console.log(err)    config.failure(err)  })}export function request3(config) {  return new Promise((resolve, reject) => {    // 创建axios实例    const isntance = axios.create({      baseURL: 'http://152.136.185.210:7878/api/m5',      timeout: 5000    })    // 发送真正的网络请求    instance(config)    .then(res => {      resolve(res)    })    .catch(err => {      reject(err)    })  })}export function request4(config) { // 创建axios实例  const instance = axios.create({    baseURL: 'http://152.136.185.210:7878/api/m5',    timeout: 5000  })  // 发送真正的网络请求  return instance(config) //因为axios实例本身就是Promise}//-------------------main.js----------------------------// 三、axios封装import {request1, request2, request3, request4} from '@/network/request.js'request1({  url: '/home/multidata'}, res => {  console.log(res)}, err => {   console.log(err)})request2({  baseConfig: '/home/multidata',  success: function(res){    console.log(res)  },  failure: function(err){    console.log(err)  }})request3({  url: '/home/multidata'}).then(res => console.log(res)).catch(err => console.log(err))request4({  url: '/home/multidata'}).then(res => console.log(res)).catch(err => console.log(err))

8 项目实战


将本地项目与远程仓库关联起来:

git remote add origin https://github.com/zfcer/testmall.gitgit push -u origin master

8.1 项目基本设置

  • 项目结构

image-20210726010851211

  • 设置css样式和全局样式

    • initialize.css:normalize.css,可以在github中查看normalize.css
    • base.css:定义全局样式

    image-20210726011916492

  • vue.config.js 全局配置:起别名

    module.exports = {  configureWebpack: {    resolve: {      alias: {        'assets': '@/assets',        'common': '@/common',        'components': '@/components',        'network': '@/network',        'views': '@/views',      }    }  }}
  • .editorconfig 全局配置项目编辑

    root = true[*]charset = utf-8indent_style = spaceindent_size = 2end_of_line = lfinsert_final_newline = truetrim_trailing_whitespace = true

8.2 tabbar&导航栏组件

  • tabbar组件

    1. 导入写好的TabBar、TabBarItem、MainTabBar组件
    2. 安装vue-router,编写index.js路由,最后在mian.js中注入router
    3. 编写对应的views
    4. 在App.vue中引入组件,template中使用组件
  • 导航栏组件

    1. 创建通用组件NarBar, 定义三个slot(left、center、right)
    2. 在views中使用NarBar组件

8.3 首页 - 轮播图&推荐组件

  • axios封装
  • 轮播图

    1. 创建swiper通用组件
    2. 在home文件夹下创建childComps/HomeSwiper(使用swiper通用组件)
    3. 在Home.vue通过axios获取数据,在HomeSwiper中通过props获取数据并展示
    4. 在Home.vue中使用HomeSwiper组件
  • 推荐组件

    1. 在/src/views/home/childCops 创建 RecommendView.vue 组件
    2. 在Home.vue通过axios获取数据,在RecommendView中通过props获取数据并展示
    3. 在Home.vue中使用RecommendView组件

你可能感兴趣的:(vue.js)