vuejs、vue CLI、webpack笔记

一、vue.js语法

1. 开始操作

1.1 安装vue.js

官网 下载js文件,添加到项目文件夹中

1.2 使用vue

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>title</title>
	</head>
	<body>
		<div id='app'>{{message}}</div> <!-- 双括号mustache(胡须)语法 -->
		<script src='../js/vue.js'></script>
		<script>
			//声明式编程,区别于document.getElementById('app')这种命令式编程
			const app = new Vue({
				el:'#app',//用于挂载要管理的元素
				data:{//初始化数据
					message:'vue 我来了'
				}
			})
		</script>
	</body>
</html>

2. 标签

2.1 v-if

作用:

v-if:'data',若data数值为真就渲染组件,否则不渲染。

2.2 v-else-if

作用:

与v-if结合使用,效果类似。

2.3 v-show

v-show='data',若data数值为真就显示组件,否则不显示,不显示效果等同于display:none;区别于v-if的不渲染。

2.4 v-pre

作用:

跳过这个元素和它的子元素的编译过程。一些静态的内容不需要编辑加这个指令可以加快编辑。

2.5 v-once

作用:

如果显示的信息后续不需要再修改,使用v-once,这样可以提高性能。

2.6 v-bind

作用:

动态将数据和属性(style,class...)标签进行绑定。

简写:':'

2.7 v-cloak

2.7.1 语法格式
 <div v-cloak>{{data}}</div>
作用:

在网络延迟高时,可能会在页面突兀的显示代码: {{data}},加上v-cloak(斗篷)在data还没有完全加载出来前可以掩藏 {{data}}。

2.8 v-for

作用:

遍历数组或者对象元素,遍历出来的数据绑定组件逐个渲染。

示例
<!-- 根据实际开发中的重要性,先value,最后index;value,key,index名字可以自定义 -->
<div v-for='(value, key, index) in object'>
   <div>{{index}} {{key}} {{value}} </div>
</div>

2.9 v-on

作用

绑定事件函数,示例:v-on:click = 'clickFunction' 等同于 on-click = 'clickFunction'

修饰符
  • stop:停止向上冒泡
  • once:使绑定的事件只响应一次
  • prevent:阻止组件的默认行为,比如form表格的默认active行为
  • {keyCode|keyAlias}:对按键事件的过滤,例如:v-on:key.enter = 'functionName' 只有按下enter建才进行回调
  • native:监听组件根元素的原生事件
简写:'@'

2.10 v-model

作用:

实现数据与表单的双向绑定。

原理
<input v-model="message" value="message">
<!-- 上面代码效果等同于下面-->
<input v-bind:value="message" @input="message=$event.target.value"/>
v-model 结合单选按钮
<body>
      <div id='app'>
	<input value='男' type='radio' name='radio-group' v-model="sex"/>男
	<input value='女' type="radio" name='radio-group' v-model='sex'/>女
	<h3>{{sex}}</h3>
      </div>
	<script src='../js/vue.js'></script>
	<script>
	const app = new Vue({
			el:'#app',
			data:{
				sex:'男'
			      }
			})
	</script>
</body>
v-model 结合复选框

复选框单选对应 bool值,多选对应数组[]

<body>
      <div id='app'>
	<input type="checkbox" v-bind:value='agree' v-model='agree' />同意协议
	<h3>{{agree}}</h3>
	</div>
	<script src='../js/vue.js'></script>
	<script>
	const app = new Vue({
			el:'#app',
			data:{
				agree:false
			}
			})
	</script>
</body>

<body>
      <div id='app'>
	<div v-for='(hobby,index) in hobbies'>
	      <input v-bind:value='hobby' type='checkbox' name='index' v-model="selectedHobbies"/>{{hobby}}
		</div>
		<h3>{{selectedHobbies}}</h3>
		</div>
      <script src='../js/vue.js'></script>
      <script>
      const app = new Vue({
		el:'#app',
		data:{
		hobbies:['游泳','跑步','看书','绘画'],
		selectedHobbies:[]
		}
		})
      </script>
