vue2.0学习笔记黑马

前置知识

一、WebPack

实际开发中并不需要手动配置webpack

1、概念

webpack是前端项目工程化的具体解决方案

主要功能:提供了友好的前端模块化开发支持、以及代码压缩混淆、处理浏览器端javaScript的兼容性、性能优化等强大的功能

好处:提高开发效率和项目可维护性

2、创建webpack项目

  • 新建项目空目录需要英文路径,并允许npm init -y 命令,初始化包管理配置文件 package.json

  • 新建src源代码目录

  • 新建src->index.html首页和src->index.js脚本文件

  • 运行npm install jquery -S命令,安装jQuery

  • 通过ES6模块化的方式导入jQuery

在项目中配置webpack

module.exports={
    mode:'development'//mode用来指定构建模式,可选值有development和production,项目上线时得改成production
}
  • 在package.json的scripts节点下,新增dev脚本如下:
"scripts":{
	"dev":"webpack"//script节点下的脚本,dev属性名字可以自定义,其值为脚本名,可以通过npm run执行脚本,例如npm run dev
}
  • 在终端中运行npm run dev 命令,启动webpack进行项目的打包构建

​ 成功后会出现一个dist文件夹里面有main.js文件,其代码并没有被压缩

  • 在html中用script导入main.js文件夹
  • 之后便可以运行代码了(每次更改代码后需要nmp run dev)

webpack代码压缩

将webpack.config.js中的mode改为production(项目上线时才为production)

3、webpack.config.js文件

在执行npm run dev后,运行webpack脚本前会读取这个文件

在webpack 4.x和5.x的版本中,有如下默认约定

  • 默认的打包入口文件为src->index.js
  • 默认的输出文件路径为dist->main.js

注意:可以在webpack.config.js中修改打包的默认约定

entry和output

在webpack.config.js配置文件中通过entry节点指定打包的入口,通过output节点指定打包的出口

const path=require('path')//导入path模块

module.exports={//向外导出一个webpack的配置对象
    entry:path.join(__dirname,'./src/index.js'),//打包入口文件的路径
    output:{
    	path:path.join(__dirname,'./dist'),//输出文件的存放路径(指定生成文件要存放的目录)
        filename:'bundle.js'//输出文件的名称(指定生成文件的名称)
	}
    mode:'development'
}

4、webpack插件

注意:下面两个插件以理解为主,之后会用脚手架自动配置

通过安装和配置第三方的插件,可以拓展webpack的能力,从而让webpack用起来更加方便,最常用的webpack插件有如下两个:

  • webpack-dev-server

    • 类似于node.js阶段用到的nodemon工具

    • 每当修改了源代码,webpack会自动进行项目的打包和构建

    • 安装命令npm install webpack-dev-server -D

    • //package.json配置修改
      "scripts":{
          "dev":"webpack serve"
      }
      
    • 再次运行npm run dev (此时生成的main.js会放到内存中而不是物理磁盘中)

    • 若出现Unable to load ‘@webpack-cli/serve’ command这种错误可以先运行npm install webpack-cli -D 再执行npm run dev

    • 修改代码后终端中会反应,但是网页中没反应

    • cannot get错误可以修改为下面的devSercer中的static为"./‘’

    • const path=require('path')//导入path模块
      module.exports={
          mode:'development',
          entry:path.join(__dirname,'./src/index.js'),//打包入口文件的路径
          output:{
          	path:path.join(__dirname,'./dist'),//输出文件的存放路径(指定生成文件要存放的目录)
              filename:'main.js'//输出文件的名称(指定生成文件的名称)
      	},
          devServer: {
      		static: "./"
      	}
      }
      
    • 在html中加载和引用生成在内存中的main.js

    • <script src="/main.js"></script>
      
    • 之后打开http://localhost:8080/点击网页中的src即可看到效果

  • html-webpack-plugin

    • webpack中的HTML插件(类似模板引擎插件)

    • 可以通过此插件自封之index.html页面的内容

    • 安装此插件后可以直接进入index首页(是复制出来的在内存中的html文件)

    • 会自动注入内存中的main.js到html(我们就不必手动引入文件)

    • 安装命令npm install html-webpack-plugin -D

    • //导入插件
      const HtmlPlugin=require('html-webpack-plugin')
      //创建实例对象
      const htmlPlugin=new HtmlPlugin({
          template:'./src/index.html',//原文件存放路径
          filename:'./index.html'//指定生成文件存放路径
      })
      module.exports={
      	mode:'development',
          plugins:[htmlPlugin],//通过plugins节点,使htmlPlugin插件生效
      }
      

5、devServer节点

在webpack.config.js配置文件中,可以通过devServer节点对webpack-dev-server插件进行更多的配置

