赞
踩
{
}
{
}
-S 是 --save的简写
-D 是 --save-dev的简写
{
}
development 表示在开发阶段
production表示要上线的项目
none 表示‘无’
执行dev脚本后会在根目录下生成一个dist文件夹,里面包含了生成的main.js文件
,main.js文件大小取决于exports的参数
开发的是有一定要用development,因为最求的是打包的速度,而不是体积
上线的时候一定要用production,因为上线最求得是体积,而不是速度快
在webpack 4.X和5.X的版本中,有如下默认约定:
1.默认的打包入口为src -> index.js
2.默认的输出文件路径为 dist -> main.js
ps:可以在webpack.config.js中修改打包的默认约定
const path = require('path')
module.exports = {
mode : 'none', //mode 来指定构建模式 develoment 开发模式 production表示要上线的项目
//entry: //指定要处理那个文件
// __dirname表示该文件的绝对路径,拼接上要处理文件的相对路径
entry: path.join(__dirname,'./src/index1.js'),
// 指定生成的文件要放到哪里
output: {
//存放的目录
path: path.join(__dirname,'dist'),
// 生成的文件名
filename: 'bundle.js'
}
}
在开发中使用插件自动打包
npm install webpack-dev-server@3.11.2 -D
"scripts": {
//添加serve参数
"dev": "webpack serve"
},
「wds」: Project is running at http://localhost:8080/
表示项目运行的地址
「wds」: webpack output is served from /
生成的js在根目录,但是不会在硬盘中显示,而是生成在内存中,因为内存比硬盘快,所以应当把index.html里的js引用为内存生成的js
/**index.html中**/
<script src="../main.js"></script>
在实际运行中需要进入http://localhost:8080/src/这个路径里面,可以使用html-webpack-plugin插件把src/index.html页面复制到项目根目录里面
npm install html-webpack-plugin@5.3.2 -D
const path = require('path') //导入html-webpack-plugin这个插件,得到插件构造函数 const HtmlPlugin = require('html-webpack-plugin') //new 构造函数,创建插件的实例对象 const htmlPlugin = new HtmlPlugin({ //指定要复制哪个页面 template: './src/index.html', //复制出来的路径以及存放路径 filename: './index.html' }) module.exports = { mode : 'none', //mode 来指定构建模式 develoment 开发模式 production表示要上线的项目 //entry: //指定要处理那个文件 // __dirname表示该文件的绝对路径,拼接上要处理文件的相对路径 entry: path.join(__dirname,'./src/index.js'), plugins: [htmlPlugin], //通过plugin节点,使htmlplugin插件生效 // 指定生成的文件要放到哪里 output: { //存放的目录 path: path.join(__dirname,'dist'), // 生成的文件名 filename: 'main.js', } }
表示将复制的页面放到主目录里面(内存)
如11所讲
devServer
module.exports = { mode : 'none', //mode 来指定构建模式 develoment 开发模式 production表示要上线的项目 //entry: //指定要处理那个文件 // __dirname表示该文件的绝对路径,拼接上要处理文件的相对路径 entry: path.join(__dirname,'./src/index.js'), plugins: [htmlPlugin], //通过plugin节点,使htmlplugin插件生效 // 指定生成的文件要放到哪里 output: { //存放的目录 path: path.join(__dirname,'dist'), // 生成的文件名 filename: 'main.js', }, // devServer devServer: { open: true,//初次打包,自动打开浏览器 port:80,//指定端口 host: '127.0.0.2' //指定打开的地址 } }
在http协议中,端口号80表示默认端口,则端口号在浏览器省略不显示
loader(加载器)
在实际开发过程中,webpack处理不了后缀不是.js结尾的模块,webpack默认是处理不了的,需要调用loader加载器才能正常的打包,否则会报错!
用vue往html页面填充数据
一套现成的解决方案,要遵守框架的规范
vue会监听数据的变化,从而重新渲染页面的结构DOM
OK:数据发生变化,页面重新渲染!
Note:数据驱动是 单向的数据绑定 \color{red}{单向的数据绑定} 单向的数据绑定
在网页中form负责采集数据,Ajax负责 “提交数据”
MVVM 是 数据驱动视图 \color{red}{数据驱动视图} 数据驱动视图和 双向数据 \color{red}{双向数据} 双向数据绑定的核心原理,MVVM是值指的Model、View和View Model它把一个页面拆分成三部分
这里我自己按照视频上面的代码识别不了Vue对象,下面代码贴的开发文档的
<!-- 希望vue控制这个div,数据填充div内部 --> <div id="app">{{ message }}</div> <!-- "username"两边加空格让格式更清晰 --> <!-- 通过cdn使用vue --> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> <!-- 创建Vue的实例对象 --> <script> //这里使用的vue开发文档来创建https://cn.vuejs.org/guide/quick-start.html#using-vue-from-cdn const { createApp } = Vue createApp({ data() { return { message: 'Hello Vue!' } } }).mount('#app') </script>
Null
指令(Directives)是vue为开发者提供的模板语法,用于辅助开发者渲染页面的基本结构。
vue中的指令按照不同的用途可以分为如下6大类:
① 内容渲染 \color{red}{内容渲染} 内容渲染指令
② 属性绑定 \color{red}{属性绑定} 属性绑定指令
③ 事件绑定 \color{red}{事件绑定} 事件绑定指令
④ 双向绑定 \color{red}{双向绑定} 双向绑定指令
⑤ 条件渲染 \color{red}{条件渲染} 条件渲染指令
⑥ 列表渲染 \color{red}{列表渲染} 列表渲染指令
v
−
t
e
x
t
\color{pink}{v-text}
v−text
缺点:会覆盖元素内部原有的内容
<p v-text="username"></p>
{ { } } 插值表达式 \color{pink}{\{\{\}\}插值表达式} {{}}插值表达式
用来解决覆盖原有内容的问题,实际开发中用的最多
但插值表达式只能用于内容节点,不能用于属性节点
v − h t m l \color{pink}{v-html} v−html
可以渲染标签
v − o n c e \color{pink}{v-once} v−once
可以通过这个指令来一次性的插值,数据改变的时候,这个值不会更新
v − b i n d \color{pink}{v-bind} v−bind
vue规定可以将v-bind:简写为":"(冒号)
在vue中绑定内容可以动态拼接
<div :title="'box'+index">这是一个div</div>
v − o n \color{pink}{v-on} v−on
语法格式为 v-on :事件名称=“事件处理函数名称”
由于v-on在开发中频率很高,简写为 @ \color{red}{@} @
<div id="app"> <p>count的值是{{ count }}</p> <!-- 语法格式为 v-on :事件名称="事件处理函数名称" --> <button v-on:click="addCount">+1</button> </div> <script src="./vue.global.js"></script> <script> const { createApp } = Vue createApp({ data() { return { count:0, } }, // methods的作用就是定义事件的处理函数 methods:{ addCount: function(){ //在实际开发中建议使用简写 addCount(){ count++ } } }).mount('#app') </script>
由于业务逻辑代码只有一行所以也可以简写为
<button @click="message++">+1</button>
<button @click="message--">-1</button>
可以使用一个形参来接收
add(e){
const nowBgc = e.target.style.background;
e.target.style.background = nowBgc ==='red' ? '' : 'red'
this.resu=nowBgc
console.log(nowBgc);
}
$event
e v e n t 是 v u e 提供的特殊变量,表示原生事件参数对象 e v e n t 。 event是vue提供的特殊变量,表示原生事件参数对象event。 event是vue提供的特殊变量,表示原生事件参数对象event。event可以解决事件对象event被覆盖的问题
.prevent 阻止默认行为
----> 阻止a连接的跳转,阻止表单的提交
.stop 阻止事件冒泡
----> 内部盒子点击不会触发外层盒子
}}
.capture
---->从外部开始向内部触发
.once
---->只触发一次
.self
---->如果通过冒泡,则不触发
表按下了enter键则执行submit方法 && 按下了esc键则执行clearInput方法
<input type="text"@keyup.enter="submit"@keyup.esc="clearInput">
v-model数据绑定指令
可以帮助辅助开发者不操作DOM的前提下,快速获取表单的数据
<p>用户名{{username}}</p>
<input type="text"@keyup.enter="submit"@keyup.esc="clearInput" v-model="username">
<p>选中的省份是:{{province}}</p>
<select v-model="province">
<option value="">请选择</option>
<option value="1">重庆</option>
<option value="2">广东</option>
<option value="3">北京</option>
<option value="4">上海</option>
</select>
注意:v-model指令只能配合表单元素一起使用,不能和p标签a标签不能输入的标签所使用
为了方便对用户内容的输入处理,v-model提供了三个修饰符
.lazy 当对象失去焦点的时候更新,而不是实时更新
v
−
i
f
\color{pink}{v-if}
v−if
v
−
s
h
o
w
\color{pink}{v-show}
v−show
实现的效果
v-if会动态创建和移除DOM元素,从而控制元素在页面上的显示与隐藏
它有更高的性能消耗
v-show指令会动态的为元素添加或移除style="display:none"样式,来控制显示与隐藏
他会有更高的出事消耗开销
频繁的切换,使用v-show更好
反之,使用v-if更好
随机生成0.01~1的数
num:Math.random(),
相当于if–else
<p v-if="num>0.5">大于0.5</p>
<p v-else>小于0.5</p>
v-else-if相当于switch case语句
v − f o r \color{pink}{v-for} v−for
语法格式:(item,index)in items
item和index都是形参,可更改
<li v-for="(user,i) in list">索引:{{i}}姓名是:{{user.name}}</li>
问题:
当列表的数据变化时,默认情况下,vue会尽可能的复用已存在的DOM元素,从而提升渲染的性能。但这种默认的性能优化策略,会导致有状态的列表无法被正确更新。
解决方案:给每一项给一个唯一的key 属性
key所绑定的值,只能是数字型或字符串型
<li v-for="(user,i) in list" :key="list.id">
过滤器(Filter)常用于文本的格式化
“|”被称为管道符
在属性中添加|可以使用过滤器
<p>{{province | capitalize}}</p>
过滤器可以用在插值表达式和v-bind属性绑定
过滤器得通过与el节点平齐的filters节点来描述
filters: {
capitalize(str){
return str.charAt(0).toUpperCase()+str.slice(1)
}
}
私有过滤在不被控制的区域不会起作用
可以用下面的例子来声明全局过滤器
<script>
Vue.filter('capitalize',(str)=>{//str是形参
return str.charAt(0).toUpperCase()+str.slice(1)
})
</script>
其中,私有过滤器优先级高于全局过滤器
可以调用多个过滤器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <!-- 导入 bootstrap 的样式表 --> <!-- https://v4.bootcss.com/docs/components/forms/#switches --> <link rel="stylesheet" href="./lib/bootstrap.css" /> <style> :root { font-size: 13px; } body { padding: 8px; } </style> </head> <body> <div id="app"> <!-- 卡片区域 --> <div class="card"> <h5 class="card-header">添加品牌</h5> <div class="card-body"> <!-- 添加品牌的表单 --> <!-- vue在做表单提交的时候,需要用到一些自定义的验证规则,这个时候就需要阻止表单默认的提交方式。 --> <form class="form-inline" @submit.prevent> <div class="input-group mb-2 mr-sm-2"> <div class="input-group-prepend"> <div class="input-group-text">品牌名称</div> </div> <!-- 文本输入框 --> <input type="text" class="form-control" v-model.trim="brandname" @keyup.esc="brandname=''"/> </div> <!-- 提交表单的按钮 --> <button type="submit" class="btn btn-primary mb-2" @click="addNewBrand">添加品牌</button> </form> </div> </div> <!-- 品牌列表 --> <table class="table table-bordered table-striped mt-2"> <thead> <tr> <th>#switches</th> <th>品牌名称</th> <th>状态</th> <th>创建时间</th> <th>操作</th> </tr> </thead> <!-- 表格的主体区域 --> <tbody> <!-- TODO:循环渲染表格的每一行数据 --> <tr v-for="(item,index) in brandlist" :key="item.id"> <td>{{item.id}}</td> <td>{{item.brandname}}</td> <td> <div class="custom-control custom-switch"> <!-- //v-model双向绑定绑定初始值 --> <input type="checkbox" class="custom-control-input" :id="item.id" v-model="item.state"> <label class="custom-control-label" :for="item.id" v-if="item.state">已开启</label> <label class="custom-control-label" :for="item.id" v-else>已禁用</label> </div> </td> <td>{{item.addtime | dateFormat}}</td> <td> <a href="#" @click.prevent="removeBrand(item.id)">删除</a> </td> </tr> </tbody> </table> </div> <script src="../../vue-2.6.14/dist/vue.js"></script> <script> //创建全局的过滤器 Vue.filter('dateFormat', (dateStr)=>{ return dateStr }) const vm = new Vue({ el: '#app', data: { brandname:'', nextId:'5', brandlist:[ { id: 1,brandname: '宝马', state: true, addtime:new Date() }, { id: 2,brandname: '奥迪', state: true, addtime:new Date() }, { id: 3,brandname: '奔驰', state: true, addtime:new Date() }, { id: 4,brandname: '山崎', state: true, addtime:new Date() }, ] }, methods: { // 添加新的品牌数据 addNewBrand(){ if(!this.brandname) return alert("品牌名不能为空!"); // 添加操作 this.brandlist.push({ id:this.nextId, brandname:this.brandname, state:true, addtime:new Date() }) this.nextId++, this.brandname = '' }, // 根据id删除对应的数据 removeBrand(id){ // 过滤旧数组,形成新数组 this.brandlist=this.brandlist.filter(x => x.id !==id ) } }, }) </script> </body> </html>
是指一个web网站中只有唯一一个html页面,所有的功能和交互都在这一个页面完成
单页面应用程序将所有的功能局限于一个web页面中,仅在该web页面初始化时加载相应的资源(HTML、Javascript和CSS)。
一旦页面加载完成了,SPA不会因为用户的操作而进行页面的重新加载或跳转。而是利用JavaScript动态地变换HTML的内容,从而实现页面与用户的交互
{
}
node_modules 目录用来存放第三方依赖包
public 是公共的静态资源目录
srC是项目的源代码目录(程序员写的所有代码都要放在此目录下)
.gitignore是Git的忽略文件
index.html是SPA单页面应用程序中唯一的HTML页面
package.json 是项目的包管理配置文件
{
}
assets目录用来存放项目中所有的静态资源文件(css、fonts等)
components目录用来存放项目中所有的自定义组件
App.vue是项目的根组件
index.css是项目的全局样式表文件
main.js是整个项目的打包入口文件
{
}
App.vue用来编写待渲染的模板结构
index.html中需要预留一个el区域
main.js把App.vue 渲染到了index.html所预留的区域中
根据封装的思想,把页面上可重用的部分封装为组件,从而方便项目的开发和维护。
例如:Ibootstrap就契合了组件化开发的思想。用户可以通过拖拽组件的方式,快速生成一个页面的布局结构。
Vue是完全支持组件化,开发的,其中后缀名为 . v u e \color{red}{.vue} .vue的文件为组件
template组件模板结构
script组件的javascript行为
css 组件的样式
template不会被渲染成DOM元素,只会起到包裹的作用
在vue3版本中<template>支持多个根节点
可以使用export default导出一个组件
可以通过name指定名称
<script>
export default{
name: 'MyApp1',
}
</script>
指定组件的数据
<template> <div> <h1>这是一个vue组件</h1> <h3>MyName:{{username}}</h3> </div> </template> <script> import HelloWorld from './components/HelloWorld.vue' export default{ name: 'MyApp1', data(){ return { username:'晓刘' } } } </script>
methods方法节点,与data同级
<template> <div> <h1>这是一个vue组件</h1> <h3>MyName:{{username}}</h3> <p>count的值是:{{count}}</p> <button @click="add">+1</button> </div> </template> <script> import HelloWorld from './components/HelloWorld.vue' export default{ name: 'MyApp1', data(){ return { username:'晓刘', count:0 } }, methods: { add(){ this.count++ } }, } </script>
style节点与script节点同级
......
<script>
......
</script>
<style>
h1{
color:red;
}
</style>
①运行npm install less -D命令安装依赖包,从而提供less 语法的编译支持
②在<style>标签上添加lang="less"属性,即可使用less 语法编写组件的样式
<style lang="less">
h1{
color:red;
i{
color:blue;
}
}
</style>
组件的引用原则 先注册,后引用 \color{red}{先注册,后引用} 先注册,后引用
vue中注册组件的方式分为“全局注册”和“局部注册”两种,其中:
被全局注册的组件,可以在全局任何一个组件内使用
被局部注册的组件,只能在当前注册的范围内使用
全局注册:
main.js:
//导出需要被全局注册的组件
import Swiper from './Swiper.vue'
//调用app.component方法注册全局组件
const app = createApp(App)
// 调用createApp函数,创建spa应用实例
app.component('mySwiper',Swiper)
Swiper:
<template>
<h1>这是一个组件</h1>
</template>
<script>
export default{
name:'myswiper'
}
</script>
局部注册:
import Search from './test.vue';
export default{
components: {
'myTest': Search,
},
.....
}
如果某些组件在开发期间的使用频率很高,推荐进行全局注册;
如果某些组件只在特定的情况下会被用到,推荐进行局部注册。
短横线命名法
\color{pink}{短横线命名法}
短横线命名法的特点:
·必须严格按照短横线名称进行使用
帕斯卡命名法
\color{pink}{帕斯卡命名法}
帕斯卡命名法的特点:
·既可以严格按照帕斯卡名称进行使用,又可以转化为短横线名称进行使用
在实际开发中,建议使用帕斯卡命名法来命名,适用性更好
快速选择相同的字符Ctrl+D
scoped的原理就是生成一个带有随机数的自定义属性
由于添加了scoped属性父组件不能给子组件进行样式声明,则需要
/
d
e
e
p
/
\color{red}{/deep/}
/deep/深度选择器
如上,
/
d
e
e
p
/
\color{red}{/deep/}
/deep/是vue2所特有的写法,在vue3推荐使用
:
d
e
e
p
(
X
X
X
)
\color{red}{:deep(XXX)}
:deep(XXX)来替代
props的作用:父组件通过props 向子组件传递要展示的数据。
props的好处:提高了组件的复用性。
父组件:
<mytest title="kukud_"></mytest>
子组件:
<script>
export default{
props: ['title'],
......
......
},
......
</script>
封装者定义了props数组,相当于留了一个形参api
在子组件中无法使用未声明的props
使用 数组语法 \color{red}{数组语法} 数组语法动态绑定classs会导致模板结构臃肿,使用对象语法来简化
<template> <div> <h2 class="thin" :class="classObj">MyStyle组件</h2> <button @click="classObj.italic=!classObj.italic">Togge italic</button> <button @click="classObj.delete=!classObj.delete">Togge Delete</button> </div> </template> <script> export default{ name: 'MyApp1', data(){ return { // 是否倾斜 isItalic: false, isDelete: false, classObj :{ italic: false, delete: false } }}, methods: { } } </script> <style lang="less" scoped> .italic{ font-style: italic; } .thin{ font-weight: 200; } .delete{ text-decoration: line-through; } </style>
:style的对象语法十分直观——看着非常像CSS,但其实是一个JavaScript对象。CSS property名可以用驼峰式(camelCase)或短横线分隔(kebab-case,记得用引号括起来)来命名:
<h2 class="thin" :class="classObj" :style="{fontSize: fsize + 'px',color: active}">MyStyle组件</h2>
Null 过时…
当类型不唯一的时候,可以用数组来表示可能的类型
<script>
export default {
name: 'MyHeader',
props:{
count: Number,
state: Boolean,
// 数组表示可能的类型,可以使Number,可以使Boolean类型
info: [Number,Boolean]
}
}
</script>
可以用 r e q u i r e d \color{red}{required} required属性来表示该值是否必填
<script>
export default {
name: 'MyHeader',
props:{
count: {
type: Number,
required: true
}
......
}
}
</script>
可以使用 d e f a u l t \color{red}{default} default属性来表示默认值
<script>
export default {
name: 'MyHeader',
props:{
count: {
type: Number,
default: 100
},
......
}
}
</script>
可以用自定义验证函数来判断
<script>
export default {
name: 'MyHeader',
props:{
count: {
valdata(value){
// 判断是否属于数组中的一个
return ['success','warning','denger'].indexOf(value) !== -1
}
}
}
}
</script>
计算属性本质上就是一个function函数,它可以实时监听 data中数据的变化,并return一个计算后的新值,供组件渲染DOM时使用。
计算属性以function函数的形式声明到computed选项中,且计算属性结果会被缓存,性能好
<script> export default { name: 'MyHeader', props:{ ...... }, data() { return { count: 5, } }, computed: { plus(){ return this.count*2; } } } </script>
计算属性必须定义在computed节点中
计算属性必须是一个function函数
计算属性必须有返回值
计算属性必须当做普通属性使用
<!-- 结算区域 --> <div class="settle-box"> <!-- TODO: 1. 动态计算已勾选的商品的总数量 --> <span>总数量:{{total}}</span> <!-- TODO: 2. 动态计算已勾选的商品的总价 --> <span>总价:{{amount}}</span> <!-- TODO: 3. 动态计算按钮的禁用状态 --> <button type="button" class="btn btn-primary" :disabled="isDisabled ? true : false">结算</button> </div> </div> </template> <script> export default { name: 'FruitList', data() { ...... }, computed:{ // 动态计算 total(){ let t=0 this.fruitlist.forEach(x =>{ if(x.state==true){ t+=x.count } }) return t }, amount(){ let a=0 //循环state属性为true的所有price单价*count数量 this.fruitlist.filter(x => x.state).forEach(x =>{ a+=x.price*x.count }) return a }, isDisabled(){ return this.total===0 } }, methods: { ...... } } </script>
javascript从设计之初就是单线程的语法,单线程的异步编程方式有诸多优点,比如无需考虑线程同步,资源竞争,线程切换开销的问题,为避免回调地狱设计了promise
fetch函数会返回一个promise(承诺在某个时间返回数据)
async关键字会将该函数标记为异步函数(返回值为promise对象的函数)
await语法等待promise完成后最终的结果
终端输入:
cnpm i axios -S
<template> <div> <h3>Watch侦听器用法</h3> <input type="text" class="form-control" v-model="username"> </div> </template> <script> import axios from 'axios' export default { name:'MyWatch', data(){ return{ username:'' } }, watch:{ // 声明这是一个异步处理函数 async username(newVal,oldVal){ console.log(newVal,oldVal) const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal) console.log(res); } } } </script> <style lang="less" scoped> </style>
在组件第一次被渲染后立即被调用,加入immedidata: true
<script> import axios from 'axios' export default { name:'MyWatch', data(){ return{ username:'admin' } }, watch:{ // 声明这是一个异步处理函数 // async username(newVal,oldVal){ // console.log(newVal,oldVal) // const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal) // console.log(res); // } username:{ async handler(newVal,oldVal){ const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal) console.log(res); }, //这里立即出发watch组件 immediate:true } } } </script>
当watch侦听的是一个对象,当对象中的属性发生了变化,则无法监听到,此时需要使用deep选项
<template> <div> <h3>Watch侦听器用法</h3> <input type="text" class="form-control" v-model="info.username"> </div> </template> <script> import axios from 'axios' export default { name:'MyWatch', data(){ return{ username:'admin', info:{ username:'admin' } } }, watch:{ // 声明这是一个异步处理函数 // async username(newVal,oldVal){ // console.log(newVal,oldVal) // const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal) // console.log(res); // } // username:{ // async handler(newVal,oldVal){ // const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal) // console.log(res); // }, // //这里立即出发watch组件 // immediate:true // } info:{ async handler(newVal,oldVal){ const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal) console.log(res); }, immediate:true, deep:true } } } </script> <style lang="less" scoped> </style>
如上笔记所示,如果对象中的每一个属性发生变化时,都会触发
<template> <div> ....... <input type="text" class="form-control" v-model="info.username"> </div> </template> <script> import axios from 'axios' export default { ....... data(){ return{ ....... info:{ username:'admin' } } }, watch:{ //这里改为属性,用单引号包裹 'info.username':{ async handler(newVal,oldVal){ const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal) console.log(res); } } } } </script> <style lang="less" scoped> </style>
计算属性和侦听器侧重的应用场景不同:
计算属性侧重于监听多个值的变化,最终计算并返回一个新值
侦听器侧重于监听单个数据的变化,最终执行特定的业务处理,不需要有任何返回值
{
}
vue框架为组件内置了不同时刻的生命周期函数,生命周期函数会伴随着组件的运行而自动调用。例如:
①当组件在内存中被创建完毕之后,会自动调用created函数
②当组件被成功的渲染到页面上之后,会自动调用mounted函数
③当组件被销毁完毕之后,会自动调用unmounted函数
当组件被重新渲染的时候,会自动调用updatad函数
....... <script> export default { name:'lifeCycle', created(){ console.log('created'); }, mounted() { console.log('mounted'); }, updated(){ console.log('updated'); }, unmounted(){ console.log('unmounted'); } } </script> .......
{
}
{
}
在main.js 入口文件中,通过app.config.globalProperties全局挂载axios
{
}
ref用来辅助开发者在不依赖于jQuery的情况下,获取DOM元素或组件的引用。
每个vue的组件实例上,都包含一个$refs对象,里面存储着对应的DOM元素或组件的引用。默认情况下,组件的$refs指向一个空对象。
相当于打一个锚点,并操作 \color{red}{相当于打一个锚点,并操作} 相当于打一个锚点,并操作
让文本框自动获得焦点的方法: . f o c u s ( ) \color{red}{.focus()} .focus()
Dom更新是异步的,因此获取引用对象的时候会出现未定义,因此需要延迟执行,比如方法
this.$nextTick(()=>{ ...... this.$refs.ipt.focus() })
- 1
- 2
- 3
- 4
在vue3中,可以声明动态组件 c o m p o n e n t \color{red}{component} component来让组件动态的展示,其中 i s \color{red}{is} is参数可以指明现在的所展示的组件
<template> <div> <button @click="ckHome">首页</button> <button @click="ckMovie">电影</button> <hr> <component :is="conName"></component> </div> </template> <script> import movie from './components/movie.vue'; import home from './components/home.vue'; export default { name:'App', components:{ movie, home, }, data() { return { conName:'home' } }, methods:{ ckHome(){ this.conName = 'home' }, ckMovie(){ this.conName = 'movie' } } } </script> <style> </style>
但是有一个弊端,当组件被切换时,默认将会销毁旧组件,里面的值也会随之被销毁,解决办法就是在 c o m p o n e n t \color{red}{component} component外添加 < k e e p − a l i v e > \color{red}{<keep-alive>} <keep−alive>组件保持动态组件的状态
<template>
<div>
<button @click="ckHome">首页</button>
<button @click="ckMovie">电影</button>
<hr>
<keep-alive>
<component :is="conName"></component>
</keep-alive>
</div>
.......
</template>
如果没有预留插槽,那么自定义的任何内容都将被遗弃
如果在封装组件的时候预留了多个插槽并声明了具体的name名称
<slot name="xxx"></slot>
如果只有一个插槽,且未命名,则默认名称为 d e f a u l t \color{red}{default} default
App.vue:
<template> <div> <button @click="ckHome">首页</button> <button @click="ckMovie">电影</button> <hr> <keep-alive> <component :is="conName"> <template v-slot:header> <h1>滕王阁序</h1> </template> <template v-slot:body> 唧唧复唧唧,木兰当不知 《懒得打,乱编的》 </template> <template v-slot:footer> <h4> 王博 </h4> </template> </component> </keep-alive> </div> </template> <script> import movie from './components/movie.vue'; import home from './components/home.vue'; export default { name:'App', components:{ movie, home, }, data() { return { conName:'home' } }, methods:{ ckHome(){ this.conName = 'home' }, ckMovie(){ this.conName = 'movie' } } } </script> <style> </style>
movie.vue:
<template> <div> <header> <slot name="header"></slot> </header> <main> <slot name="body"></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> </template> <script> export default { name:'move' } </script> <style> </style>
具名插槽 v − s l o t : \color{red}{v-slot:} v−slot:可以替换成 # \color{red}{\#} #
相当于子传父
父组件 — App.vue:
<template v-slot:body="info">
唧唧复唧唧,木兰当不知
{{info}}
</template>
在插槽后面跟一个 = " i n f o " \color{red}{="info"} ="info"可以传递一个对象,info可以看做形参
子组件 — movie.vue:
<template> <div> ...... <main> <slot name="body" :info="da" :msg="ya"></slot> </main> ...... </div> </template> <script> export default { name:'move', data() { return { da:'这是一条数据', ya:'这是第二条数据' } }, } </script> ......
所显示:
在default之后可以直接指定数据,更加方便
vue 官方提供了v-for、v-model、v-if等常用的内置指令。除此之外vue还允许开发者自定义指令。
vue中的自定义指令分为两类,分别是:
私有自定义指令 \color{red}{私有自定义指令} 私有自定义指令&&& 全局自定义指令 \color{red}{全局自定义指令} 全局自定义指令
使用自定义指令必须以’v-’开头,声明不需要开头
这里使用了mounted钩子函数
{
<template> <div> directives!! 自动获得焦点 <h1> <input type="text" v-focuss > </h1> <slot name="header"></slot> </div> </template> <script> export default { name:'directives', data() { return { } }, directives:{ focuss:{ // 被绑定到的函数渲染后自动触发mounted这个函数 mounted(el) { // 用focus获取焦点 el.focus(); }, } } } </script> <style lang="less" scoped> </style>
}
在项目的main.js中:
{
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
import './assets/bootstrap-3.4.1-dist/css/bootstrap.css'
const app = createApp(App)
app.directive('focus',{
mounted(el){
el.focus()
}
})
app.mount('#app')
}
}
在上面的z局部自定义函数中的代码有一个不足之处,当mounted 函数只在元素第一次插入DOM时被调用,当点击+1后,会失去焦点
当DOM更新时
m
o
u
n
t
e
d
函数
\color{red}{mounted函数}
mounted函数不会被触发。updated函数会在每次DOM更新完成后被调用。
添加update函数后
在vue2项目中,名称有所不同【mounted -> bind】【updated -> update】
mounted和updated的业务逻辑如果相同可以使用简写形式
app.directive('focus',(el)=>{
el.focus();
})
在自定义指令中可以通过 = " X X X " \color{red}{="XXX"} ="XXX"来传递参数值
在vue自检中:
<input type="text" v-focus v-color="'red'">
main.js中:
app.directive('color',(el,binding)=>{
//第二个参数为形参
el.style.color=binding.value;
})
blur与change事件在绝大部分的情况下表现都非常相似,输入结束后,离开输入框,会先后触发change与blur,唯有两点例外。
1、没有进行任何输入时,不会触发change
在这种情况下失焦后,输入框并不会触发change事件,但一定会触发blur事件。在判断表单的修改状态时,这种差异会非常有用,通过change事件能轻易地找到哪些字段发生了变更以及其值的变更轨迹。
2、输入后值并没有发生变更
这种情况是指,在没有失焦的情况下,在输入框内进行的删除与输入操作,但最终的值与原值一样,这种情况下失焦后,keydown、input、keyup、blur都会触发,但change依旧不会触发。
后端路由指的是:请求方式、请求地址与function 处理函数之间的对应关系。
SPA指的是一个web网站只有唯一的一个HTML页面,所有组件的展示与切换都在这唯一的一个页面内完成。
此时,不同组件之间的切换需要通过前端路由来实现。
Hash地址与组中的联系
用户点击了页面上的路由链接
导致了URL地址栏中的Hash值发生了变化
前端路由监听了到Hash地址的变化
前端路由把当前Hash地址对应的组件渲染都浏览器中
cnpm i vue-router@next -S
后面为类名
linkActiveClass:‘XXXX’,
通过冒号(:)可以定义后面的参数是可变的
如/home/:XXX
参数值可以通过 $ r o u t e . p a r a m s \color{red}{route.params} route.params来获取XXX
也可通过prop传参
(1)在动态路由规则开启动态传参 props:true
(2)在子组件使用props数组进行接收
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。