</body>
v-model 结合select
<!-- 若想实现多选 添加标签:multiple -->
<select name='abc' v-model='fruit'>
      <option value='苹果'>苹果</option>
      <option value='香蕉'>香蕉</option>
      <option value='葡萄'>葡萄</option>
      <option value='榴莲'>榴莲</option>
</select>
修饰符:
  • lazy:对于绑定的组件,只在其失去焦点或按下回车才更新vue实例中的数据。
  • number:传入vue实例中的数据为Number对象
  • trim:除去数据中的前后空格

3. 组件中的key属性

3.1 作用:

唯一确定组件,使组件能不随意更新。通俗讲可以让组件更好复用或不复用。

3.2 示例:若不加入key,js内核会复用input组件,造成组件中的值会保留。

<body>
      <div id='app'>
            <div v-if='flag'>
	      <input key='account'/>账号登录
            </div>
            <div v-else>
                  <input key='email'/>邮箱登录
            </div>
      <button @click="btnClick">{{login}}</button>
      </div>
<script src='../js/vue.js'></script>
<script>
      const app = new Vue({
                  el:'#app',
                data:{
		        flag:true,
                        login:'切换邮箱登录'
			},
              methods:{
			btnClick(){
			      if(this.flag){
				this.flag = !this.flag;
				this.login = '切换账号登录';
				}else{
					this.flag = !this.flag;
					this.login = '切换邮箱登录'
				}
			}
		        }
			})
</script>
</body>

4. 响应式函数

4.1 响应式操作

修改vue实例中数据,绑定vue实例中数据的组件/属性会实时更新。通过函数实现的响应式操作即为响应式函数。

4.2 关于数组操作的响应式函数

  • push('') 最后加多元素
  • pop() 删最后一个
  • shift() 删第一个
  • unshift('') 最开头添加多个元素
  • splice('','','') start, length ,item 它可以进行删除元素,插入元素,替换元素
  • reverse 数组反转

4.3 非响应式操作

通过索引改变数组!!!

5. Vue实例中的过滤器对象

5.1 作用

将数据按照一定的规则转化为另外一个数据返回。

5.2 示例:将price作为参数传入priceFilter中,返回修改后的price

<body>
      <div id='app'>
	<!-- 使用过滤器 ,默认将price作为参数传入给priceFilter-->
	<h4>价格:{{price | priceFilter}}</h4>
      </div>
      <script src='../js/vue.js'></script>
      <script>
            const app = new Vue({
                        el:'#app',
                        data:{
				price:12.3
			      },
                        filters:{ //在vue实例中加入filter对象,在filter对象里面定义过滤器(函数)
				priceFilter(price){
				//保留小数2位:Number.toFixed(2) 
				return '¥' + price
				}
			}
			})
	</script>
</body>

6. js中高阶函数 (很多高级语言中都会有)

6.1 filter()

result = array.filter(callback(n){}) 回调函数返回的必须为一个bool值,若为true自动 将n加入内部数组,否则不加入

6.2 map()

result = array.map(callback(n){}) 回调函数的返回值为新数值返回

6.3 reduce()

result = array.reduce(callback(n1,n2){},0) 第二个参数为第一个值的初始值, 对两个值进行操作,返回操作后的结果作为下一组传入的第一个值。

7. 组件化

7.1 自定义第一个组件 (创建构造器,注册组件,使用组件)

<body>
		<div id='app'>
			<!-- 使用组件 -->
			<my-component></my-component>
		</div>
		<script src='../js/vue.js'></script>
		<script>
			//创建组件构造器
			creater = Vue.extend({
				//tab键上面的那个符号在ES6中可以实现内部内容任意换行圈成一个整体
				name:'cmp',
				template:`
				<div>
					<h4>我的第一个组件</h4>
				</div>
				`
			})
			//注册组件 (此方法注册的组件为全局组件,所有vue实例挂载的元素中都可以使用)
			Vue.component('my-component',creater)
			const app = new Vue({
				el:'#app'
			})
		</script>
	</body>

7.2 全局组件注册的简写(语法糖)

//Vue.compontent会自动将第二个参数{}传给Vue.extend()
Vue.component('my-component',{ 
	template:`<div></div>`
	})