devServer{
    open:true,//首次打包成功后自动打开浏览器
    port:8080,//修改端口号
    host:"127.0.0.1",//指定运行的主机地址
}

6、loader

在实际开发中,webpack默认只能处理.js后缀文件,其它的非js后缀文件模块处理不了,需要loader加载器才可以正常打包

loader加载器作用:协助webpack打包处理特定的文件模块,比如:

  • css-loader可以打包处理.css相关文件
  • less-loader可以打包处理.less相关文件
  • babel-loader可以打包处理webpack无法处理的高级js语法

在webpack中一切皆模块,都可以通过es6语法在js中导入模块包括css文件

import "./index.css"

因为webpack无法处理css等模块,所以需要配置loader

配置css的loader

  • 运行npm i [email protected] [email protected] -D命令,安装处理css文件的loader

  • 在webpack.config.js的module->rules数组中,添加loader规则如下

  • module:{
    rules:[{test:/\.css$/,use:["style.loader",'css.loader']}]
    }
    
  • 其中test表示匹配的文件类型,use表示队友要调用的loader

注意:

  • use数组中指定的loader顺序是固定的
  • 多个loader的调用顺序是:从后往前调用

配置url-loader

  • 运行npm i [email protected] [email protected] -D命令

  • 在webpack.config.js中

  • rules:[{test:'/\.jpg|png|gif$/',use:'url-loader?limit=22229'}]
    

    ?之后是loader的参属项

  • limit用来指定图片的大小单位是字节

  • 只有<=limit大小的图片才会被转为base64格式的图片

配置babel-loader

  • webpack有时无法处理高级的js语法,需要babel-loader来处理

  • npm i [email protected] @babel/[email protected] @babel/[email protected] -D

  • {test:/\.js$/,use:'babel-loader',exclude:/node_modules/}
    
  • 在项目根目录下,创建名为babel.config.js的配置文件,定义babel的配置项如下

  • module.exports={
    	plugins:[['@babel/plugin-proposal-decorators',{legacy:true}]]
    }
    

7、base64图片

base64图片可以防止发起一些不必要的网络请求

8、打包发布

在package.json文件的scripts节点下,新增build命令如下

"scripts":{
	"div":"webpack serve",
	"build":"webpack --mode production"
}

–mode是一个参数项,用来指定webpack的运行模式,production表示生产环境,会对打包生产的文件进行代码压缩和性能优化

build中只用webpack去掉serve会将生成文件到磁盘而不是内存

  • npm run build (打包发布项目)

注意:通过–mode指定的参数项,会覆盖webpack.config.js中的model选项来打包

9、优化图片和js文件路径

优化js文件路径

output:{
path:path.join(__dirname,'dist'),
//生成的文件名,为其放入js文件夹中方便分辨和归类
filename:'js/main.js'
}

优化图片路径

webpack.config.js中的url-loader配置项

//outputPath修改图片打包路径
{
 test:/\.jpg|png|gif$/,
 use:'url-loader?limit=470&outputPath=images'
}

10、自动清理dist目录下的旧文件

安装clean-webpack-plugin插件

  • npm install clean-webpack-plugin -D

  • //导入
    const {CleanWebpackPlugin}=require{'clean-webpack-plugin'};
    
    moudel.export={
        ///........
    	plugins:[htmlPlugin,new CleanWebpackPlugin()]
        //.....
    }
    

11、Source Map解决报错位置不匹配

浏览器报错的行号是生成文件里的行号

因此需要配置SourceMap

SourceMap就是一个信息文件,存储着位置信息,也就是说,该文件中存储着压缩混淆后的代码所对应的转换前的位置

有了它,出错的时候,除错工具将直接显示原始代码,而不是转换后的代码。

  • 在webpack.config.js中添加如下配置即可

  • module.exports={
    devtool:'eval-source-map',
    }
    

发布项目前要把sourcemap关闭,防止源代码被泄露

在实际发布的时候建议把值改为:nosources-source-map,即照顾了调试代码的体验又具有安全性

VUE2.0

工程化的前端开发

  • 模块化(js模块化、css模块化、资源模块化)
  • 组件化(现有UI结构、样式、行为的复用)
  • 规范化(目录结构的划分、编码规范化、接口规范化、文档规范化、Git分支管理)
  • 自动化(自动化构建、自动部署、自动化测试)

一、Vue简介

1.介绍

vue是一套用于构建用户界面的前端框架

框架是一套现成的解决方案,程序员只能遵守框架的规范,去编写自己的业务功能

vue的指令、组件、路由、Vuex、vue组件库

2.vue的特性

  • 数据驱动视图

好处:当页面数据变化时,页面会自动重新渲染