7.3 局部组件注册 (确立一个概念:Vue实例本身是个组件)

<body>
		<div id='app'>
			<cpn></cpn>
		</div>
		<div id='app2'>
			<!-- <cpn></cpn>  试图引用app实例的局部组件,报错! -->
		</div>
		<script src='../js/vue.js'></script>
		<script>
			const cpnC = Vue.extend({
				template:'<div>局部组件</div>'
			})
			const app = new Vue({
				el:'#app',
				components:{
					cpn:cpnC
				}
			})
			const app2 = new Vue({
				el:'#app2'
			})
		</script>
	</body>

7.4 组件中的模板(template)分离写法

1.通过脚本分离:
<script type='text/x-template' id='temp'>
	<div>
		在类型为'text/x-template'的script中定义
	</div>
</script>
<script >
		//通过id引用
		Vue.component('my-component',{template:'#temp'})
</script>
2.通过组件模板分离
<template id='#temp'>
	<div>
		在template组件中定义模板
	</div>
</template>

<script>
	Vue.component('my-component',{template:'#temp'})
</script>

7.5 向组件中存放数据

<!-- 使用组件中message数据 -->
<cpn>{{message}}</cpn>
--------------------------------------------------
<script>
Vue.component('cpn',
	{
		template:'#cpn',
		data()   //这个对象必须为函数
		{
			return {message:'abc'}
		}
	}
)
</scirpt>

7.6 思考:组件中data为什么是函数?

这可以保证数据作用域仅限于当前组件,而不会作用于其他相同的组件!

7.8 创建父子组件

<body>
	<div id='app'>
		<!-- 使用组件 -->
		<cpn2></cpn2>
	</div>
	<script src='../js/vue.js'></script>
	<script>
		const cpnC = Vue.extend({
		template:'<div>子组件</div>'
		})
		Vue.component('cpn2',{
			template:'<div>父组件<cpn></cpn></div>',
			components:{
			cpn : cpnC  //*这里只能是一个组件构造器,若为一个组件就报错找不到
				}
			}
		)
		const app = new Vue({
			el:'#app'
			})
	</script>
</body>

7.9 父子组件的通信

需求:子组件不能引用父组件或者Vue实例的数据,但是实际开发中却需要父子组件相互通信!

Vue提供的方法:
通过props(properts 简写)向子组件传递数据;
通过事件($emit Events)向父组件发送数据。

1. 父组件向子组件传递数据:
<body>
		<div id='app'>
			<!-- 父组件向子组件传递数据 -->
			<cpn v-bind:movies='movieList'></cpn>
		</div>
		<template id="temp">
			<div>
				<ul>
					<!-- 遍历显示组件中的movies数据 -->
					<li v-for='movie in movies'>{{movie}}</li>
				</ul>
			</div>
		</template>
		<script src='../js/vue.js'></script>
		<script>
			const app = new Vue({
				el:'#app',
				data:{
					movieList:['三傻大闹宝莱坞','我不是药神','唐人街探案']
				},
				components:{
					cpn:{
						template:'#temp',
						props:['movies'] //这里的movies在上面被当成一个变量属性
					}
				}
			})
		</script>
</body>
1.1 props的一些可选操作
  1. 数据类型限制:
    props:

  2. 带默认值:(对象中 required 表示 是否必须传数据)

props:
{movies:
      {	
	type:Array,
	default:[''],
	required:true
      }
}

上面的语法有个错误,default默认值为数组或对象类型时default必须为一个函数:default(){return []}

  1. 自定义数据类型:
    props:
1.2 props中数据变量驼峰命名问题:

props:{moviesName:Array} //声明时为驼峰

//使用时要以-连接

2.子组件向父组件传递数据:($emit发射的事件同样不能用驼峰命名法)
<!-- 触发流程:btnClick -->cpn-event -->getCpnData -->
<body>
		<div id='app'>
			<cpn @cpn-event='getCpnData'></cpn>
			<h2>子组件传来的数据:{{cpnData}}</h2>
		</div>
		<template id="temp">
			
		</template>
		<script src='../js/vue.js'></script>
		<script>
			const app = new Vue({
				el:'#app',
				data:{
					cpnData:''
				},
				methods:{
					getCpnData(item){
						this.cpnData = item
					}
				},
				components:{
					cpn:{
						template:`
						<div>
							<button @click="btnClicked">子组件按钮</button>
						</div>
						`,
						data(){
							return {item:'子组件数据'}
						},
						methods:{
							btnClicked(){
								return this.$emit('cpn-event',this.item)
							}
						}
					}
				}
			})
		</script>
	</body>
扩展知识
<!-- component watch 对象 监听数据改变;
watch中的函数名 和 data 返回的变量名相同 -->
data(){
	return {number1:123}
      },
watch:{
         number1(newValue, oldValue){
         this.number1 = newValue;
         this.$emit('numb1change',this.number1) 
         }
      }

7.10 父子组件互相访问

1.父组件访问子组件

$children 或者 $refs (reference)

this.$children[0].function()
this.$children[1].name

在实际开发中一般不使用this.$children ,组件数量随时会变,下标取值不稳定

this.$refs.aaa 父组件中访问子组件,refs默认为空,在组件中需要加ref
<cpn ref='aaa'> </cpn> 组件中加入ref使用
2.子组件访问父组件
his.$parent  //在子组件中访问父组件
this.$root //在子组件中访问vue实例

7.11 slot 插槽

作用

使组件内部具有更好可扩展性。使得我们可以给自定义组件中添加中添加其他html内容。

使用方法
<!-- 1.在模板中定义slot -->
<template id="temp">
	<div>自定义组件
		<slot></slot>
	</div>
</template>

<!-- 2.使用带有slot的模板的组件 -->
<!-- h2 和 button 会替换组件中的slot,可以将slot理解为一个占位符 -->
<cpn>
	<h2>给自定义组件添加html元素</h2>
	<button>按钮</button>
</cpn>
slot常见几种情形
<!-- 1.带默认值slot -->
<!-- 若不给自定义组件中添加html内容,默认显示button;若添加了就替换button  -->
<slot><button>按钮</button></slot>

<!-- 2.具名(带name)slot -->
<template id='barTemp'>
	<slot name='left'></slot>
	<slot name='center'></slot>
	<slot name='right'></slot>
</template>
<!-- 使用:(指名道姓替换组件中某个插槽) -->
<cpn><button slot='left'>返回</button></cpn>
<cpn><span slot='center'>标题</span></cpn>
<cpn><button slot='right'>搜索</button></cpn>

<!-- 3.作用域slot :父组件替换插槽的标签,但是内容由子组件来提供-->
<!-- 需求:内容在子组件,希望父组件告诉我们如何展示,怎么办? -->
<template>
	<slot v-bind:data='子组件数据'></slot>
</template>
<!-- 重点是:slot-scope='slot' -->
<cpn>
	<template slot-scope='slot'>
		<div v-for='item in slot.data'>{{item}}</div>
	</template>
</cpn>

二、模块化和webpack

1. 模块化规范

1.1 常见模块化规范:

CommonJS(node采用的该规范)、AMD、CMD、ES6的Modules

1.2 CommonJS 的导出

请在node 环境下使用

a.js文件:

flag = true
sum(a,b){
	return a+b
}
<!-- 重点:module.exports -->
module.exports = {
	flag:flag,
	sum:sum
}

2.2 CommonJS 的导入

b.js文件

<!-- 重点:require -->
var obj = require('a.js')
console.log(obj.flag)
console.log(obj.sum(1,2))

2.3 脚本标签中的 module 类型

作用:

将每个js文件作为独立的模块,避免了js文件间命名冲突。

演示

a.js文件中:

var flag = true
if(flag){console.log('a.js文件')}

b.js文件中:

if(flag){console.log('b.js文件')}

index.html 文件中

<!-- 加入type='module' 后会报错 ,
因为type='module' 可以保证多个文件共同引用不会出现命名冲突-->
<script src='a.js' type='module'></script>
<script src='b.js' type='module'></script>
思考:一个js文件想引用另外一个js文件中的数据ES6中怎么实现?

ES6 标准中的export,import 的运用。

2.4 ES6 的导出

a.js文件中 export演示