注意:数据驱动视图是单向的数据绑定

  • 双向数据绑定

在填充表单时,双向数据绑定可以辅助开发者在不操作DOM的前提下,自动把用户填充的内容同步到数据源中

好处:开发者不再需要手动操作DOM元素,来获取表单元素最新的值

二、MVVM

MVVM是vue实现数据驱动视图和双向数据绑定的核心原理。MVVM指的是Model、View和ViewModel,它把每个HTML页面拆分成了这三个部分:

在MVVM概念中:

  • Model表示当前页面渲染时所依赖的数据源
  • View表示当前页面所渲染的DOM结构
  • ViewModel表示vue的实例,它是MVVM的核心

vue2.0学习笔记黑马_第1张图片

三、vue的基本使用

1.基本使用步骤

①导入vue.js的script脚本文件

②在页面中声明一个将要被vue所控制的DOM区域

③创建vm实例对象(vue实例对象)

<body>
    
    <div id="app">
        {{username}}}
    div>
    
    <script src="./lib/vue-2.6.12.js">script>
    
    <script>
    	//创建vue实例对象
        const vm=new Vue({
            //el属性表示当前vm实例要控制那个区域,接收的值是一个选择器
            el:'#app',
            //data对象就是要渲染的数据
            data:{
                username:'zhangsan'
            }
        })
        
    script>
body>

vue2.0学习笔记黑马_第2张图片

四、vue的指令

1.指令的概念

指令是vue为开发者提供的模板语法,用于辅助开发者渲染页面的基本结构

vue中的指令按照不同的用途可以分为6大类:

  • 内容渲染指令 v-text,{{}},v-html
  • 属性绑定指令 v-bind (
  • 事件绑定指令 v-on (@)
  • 双向绑定指令 v-model
  • 条件渲染指令 v-if,v-else,v-else-if,v-show
  • 列表渲染指令 v-for

2.内容渲染指令

内容渲染指令用来辅助开发者渲染DOM元素的文本内容,常用的内容渲染指令有如下三个:

  • v-text
  • {{}}
  • v-html

v-text

  • 缺点:会覆盖标签原本内容,所以几乎不用
//把username对应的值渲染到p标签
<p v-text="username">
p>
//把gender对应的值,渲染到p标签中
//默认的文本“性别”会被gender的值覆盖
<p v-text="gender">
    性别
p>

{{}}

插值表达式(Mustache)

<p>
    姓名:{{username}}
    性别:{{gender}}
p>
  • 只是占位符,不会覆盖原有内容

  • 不会渲染html标签

  • 只能用于内容节点,不能用于属性值

v-html

  • 可以渲染html标签
//info:"<h4>hello world!h4>"
<p v-html="info">    
p>

3、属性绑定指令

v-bind:

<div id="app">
    <input type="text" v-bind:placeholder="tips">
    <img v-bind:src="photo">
div>
<script>
    const vm=new Vuew({
        el:'#app',
        data:{
            tips:"请输入用户名",
        	photo:'http://image.....'
        }
    })
script>

需要动态改变的属性就在属性前写 v-bind:

可以简写为’ : ’

之后属性值就填data中的变量名

4、Javascript表达式

在vue提供的模板渲染语法中,除了支持绑定简单的数据值之外,还支持javascript表达式的运算

{{number+1}}

{{ok?'Yes':'No'}}

{{message.split('').reverse().join('')}}

<div v-bind:id="'list-'+id">div>

v-bind属性绑定期间,如果绑定内容需要进行动态拼接,则字符串的外面应该包裹单引号,否则会被认为是data中的变量

5、事件绑定指令

v-on:

  • 可以简写为@
  • 事件处理函数传参可以用()传参
<div id="app">
    <h3>
    count值为:{{count}}
h3>
<button v-on:click="add(1)">
    +1
button>
    
div>
<script>
	const vm=new({
        le:"#app",
        data:{
            count:0
        },
        //methods中定义事件处理函数
        methods:{
            add(n){
                //这里的this相当于vm
                //html中可以用()传参,不传参可以不加小括号
                this.count+=n
            }
        }
    })
script>

@click,@input,常见的原生事件都可以绑定

$event

  • 绑定事件时如果没有传参,则函数接收的第一个参数为e也就是事件
  • 若传参了,则需要传入实参$event然后对应接收的形参就是e
<div id="app">
    <h3>
    count值为:{{count}}
	h3>
<button v-on:click="add(1,$event)">
    +1
button>
    
div>
<script>
	const vm=new({
        le:"#app",
        data:{
            count:0
        },
        //methods中定义事件处理函数
        methods:{
            add(n,e){
                this.count+=n
                console.log(e)
                if(this.count%2===0){
                    //偶数
                    e.target.style.backgroundColor="red"
                }
                else{
                    e.target.style.backgrounColor=''
                }
            }
        }
    })
script>

事件修饰符

①**.prevent**

起到e.preventDefault作用

加在事件绑定之后

<a href="src" @click.prevent="show">a>

②**.stop**

阻止事件冒泡

起到e.stopPropagation的作用

按键修饰符

在监听键盘事件时,我们经常需要判断详细的按键,此时可以为键盘相关事件添加按钮修饰符


<div id="app">
    <input type="text" @keyup.esc="clearInput">
    
div>
<script>
	const vm=new({
        le:"#app",
        data:{
            
        },
        //methods中定义事件处理函数
        methods:{
            clearInput(e){
                console.log("触发esc键")
                e.target.value=""
            }
        }e
    })
script>

6、双向数据绑定指令

结合表单使用

v-model

将表单中的value替换成v-model即可

<div id="app">
    <input type="text" v-model="username">
    <p>
        用户的名字:{{username}}
    p>
    
div>
<script>
	const vm=new({
        le:"#app",
        data:{
            username:'zhangsan'
        },
        //methods中定义事件处理函数
        methods:{
            clearInput(e){
                console.log("触发esc键")
                e.target.value=""
            }
        }e
    })
script>

v-model是双向绑定,而v-bind是单向绑定

且使用v-model后input表单的value属性就没有意义了

只有表单元素才能使用v-model

input\textarea\select\

v-model的修饰符

修饰符 作用 示例
.number 自动将用户的输入值转为数值类型
.trim 自动过滤用户输入的首尾空白字符
.lazy 在”change“时而非”input“时更新,即不会每次输入一个字符就同步而是回车后同步

7、条件渲染指令

用来辅助开发者按需控制DOM的显示和隐藏。条件渲染指令有如下两个分别是

  • v-if
    • 动态增删元素,刚进入页面时某些元素默认不展示,且后期可能不需展示时if性能更佳
    • v-else和v-else-if可以配合v-if使用
  • v-show
    • 利用display来控制显示,频繁改变时性能更佳
<div id="app">
    
    <p v-if="flag">
        这是被v-if控制的元素
    p>
    <p v-show="flag">
        这是被v-show控制的元素
    p>
div>
<script>
	const vm=new({
        le:"#app",
        data:{
            flag:true
        },
        //methods中定义事件处理函数
        methods:{
          
        }
    })
script>

8、列表渲染指令

v-for

需要以item in list的形式使用

需要索引的时候可以(item,index) in list

  • 一定需要绑定key属性,尽量用唯一的id来绑定且必须是字符串或者数字,一定不要用index来绑定(index的值不具有标识性)
<div id="app">
    <li v-for="(item,index) in list"
        key="item.id">
    	索引:{{index}} id:{{item.id}} 姓名:{{item.name}}
    li>
    
div>
<script>
	const vm=new({
        le:"#app",
        data:{
          list:[
          	{id:1,name:'zs'},
          	{id:2,name:'ls'}
          ]
        },
        //methods中定义事件处理函数
        methods:{
          
        }
    })
script>

五、过滤器

注意:过滤器在vue3中已经被删除,这里只要会一点基础就行

过滤器(Filters)是vue为开发者提供的功能,常用于文本的格式化,过滤器可以用在两个地方:插值表达式v-bind属性绑定

5.1基本用法

过滤器应该被添加在javascript表达式的尾部,由”管道符“进行调用,

<div id="app">
    
	<p>
   	{{message|capi}} 
	p>
	
	<div v-bind:id="rawId | formatid">div>
div>

<script>
	const vm=new Vue({
        el:'#app',
        data:{
            message:'hello vue.js'
        }
        //过滤器本质是一个函数,需要被定义到filter节点之下
        filter:{
			capi(val){//val永远是管道符前面的值
  			    const first=val.charAt(0).toUpperCase()//取第一个字符并变大写
                const other=val.slice(1)//从1开始截取字符串
        		return first+other
   			}        
    	}
    })
script>

5.2私有过滤器和全局过滤器

1、私有过滤器

filter中的过滤器为私有过滤器

只有当前vm控制的标签区域才能使用私有的过滤器

2、全局过滤器

一般都定义全局过滤器

当全局与私有过滤器名冲突,则按就近原则取私有过滤器

//在vm对象外按下面形式定义
Vue.filter('过滤器名',(val)=>{
	//处理程序
	return 结果
})

定义格式化时间的过滤器

Vue.filter('dataformat',function(time){
//1、对time进行格式化处理得到YYYY-MM-DD HH:mm:ss格式
//2、把格式化的结果return出去
//这里使用dayjs库来导入时间
//直接调用dayjs()得到的是当前时间
//dayjs(给定的时间)得到指定的日期
const timestr=dayjs().format('YYYY-MM-DD HH:mm:ss')
})

5.3连续调用多个过滤器

{{time|format|xxx|yyy|zzz}}

将值不断的往后传,最后一个return的值就是结果

5.4filter可以通过小括号传参

但是传入的参数在接收时会从形参第二位开始接收,第一位默认是管道符前的值

六、侦听器

1、什么是watch侦听器

允许开发者监视数据变化,从而针对数据变化做特定的操作,监听的是data里数据值的变化

2、基本用法

<div id="app">
    <input v-model="username" type="text">
div>
<script>
    const vm=new Vue({
	el:'#app',
	data:{username:''},
        
	watch:{//定义侦听器,
        //1、函数形式侦听器,用相关数据名作为方法名
		username(newVal,oldVal){
			console.log(newVal,oldVal)
		}
        //2、对象格式的侦听器,相关数据名作对象名
        username:{
			handler(newVal,oldVal){//handler是固定写法
			}
		}
	}
})
script>

典型应用场景:判断用户名是否被占用,若占用则清除并警告

3、immediate选项

  • 函数形式的侦听器不会在初次进入页面时触发

  • 对象格式的侦听器可以通过immediate选项,让侦听器自动触发

watch:{
	username:{//对象格式的侦听器
		handler(newVal,oldVal){//handler是固定写法
		
		},
        immediate:true //true表示初次进入就触发,默认为false
	}
}

4、deep选项-深度侦听

对象里的数据不会被函数形式的侦听器所侦听

可以使用对象格式,并用deep选项来侦听每一个对象中的数据

data:{
	info:{
	username:''
	}
}
watch:{
 info:{
 	handler(newVal,oldVal){
 		//..
 	},
 	deep:true//开启深度侦听,就能侦听对象中的任何属性的变化
 },
 'info.username'(){
 	//也可以用这种方法来侦听具体子属性变化,注意需要单引号
 }
}

注意:深度侦听会遍历数据对象的所有嵌套属性,如果是大型数据需要慎用,以免造成性能上的不足

七、计算属性

1、介绍

计算属性的值是通过一系列运算后得到的属性值

这个动态计算出来的属性值可以被模板结构或methods方法使用

动态改变背景颜色

<div :style="{backgroundColor:`rgb(${r},${g},${b})`}">
    颜色:{{rgb(${r},${g},${b})}}
div>

这种用字符串拼接的形式来动态改变虽然实现了效果,但是当其中一个rgb改成rgba时其余的rgb也得改,这就非常没效率,因此需要计算属性

data:{
r:0,g:0,b:0
},
computed:{//存放所有计算属性
	//计算属性需要定义为方法形式
	//在vm对象中methods里可以用例如this.rgb调用
	//html模板中可以直接调用,
	//依赖的数据源变化也会引起计算属性的变化
	rgb(){
		return `rgb(${this.r},${this.g},${this.b})`
	}
}
//实际应用
{{rgb}}

补充:axios

axios是一个专注于网络请求的库

npm -i axios -S

基本语法

import axios from 'axios'
axios({
	method:'请求的类型',
	url:'请求的url地址',
    //Get参数,按需
    params:{}
    //post请求体参数,按需
    data:{}
	//调用axios返回的是promise对象,可以用.then
}).then(result)=>{
	//.then用来指定请求成功后的回调函数
	//形参中的result是请求成功后的结果
}

axios在请求到数据之后,给真正的数据做了一层外包装

data属性里面才是正真的数据

async和await,以及对返回结果解构赋值得到真正数据

vue2.0学习笔记黑马_第3张图片

解构赋值时在变量名后面用:可以更改变量名

例如

{data:res}=result

则得到结果的变量名为res

axios.get

const {data:res}=axios.get("url地址",
                          {
    params:{请求体数据}
    
})

axios.post

const {data:res}=axios.post('url',{post请求体数据})

八、vue-cli

1、单页面应用程序

**单页面应用程序(SPA)**顾名思义指一个web网站中只有唯一一个HTML页面,所有的功能与交互都在这唯一的一个页面内完成

2、vue-cli

vue-cli是vue.js开发的标准工具。简化了程序员基于webpack创建工程化的vue项目的过程

3、安装和使用

vue-cli是npm上的一个全局包,使用npm install命令,即可方便的把它安装到自己的电脑上:

npm install -g @vue/cli

基于vue-cli快速生成工程化的Vue项目:

vue create 项目名称

vue2.0学习笔记黑马_第4张图片

建议选择最后一项,可以自定义安装需要的东西

vue2.0学习笔记黑马_第5张图片

然后选择2.x即vue2.0

vue2.0学习笔记黑马_第6张图片

vue2.0学习笔记黑马_第7张图片

  • 创键完成项目后cd 到更目录
  • 然后npm run serve

4、src目录

  • assets文件夹存放静态资源文件,比如图片、css样式表

  • components文件夹存放程序员封装的可复用组件

  • main.js是项目的入口文件,整个项目的运行需要先运行main.js

  • App.vue是项目的根组件,可以清空后重写

5、vue项目的运行流程

在工程化项目中,vue要做的事情很单纯,通过main.jsApp.vue渲染到index.html的指定区域中

6、main.js

//导入Vue这个包,得到Vue构造函数
import Vue from 'vue'
//导入App.vue根组件,将来要把App.vue中的模板结构渲染到HTML页面中
import App from './App.vue'

Vue.config.productionTip = false
//创键Vue实例对象
new Vue({
    //将render函数指定的组件渲染到html页面中
  render: h => h(App),
    
}).$mount('#app')

在index.html中id为app的div在渲染时会被App.vue中的标签替换掉,其相当于成了一个占位符(render指定的结构会替换掉el指定的结构,这里的el用$mount方法替代,两种方法作用一样)

  • APP.vue用来编写带渲染的模板结构
  • index.html中需要预留一个el区域(el可以用$mount()方法代替)
  • main.js把App.vue渲染到了index.html所预留的区域中

九、组件的基本使用

声明一个模板结构,比如Test.vue

//Test.vue
<template>
	<div>
        <h3>
            这是一个自定义的模板
        h3>
    div>
template>

修改main.js

//main.js
import Vue from 'vue'
import Test from './Test.vue'

Vue.config.productionTip = false

new Vue({
  render: h => h(Test),
}).$mount('#app')

1、组件化开发

根据封装的思想,把页面上可重用的UI结构封装为组件,从而方便项目的开发和维护

2、vue中的组件化开发

vue是一个支持组件化开发的

vue中规定:组件的后缀名是.vue之前接触到的App.vue本质上就是一个Vue组件。

3、Vue组件的三个组成部分

每个.vue组件都由三部分组成:

  • template->组件的 模板结构
  • script->组件的 JS行为
  • style->组件的 样式

vue中分别对应template,script,style标签,一般按照此顺序写,且script中必须要有export defualt{} js代码写在括号中

注意:template中只能有一个根div

<template>
	<div>
        自定义模板 
        <h1>
            用户:{{username}}
        h1>
        <button @click="changeName">
            修改用户名
        button>
    div>
template>

<script>
    //固定写法,默认导出
	export default{
        //组件中的data必须是一个函数,return一个数据对象
        data(){
            return {
                username:'zs'
            }
        },
        //组件中定义方法
        methods:{
            changeName(){
                this.username="ls"
            }  
        },
        //当前组件中的侦听器
        watch:{
        
    	},
        computed:{
            //计算属性
        },
        filter:{
            //过滤器
        }
    }
script>

<style>
    div {
        background:'red';
    }
style>

4、组件之间的父子关系

组件被封装好后彼此之间是相互独立的,不存在父子关系

在使用组件时,根据彼此之间的嵌套关系,形成了父子关系、兄弟关系

4.1使用组件的三个步骤

  • 1、在当前组件/根组件中使用import语法导入需要的组件
import xxx from '@components/xxx.vue'
  • 2、在当前组件/根组件中的script中的components节点注册组件
export default{
	components:{
        xxx
    }
}
  • 3、在当前组件/根组件中以标签形式使用刚才注册的组件
<div id="app">
	<xxx>xxx>    
<div>

4.2通过components注册的是私有子组件

即被注册的组件在哪个组件中注册则只能在该组件中使用

4.3注册全局组件

在main.js中通过Vue.component()方法,

import xxx from '@/components/xxx.vue'

Vue.component("注册名称",xxx)//注册名称可以起任意名,但建议以大写开头

5、组件的props

props是组件的自定义属性,在封装通用组件的时候,合理的使用props可以极大提高组件的复用性

export default{
	//props是自定义属性,允许使用者通过自定义属性,为当前组件指定初始值
	props:[
		'自定义属性1',
        '自定义属性2',
        ...
	],
}

vue2.0学习笔记黑马_第8张图片

通过调用组件并给自定义属性赋值可以传值给props

<xxx a="9">xxx>

Tip:结合v-bind可以使传入的数值为数值型而不是原来的字符串型(实质是使引号中的内容变为js代码)

<xxx :a="9">xxx>

props的数据可以直接在html模板结构中被使用

5.1props中的数据只读,不能修改

可以将从props读取的数据传入到data的变量中

比如props中有个变量init,data中有个变量count则可以这样赋值

data(){
	return{
		count:this.init
	}
}

如此可以修改data中的值而不必修改props的值尚且其值也并不能被修改。

5.2props的default默认值

可以设置props的默认值

语法:

export default{
	props:{
		a:{
			//用default属性定义属性的默认值
			default:0
		}
	}
}

5.3props的type值类型

在声明自定义属性值时,可以通过type来定义属性的值类型

export default{
	props:{
		init:{
			//default定义属性的默认值
			default:0,
			//用type属性定义属性的值类型
			//如果传递过来的值不符合此类型,则会在终端报错
			type:Number
		}
	}
}

5.4props的required必填项

 export default{    
     props:{        
         init:{            
             //default定义属性的默认值            
             default:0,            
             //用type属性定义属性的值类型            
             //如果传递过来的值不符合此类型,则会在终端报错            
             type:Number,
             //required:true表示该自定义属性必须填写
             required:true
         }    
     }
 }

6、组件之间的样式冲突问题

默认情况下,写在vue组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。

导致组件之间样式冲突的根本原因是:

  • 单页面应用程序中,所有组件的DOM结构,都是基于唯一的index.html页面进行呈现的
  • 每个组件中的样式,都会影响整个index.html页面中的DOM元素

6.1解决方法

style标签的scoped属性

只要给当前组件的style标签加上scoped属性就可以解决

<style scoped>
style>

6.2使用deep修改子组件中的样式

加上deep可以修改子组件中样式

/deep/ h5{
	color:red;
}

当使用第三方组件库的时候可以使用该方法在父组件中修改引入的组件的样式

十、组件的生命周期

1、生命周期&生命周期函数

生命周期:是指一个组件从创键->运行->销毁的整个阶段,强调的是一个时间段

生命周期函数:是由vue框架提供的内置函数,会伴随着组件的生命周期,自当按次序执行

vue2.0学习笔记黑马_第9张图片

vue2.0学习笔记黑马_第10张图片

vue2.0学习笔记黑马_第11张图片

2、创键阶段生命周期函数

vue2.0学习笔记黑马_第12张图片

  • beforeCreate()函数调用时。组件的props/data/methods尚未创键,都处于不可用状态,所以此刻该函数并不能做什么事情,因此一般不用

  • created()函数调用时,组件的props/data/methods已经初始化,都处于可用阶段,但是组件的模板结构尚未生成,此函数十分重要,可在此阶段发起ajax请求,来获取数据并转存到data

vue2.0学习笔记黑马_第13张图片

vue2.0学习笔记黑马_第14张图片

  • beforeMount()函数,将要把内存中编译好的HTML结构渲染到浏览器中。此时浏览器中还没有当前组件的DOM结构,此方法一般不会用
  • **mounted()**函数,此刻已经把内存中的HTML结构成功渲染到了浏览器中,此时已经包含了当前组件的dom结构,可以最早操作DOM元素

3、运行阶段生命周期函数

vue2.0学习笔记黑马_第15张图片

  • beforeUpdate()函数,只有数据变化的时候才会触发。此时UI结构还是没有更新数据前的UI结构
  • updated()函数,此时已经完成了最新的DOM结构的渲染

4、销毁阶段生命周期函数

vue2.0学习笔记黑马_第16张图片
  • beforeDestroy()函数
  • destroyed()函数

十一、组件之间的数据共享

1、组件之间的关系

两种最常见的关系

  • 父子关系
  • 兄弟关系

2、父子组件数据共享

2.1父向子传递

props自定义属性

//父组件
<Son :msg="message" :user="userinfo">Son>

data(){
	return{
		message:'hello vue.js',
		userinfo:{name:'zs',age:20}
	}
}
//子组件
<template>
	<div>
        <h5>
            Son组件
        h5>
        <p>
            父组件传递过来的msg值为:{{msg}}
        p>
        <p>
            父组件传递过来的user值为:{{user}}
        p>
    div>
template>

props:['msg','user']

2.2子向父传递

子组件向父组件共享数据使用自定义事件

//子组件
export default {
	data(){
		return {count:0}
	},
	methods:{
		add(){
			this.count+=1
			//修改数据时通过$emit()触发自定义事件
			this.$emit('numchange',this.count)
		}
	}
}
//父组件
<son @numchange="getNewCount"></
son>
export default{
	data(){
        return {countFromson:0}
        
    },
	methods:{
        getNewCount(val){
            this.countFromSon=val
        }
    }
}

3、兄弟组件数据共享

EventBus

1、定义一个eventBus.js文件,导出一个空的Vue实例

//eventBus.js
import Vue from 'vue'
//向外共享Vue的实例
export default bus=new Vue()

2、发送方用emit发送

//兄弟组件A(数据发送方)
import bus from './eventBus.js'

export default{
    data(){
        return {
            msg:'hello'
        }
    },
    methods:{
        sendMsg(){
            bus.$emit('share',this.msg)
        }
    }
}

3、接收方用on接收

//兄弟组件B(数据接收方)
import bus from './eventBus.js'

export default{
    data(){
        return {
            msgFrombrother:''
        }
    },
    created(){//可以在created生命周期函数中调用
        bus.$on('share',val=>{
            this.msgFromLeft=val
        })
    }
}

十二、ref引用DOM元素

ref用来辅助开发者在不依赖于jQuery的情况下获取DOM元素或组件的引用。

每个vue的组件实例上,都包含一个** r e f s ∗ ∗ 对象,里面存储着对应的 D O M 元素或组件的引用。默认情况下,组件的 ∗ ∗ refs**对象,里面存储着对应的DOM元素或组件的引用。默认情况下,组件的** refs对象,里面存储着对应的DOM元素或组件的引用。默认情况下,组件的refs**指向一个空对象。

<template>
	<h1 ref="myh1">
        组件
    h1>
    <button @click="show">
        点我变红
    button>
template>
<script>
	export default{
        data(){
            return {
                
            }
        },
        methods:{
        	show(){
               //首先需要在标签上取ref的名字 
                console.log(this.$refs.myh1)//获取对应名字的dom并打印
              this.$refs.myh1.style.color="red"
            }
    	}
    }
script>

十三、ref引用组件

<template>
    {{count}}
	<xxxx ref="myComponent"/>
    <button @click="show">
        
    button>
template>
<script>
	import xxxx from "@components/xxxx.vue"
    export default{
        data(){
            return {
              
            }
        }
        components:{
            xxxx
        }
    methods:{
        show(){
            console.log(this.$refs.myComponent)
            this.$refs.myComponent.该组件方法/属性
            //得到该组件中可以直接使用该组件方法和属性
        }
    }
    }
script>

tips: this.$nextTick(callback)方法

延迟到DOM更新后调用callback

this.$nextTick(()=>{
	//....
})

有利于处理因为DOM没更新导致的undifined

十四、数组中的方法

foreach循环

some循环

every循环

reduce的基本使用

十五、动态组件

1、component标签

vue提供了一个内置的组件,专门用来实现动态组件的渲染,相当于一个占位符

is中填写要渲染的子组件名,可以用:绑定来实现动态组件

<template>
	<div>
        <component is="组件名">component>
    div>
template>

<template>
	<div>
        <component :is="comName">component>
    div>
template>
<script>
    import Cart from"./components/Cart/Cart.vue"
	export default{
        data(){
            return {
                comName:'Cart'
            }
        },
        components:{
            Cart
        }
    }
script>

注意:component切换组件时原先组件会被销毁

2、使用keep-alilve保持状态

防止切换时销毁组件,会将组件缓存

<keep-alive>
	<component :is="comName">component>
keep-alive>

3、keep-alive对应的生命周期函数

当组件被缓存时,会自动触发组件的deactivated生命周期函数。

当组件被激活时,会自动触发组件的activated生命周期函数

组件第一次激活时会触发created函数,但之后的激活不会再触发

4、keep-alive的include属性

include属性用来指定:只有名称匹配的组件会被缓存。多个组件名之间用逗号分隔

<keep-alive include="component1,component2">
    <component :is="comName">component>
keep-alive>

5、keep-alive的exclude

exclude用来指定:名称匹配的组件不会被缓存,用法与include一样

注意:它不能与include同时使用

十六、插槽

1、介绍

插槽是vue为组件的封装者提供的能力。允许开发者在封装组件时,把不确定的,希望由用户指定的部分定义为插槽

vue2.0学习笔记黑马_第17张图片

//com组件
<template>
	<div>
        
        <slot>slot>
    div>
template>
<template>
	<div class="app">
        <com>
        	<p>
                这是在com组件的内容区域,声明的p标签
            p>
        com>
    div>
template>

2、v-slot指令

vue规定每一个插槽都有一个name名称

如果省略了name属性则会有默认名称叫做default

默认情况下在使用组件的时候提供的内容都会填充到default的插槽中

//com组件
<template>
	<div>
        
        <slot name="default">slot>
    div>
template>

可以指定内容放入名为何值得插槽,但需要template标签,template标签是虚拟的元素不会被渲染

<template>
	<div class="app">
        <com>
        	<template v-slot:default>
            	<p>
                    将p标签放入com组件的名为default的插槽中
                p>
            template>
        com>
    div>
template>

3、v-slot的简写形式以及插槽的后备内容

v-slot: 可以简写为#