var name = '鲤鱼的探险历程'
getName()
{
      return name
}
//方式一:对象形式导出
export {name, getName}
//方式二:直接导出
export var name2 = 'vue coder'
//方式三:匿名导出
const email = '123@126.com'
export default email   //同一个模块(文件)中只能存在一个

2.5 ES6 的导入

b.js文件中 import演示

//对应方式一:
import {name, getName} from 'a.js'
//对应方式二:
import {name2} from 'a.js'
//对应方式三:
import my_email from 'a.js' //导入者自己命名变量

应用于除了匿名导出的其他方式:
//‘* as ’的作用:给导入对象命名,避免 1.导入变量和当前文档中的变量相同产生冲突,2.导入数据过多的问题
import * as aaa from '../aa.js'  
console.log(aaa.val)

2. webpack的使用

webpack官网

webpack中文

webpack功能图

2.1 webpack 的安装

全局安装

npm install webpack -g

本地(局部)安装

npm install webpack --save

2.2 建立项目

目录结构
  • dist //保存打包后的文件
  • src //源代码文件夹
    * main.js //在该文件引用所有js文件
    * a.js
    * b.js
  • index.html //项目入口文件

2.3 打包文件

把终端(cmd)路径换成当前项目路径,然后键入(4.x.x版本):

webpack ./src/main.js -o ./dist/bundle.js

webpack3.x.x的版本使用:

webpack ./src/main.js ./dist/bundle.js

解释:将main.js以及它所引用的所有js文件打包到bundle.js文件;
若是webpack 5.x.x会在dist/bundle.js 的文件夹中生成打包后的main.js
思考:怎么精简:webpack ./src/main.js ./dist/bundle.js ?

需要对webpack进行配置。

配置流程:
  1. 当前项目中建立文件:webpack.config.js
  2. webpack.config.js中添加内容:
const path = require('path')  //导入node的path包
module.exports = {
	entry:'./src/main.js',
	//output中的路径必须为绝对路径
	output:{
	//__dirname 为node中上下文全局变量,值为当前路径,
	//path.resolve 进行路径拼接
	path:path.resolve(__dirname,'dist'),
	filename:'bundle.js'
	},
	mode:'development' //不加这条代码,在4.x.x以上的webpack默认打包为压缩后的代码
}
//概括:将src下的main.js文件打包到当前路径下的dist文件夹的bundle.js文件中
思考:这里引用了nodo的path包,那么就需要配置一个package.json文件,该文件如何配置?

1. 在当前项目路径下运行终端命令:npm init
2. 按照提示进行配置,配置完后项目中就会生成 package.json 文件

<!-- package.json 文件内容 -->
{
  "name": "webpacktest",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",//随便填的入口文件
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
       },
  "author": "",
  "license": "ISC"
}
  1. 以后在终端直接输入:webpack ,即可起到相同打包效果。

2.4 npm 运行 webpack

思考:若配置文件很多webpack命令就会又变得很长,怎么解决?

用 npm run ... 代替。

怎么用npm run build 代替 webpack ?

在 package.json 的scripts中添加:"build":"webpack"

运行npm run build 时,会默认先从局部(本地)找webpack,再找全局
这里面存在一个问题:若项目中需要低版本的webpack怎么办?

安装局部(本地)webpack : npm install webpack@3.6.0 --save-dev //有-dev意思为开发时依赖

在终端使用webpack命令会使用全局的webpack. 想访问本地需要输入 ./node_module/.bin/webpack

2.5 webpack.loader

loader作用

将 less-->css ,TypeScript --> js ...
总的一句话:将其他文件打包为css、js、html这种浏览器认识的基本类型

loader的使用

步骤一:npm 安转需要使用的loader;(不同文件打包,对应不同loader)

步骤二:在webpack.config.js 中的module关键字下进行配置

2.5.1 打包CSS

1.npm install --save--dev css-lodeer style-loader

2.webpack.config.js 文件配置:

module:{
      rules:[
	{
            test:/\.css$/,
            use:['style-loader','css-loader']
            //css-loader 负责加载css文件,style-loader负责编译
            //为什么css-loader写在后面,因为node数据加载默认从右至左
	}
      ]
}
2.5.2 打包less

1.npm install --save-dev less-loader less //less负责转换less-->css

2.{test:/.less$/, use['style-loader','css-loader','less-loader']}

2.5.3 打包图片

1.npm install --save-dev url-loader

2.webpack.config.js文件中:

module:{
      rules:[
            {
                  test:/\.(png|jpg|jpeg)$/,
                  use:[
                        {
                              loader:'url-loader',
                              options:{limit:8192}
                              //小于limit大小的图片会被base64编码后替换图片url
                              //当加载大于limit的图片时需要file-loader 模块
			}
			]
	}
	]
}

3.若image的大小有大于limit限制的才有这步骤:
npm install --save-dev file-loader

!!!若运行程序入口网页index.html不在dist包中,可能会报路径加载错误

原因:file-loader会将照片文件加载到打包文件中,这样源代码中的路径就会有问题。

解决方法:使打包照片路径时候自动添加上dist路径,在webpack.config.js的output中加上:publicPath:'dist/'

file-loader会用hash值命名图片,若需求希望打包后的文件有一定的规范:
希望放在img文件夹中,原来文件名+hash的前8位+文件类型
(为什么不直接用文件名字,在实际开发中项目中可能存在相同名字的图片被同时加载到img文件夹)

操作:options中加上:name:'img/[name].[hash:8].[ext]'

2.5.4 ES6代码转为ES5代码

1.npm install --save-dev babel-loader@7 babel-core babel-preset-es2015

2.{test:/.js$/, exclude:/(node_modules|bower_components)/,use:{loader:'babel-loader',options:{presets:['es2015']}}}

2.6 配置vue环境

1.npm install --save vue //安装运行时依赖,非开发时依赖!

2.导入vue: import Vue from 'vue'

再运行 :npm run build 可能会报错

原因:在使用vue的文件中存在 const app = new Vue({}),会被当作编译template,而runtime-only 版本不支持template

解决方法:使用 runtime-compiler 的vue版本。

操作:在webpack.config.js中配置中加入 resolve:{alias:{'vue$':'vue/dist/vue.esm.js'}}

原理:将import Vue from 'vue'中的vue引入了另一个文件,vue.esm.js相当于使用runtime-compile

打包.vue文件

1.npm install vue-loader vue-template-compiler --save-dev

2.{test:/.vue$/,user:['vue-loader']}

打包时可能报错:vue-loader 缺少一个插件,14版本上的webpack需要配置一个插件

解决方法:在package.json中修改 'vue-loader':'^13.0.0' 版本限制在13-14间,再执行 npm install

怎么省略输入文件类型?
在webpack.config.js的module.export中加入:

resolve:{//用来解决路径问题
      "extensions":['.js','.css','.vue']
      }

2.7 plugin 插件的使用

步骤一:通过npm安转需要应用的插件

步骤二:在webpack.config.js中的plugins中配置插件

loader和plugin区别:loader像一个加载器、转换器;plugin是一个扩展器。

plugin常用的有:给js添加一个版权声明,代码压缩(丑化)

·版权声明操作:

在webpack.config.js文件中

const path = require('path')
const webpack = require('webpack')
module.exports = {
	entry:'./src/main.js',
	output:{
	//__dirname 为node中上下文全局变量,值为当前路径,
	//path.resolve 进行路径拼接
	path:path.resolve(__dirname,'dist'),
	filename:'bundle.js'
	},
	mode:'development',
	resolve:{//用来解决路径问题
		"extensions":['.js','.css','.vue']
	},
	plugins:[
		new webpack.BannerPlugin('我的版权')
		]
}

·打包html的plugin

真实发布项目时,发布的dist文件夹中的内容需要index.html文件

执行:npm install html-webpack-plugin --save-dev

const HtmlWebpackPlugin = require(html-webpack-plugin)
--------------------------------------------------
plugins:[
	new HtmlWebpackPlugin(
	{template:'index.html'})//根据模板生成index.html
] 

打包成功后会在dist文件夹下生成index.html文件

文件中自动加入

posted @ 2020-11-22 23:07  鲤鱼的探险历程  阅读(130)  评论(0)    收藏  举报