1 Star 0 Fork 1

孙烨/vue-learning

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
README.txt 45.07 KB
一键复制 编辑 原始数据 按行查看 历史
孙烨 提交于 2023-01-18 18:35 . 初始化头条项目,清楚多与代码
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
第一天:webpack vue前置知识点
一:webpack基本使用
1.新建基本src目录index.html index.js文件
2.npm init -y 创建package.json文件
3.npm install jquery -S 安装jQuery,会记录到package.json文件
4.import $ from 'jquery' 通过es6方法导入jQuery到index.js
5.npm install webpack webpack-cli -D 安装webpack并记录到package.json文件
6.根目录中创建webpack.config.js的webpack配置文件
module.exports = {
mode: 'development' //webpack运行模式,开发环境一般使用development 生产中用production
}
7.package.json中的scripts节点下增加dev脚本:
8.npm run dev运行webpack再目录下生成../dist/main.js包含了index.js和jQuery.js
9.index.html中引入生成的main.js即可
二:webpack配置文件进一步使用
1.webpack默认打包的main.js并未做压缩,仍然保留注释以及换行等
2.将webpack.config.js中的mode模式由development设置为production
3.重新运行webpack脚本 npm dev
三:webpack执行说明:
1.npm run dev 执行的是package.json中的script脚本中的dev所对应的webpack命令
2.执行webpack命令会到webpack.config.js中按照mode所指定的模式进行打包
3.如果webpack.config.js不做指定配置,webpack版本4/5会默认寻找../src/index.js,默认输出到../dist/main.js
4.自定义输入输出再webpack.config.js配置文件中通过entry和output节点指定出入口,
使用path变量需要先导包const path = require('path') __dirname表示当前文件的路径
一般entry写法 entry: path.join(__dirname,'./src/index1.js')
一般output写法
四:每次修改源码需要重新npm run dev才能生效问题处理
1.自动打包配置插件 webpack-dev-server监听项目代码变动并执行重新发包
2.安装命令 npm install webpack-dev-server -D
3.package.json中script脚本中的dev改为"dev": "webpack serve"
4.执行npm run dev 并发现项目一直启动并监听修改,每次修改都会重新打包
问题:打开之后get无法请求
配置webpack.config.js增加devServer节点指定根目录
devServer: {
static: "./",
},
问题:打开之后需要点击src才能进入页面
安装html-webpack-plugin插件
npm instal html-webpack-plugin -D
配置webpack.config.js
1.const HtmlPlugin = require('html-webpack-plugin')//导入html插件获得构造函数
2.//通过构造函数创建html插件的实例对象
const html = new HtmlPlugin({
template:'./src/index.html',//需要复制的页面
filename:'./index.html'//需要复制到的位置
});
3.module.exports = {
//需要执行的插件数组
plugins:[html]
}
问题:npm run dev之后不能自动打开浏览器..
配置webpack.config.js中增加devServer节点
devServer:{
open:true,
port:80
}
五:webpack loader加载器介绍
1.webpack默认只能处理.js结尾的文件其他非.js需要对应的loader来进行处理
2.webpack打包-判断js模块-是否包含高级js语法,通过webpack处理或使用babel寻找loader处理
-寻找对应的loader模块
3.如果在js中使用import导入css文件会导致
ERROR in ./src/css/index.css 1:3
Module parse failed: Unexpected token (1:3)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
4.安装支持css文件的loader
npm i style-loader css-loader -D
webpack.config.js中的module节点中的rules数组增加匹配规则
module: {
rules:[
//定义不同模块对应的loader,有顺序的 style-loader处理完交给css-loader,全都处理完之后交付给webpack并打包到内存中
{test: /\.css$/,use:['style-loader','css-loader']},
]
}
5.安装支持less文件的loader
npm i less-loader less -D
webpack.config.js中的module节点中的rules数组增加匹配规则
{test: /\.less$/,use:['style-loader','css-loader','less-loader']}
6.安装支持文件和url的loader
npm i url-loader file-loader -D
//大于500字节的数据转为base64处理
{test: /\.jpg|png|gif$/,use:['url-loader?limit=500']}
7.部分高级js语法webpacket默认可能也不能处理,比如@装饰器
安装babel-loader
npm i babel-loader @babel/core @babel/plugin-proposal-decorators @babel/plugin-proposal-class-properties -D
配置加载器,排除第三方包不要对他们做更改
{test: /\.js$/,use:['babel-loader'],exclude:/node_modules/}
创建配置文件,根目录下创建bebel.config.js加载babel插件
module.exports = {
"plugins": [
["@babel/plugin-proposal-decorators", { "version": "legacy" }],
"@babel/plugin-proposal-class-properties"
]
}
六:项目build打包上线
1.将内存中的文件放到磁盘中
package.json的script节点增加build命令并加上参数,否则会读取配置文件中的参数开发环境一般为developement
"build":"webpack --mode production"
2.装个clean工具能自动把打包文件给删除
npm.js官网找一下参照文档装clean-webpack-plugin
使用的时候需要确保输出目录不被占用,否则不会被自动clean
七:SourceMap的使用
1.用于储存webpacket打包前后文件的位置信息,便于找到原位置
2.webpack.config.js中mode同级增加参数
devtool: 'eval-source-map',//开发调试阶段通过sorceMap使得打包后和打包前行号保持一致
使得开发中可以通过控制台定位到源代码的位置
3.webpack.config.js中mode同级增加参数
devtool: 'nosources-source-map',//发布阶段通过sorceMap使得打包后和打包前行号保持一致
但不可以通过控制台定位到源代码的位置
4.webpack.config.js中mode同级增加参数
devtool: 'source-map',//发布阶段通过sorceMap使得打包后和打包前行号保持一致
并且可以通过控制台定位到源代码的位置
八:webpacket的真实配置
1.webpack工作环境中有工具一键生成
上面介绍只做原理介绍,实际中开发很少直接进行修改....
2.拓展@
前端路径可能比较复杂,如果使用相对路径会比较凌乱
一般约定使用@表示项目src路径,统一使用@路径由外往里找而不是使用相对路径由某个点开始
配置:
webpack.config.js
新增 resolve 节点声明 alias 属性增加键值对 '@':path.join(__dirname,'./src/')
resolve:{
alias:{
'@':path.join(__dirname,'./src/')
}
}
九:安装vue.js devtools调试工具
这是一个浏览器插件,安装完需要配置允许访问文件url
第二天:了解vue
一:vue介绍
1.概念:构建用户界面的前端框架
包括指令、组件、路由、vueX、组件库等...
2.特性:
数据驱动视图-vue监听数据变化来渲染页面结构,此为单向数据改变引起页面改变
双向数据绑定-在网页中from表单负责采集数据,ajax负责佛则提交数据写表单时数据变化奖备案too
3.MVVVM
model:数据源
view:当前页面的dom结构
viewModel:vue的实例,检测model和view并做同步或更新,是核心
二:vue基本使用
1.使用步骤:
1.导入vue.js的脚本
<script src="./lib/vue-2.7.10.js"></script>
2.创建vue实例对象
const vm = new Vue({
/* 当前vm实例需要控制的dom区域,el的值是一个选择器 */
el: '#app',
/* data 需要渲染到页面的数据 */
data:{
username:'zhangsan',
},
});
3.使用vue为需要的dom元素填充数据
<div id="app">{{ username }}</div>
2.指令:
vue的模板语法,辅助开发渲染页面基本结构共有六类都很重要也很简单基础
内容渲染、属性绑定、事件绑定、双向绑定、条件渲染、列表渲染
1.内容渲染指令:{{}}
1.v-text 渲染文本内容 覆盖原始内容
<!-- 将要被vue控制的div,把数据填充过来 -->
<div id="app">
<p v-text="username"></p>
<p v-text="gender">性别</p>
</div>
<script src="./lib/vue-2.7.10.js"></script>
<script>
const vm = new Vue({
el: '#app',
data:{
username:'zhangsan',
gender:'女',
},
});
</script>
2.{{}} 插值表达式 渲染文本内容 不会覆盖原始内容
<p >姓名 {{username}}</p>
<p >性别 {{gender}}</p>
3.v-html 渲染标签内容
info:'<h4 style="color:red;font-weight:bold;">高级消息...</>'
<div v-html="info"></div>
2.属性绑定指令:v-bind: 简写 :
-----------------------分割线---------
此处先暂停,先补充一下node.js相关知识点
--------------------------------------
回来了^_^,node.js可查看 https://gitee.com/qq2528825468/node-js-learn
--------------------------------------
1.原因:插值表达式只能用于标签内容节点中,不能用于标签属性节点
2.使用:v-bind: (可省略只写:)
<!-- 将要被vue控制的div,把数据填充过来 -->
<div id="app">
<input type="text" v-bind:placeholder=tips>
</div>
<script src="./lib/vue-2.7.10.js"></script>
<script>
const vm = new Vue({
el: '#app',
data:{
tips:'请输入用户名',
},
});
</script>
3.运算
模板渲染中可进行简单的运算处理
{{number+1}}
{{ok?'YES':'NO'}}
{{message.split('').reverse().join('')}}
<div v-bind:id="'list-'+id"></div>
3.事件绑定指令v-on: 简写 @
1.需要绑定事件处理函数使用
2.使用 v-on:
<!-- 将要被vue控制的div,把数据填充过来 -->
<div id="app">
<p> count的值:{{count}}</p>
<button v-on:click="add()">+n</button>
</div>
<script src="./lib/vue-2.7.10.js"></script>
<script>
/* vue实例对象 */
const vm = new Vue({
/* el指定页面控制区域 */
el: '#app',
/* 控制区域内所需要渲染的数据 */
data:{
count:1,
},
/* 控制区域所需要渲染的事件处理函数 */
methods: {
add(n) {
this.count++
}
},
});
</script>
3.获取原生DOM事件的事件对象
传参时 不传参或者使用 $event, 表示获取原生DOM事件的事件对象
4.事件修饰符
vue用于在事件绑定时对元素标签动作的修饰
<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>
<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>
<!-- 也可以只有修饰符 -->
<form @submit.prevent></form>
<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>
4.按键修饰符
<!-- 仅在 `key` 为 `Enter` 时调用 `submit` -->
<input @keyup.enter="submit" />
Vue 为一些常用的按键提供了别名:
.enter
.tab
.delete (捕获“Delete”和“Backspace”两个按键)
.esc
.space
.up
.down
.exact 修饰符 修饰符允许控制触发一个事件所需的确定组合的系统按键修饰符
<!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 仅当没有按下任何系统按键时触发 -->
<button @click.exact="onClick">A</button>
鼠标按键修饰符:
.left
.right
.middle
<button @click.right="shout(1)">ok</button>
4.表单输入绑定指令
1.用于表单标签和js变量进行双向数据绑定
<input v-model="text"> input中实时展示text数据
非表单标签,虽然可以展示数据但用户不能修改数据,所以双向数据绑定并无实际意义
2.修饰符:
.lazy
默认情况下,v-model 会在每次 input 事件后更新数据 (IME 拼字阶段的状态例外)。
你可以添加 lazy 修饰符来改为在每次 change 事件后更新数据:
<!-- 在 "change" 事件后同步更新而不是 "input" -->
<input v-model.lazy="msg" />
.number
如果你想让用户输入自动转换为数字,你可以在 v-model 后添加 .number 修饰符来管理输入:
如果该值无法被 parseFloat() 处理,那么将返回原始值。
number 修饰符会在输入框有 type="number" 时自动启用。
<input v-model.number="age" />
.trim
如果你想要默认自动去除用户输入内容中两端的空格,你可以在 v-model 后添加 .trim 修饰符:
<input v-model.trim="msg" />
5.条件渲染指令
1.v-if v-show
1.用法
<div id="app">
<p v-if="flag_view">v-if 控制的数据</p>
<p v-show="flag_view">v-show 控制的数据</p>
</div>
<script>
/* vue实例对象 */
const vm = new Vue({
/* el指定页面控制区域 */
el: '#app',
/* 控制区域内所需要渲染的数据 */
data:{
/* flag_view true展示数据 false隐藏数据 */
flag_view:true
},
/* 控制区域所需要渲染的事件处理函数 */
methods: {
},
});
</script>
2.区别
v-if使用的是真实标签是否存在
v-show使用的是标签的css样式 display 属性值的切换
总的来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
因此,如果需要频繁切换,则使用 v-show 较好
如果在运行时绑定条件很少改变,则 v-if 会更合适。
3.<template> 上的 v-if
(----------------!!!存疑,在html中这样写是不可以的)
因为 v-if 是一个指令,他必须依附于某个元素。但如果我们想要切换不止一个元素呢?
在这种情况下我们可以在一个 <template> 元素上使用 v-if,这只是一个不可见的包装器元素,
最后渲染的结果并不会包含这个 <template> 元素。
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
6.列表渲染指令
1.v-for
我们可以使用 v-for 指令基于一个数组来渲染一个列表。
v-for 指令的值需要使用 item in items 或者 (item in items) in items
形式的特殊语法,其中 items 是源数据的数组,而 item 是迭代项的别名:
<tbody>
<tr v-for="(item,index) in list">
<td>{{index}}</td>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
</tr>
</tbody>
data:{
list:[
{id:1,name:'孙烨'},
{id:2,name:'孙花花'}
]
},
2.说明
v-for 的默认方式是尝试就地更新元素而不移动它们。要强制其重新排序元素,你需要用特殊 attribute key 来提供一个排序提示:
不要用index作为key值,index是数据在生成之后的顺序值,如果数据变化(或者排序)那么数据所对应的index就会被改变
例如: <li v-for="item in list" :key="item.id">name is : {{item.name}} </li>
3.过滤器
1.说明:
过滤器只在vue2中存在,过滤器可串联调用并可进行传参,vue3已删除该功能,该部分不做详细说明
在 3.x 中,过滤器已移除,且不再支持。取而代之的是,官方建议用方法调用或计算属性来替换它们。
https://v3-migration.vuejs.org/zh/breaking-changes/filters.html
2.全局过滤器:
new vue实例之前挂载到vue构造函数上面
3.局部过滤器:
vue实例初始化之后通过filters属性挂载到实例中
局部过滤器优先级高于全局过滤器
4.侦听器watch
1.说明:
用于监听数据的变化,watch中声明,可进行函数式声明或者对象式声明
new Vue({
/* 监听器 */
watch:{
/* 方法形式的监听器-不能页面初始化时进行触发 */
message(newVal,oldVal){
console.log(newVal+"方法形式的监听器"+oldVal)
}
},
message:{
handler: function(newVal,oldVal){
console.log(newVal+"对象形式的监听器"+oldVal)
},
immediate:true, /*初始化时是否调用*/
deep: true /* 深度监听,监听对象的每一个属性的变化 */
}
})
2.深层侦听
直接给 watch() 传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发
3.属性监听
如果要监听对象的某个属性,可以直接声明
用小括号将监听器方法包起来
'user.name'(newVal,oldVal){}
5.计算属性
1.说明:
定义到computed节点下,定义为方法形式,使用为数据形式
2.示例:
<input type="text" v-model="message">
<p>{{this.myComputed}}</p>
data:{
message:"hello vue.js",
},
computed:{
myComputed:function(){
return `plus- ${this.message}`
}
}
5-1.axios
1.说明:
基于 promise 网络请求库,作用于node.js 和浏览器中
2.使用:
普通使用和async-await使用
https://www.axios-http.cn/docs/example
3.解构赋值
1.直接使用
const username = {id:123,username:"lihua"}.username
等同于
const {username} = {id:123,username:"lihua"}
2.重命名
const name = {id:123,username:"lihua"}.username
等同于
const {username:name} = {id:123,username:"lihua"}
6.vue-cli
1.单页面应用程序
一个前端项目,只有一个html页面
2.说明:
vue-cli简化了webpack创建项目的过程
可以专注于编写应用程序,而不是花费数天时间争论配置
3.使用:
npm install -g @vue/cli
vue create demo-first
选组件
npm run serve
4.目录结构
public-图标和首页HTML
src-源代码
assets-静态资源
components-组件
main.js-入口文件
APP.vue-项目根组件
5.vue的本质作用:
通过main.js将App.vue的内容渲染到inde.html中
7.vue组件
1.说明:
将页面可以重用的ui结构封装为组件达到复用的目的
vue支持组件化开发,后缀名为.vue,默认的APP.vue就是一个组件
2.组成:
template模板结构
script js行为
style 组件的样式,有默认的结构且data需要以函数的形式出现,如果使用less则style中增加lang="less"
3.父子关系:
嵌套的使用组件,组件和组件间形成了父子关系或者兄弟关系
4.组件的使用
1.父组件中import导包子组件
2.在components节点中注册组件
3.以标签的形式使用子组件
import left from '@/components/left.vue'
import right from '@/components/right.vue'
export default {
components:{
left,right_reName:right
},
<left_name></left_name>
<right_reName></right_reNames>
5.私有组件:
通过在components节点中注册组件都是私有组件
A components B
B只能在A中使用
6.全局组件
main.js中使用Vue.component()方法进行注册
示例main.js:
import Global from '@/components/gloable.vue'
Vue.component('Global_name',Global)
7.props
组建的自定义属性,合理利用可提高组件复用性,props是只读的应避免直接对其进行修改,应转存到data数据进行修改
props节点下增加自定义属性
示例:
export default {
props:['init'],
}
<Global_name init="App参数props"></Global_name>
也可以使用复杂形势
所有 prop 默认都是可选的,除非声明了 required: true
type 数据类型
default 默认的初始值
export default {
props:{
init:{
default:"default_name",
type:number
required: true
}
},
8.样式冲突
<style lang="less" scoped>
scoped,则当前组件的所有标签会生成唯一属性,防止组件间样式相互影响
如果父组件引用子组件后,父组件需要修改子组件样式
9.deep的使用
使用 scoped 后,父组件的样式将不会渗透到子组件中
处于 scoped 样式中的选择器如果想要做更“深度”的选择,也即:影响到子组件,可以使用 :deep() 这个伪类:
8.生命周期:
1.说明:
组件从创建、运行、销毁的过程
通过声明周期函数,可在声明周期各个时间点去执行某些事件
创建:new vue->before-create->created->before-mount-mounted
运行:before-update->updated
销毁:before-destroy->destroyed
2.使用:
常在created阶段进行ajax请求将数据转存到data供页面渲染使用
常在mounted阶段操作dom元素
9.数据共享
1.父向子组件之间数据共享
自定义属性:父组件使用子组件,通过props 进行数据传递
2.子向父组件之间数据共享
子组件通过this.$emit('事件名',需要传输数据)触发自定义事件
父组件中通过标签属性@事件名="事件函数"进行监听数据
mounted(){
/* 生命周期中将数据传到父组件 */
this.$emit("myEmit",this.username)
}
<right_name @myEmit="showData"></right_name>
methods: {
showData(val){
console.log(val)
}
},
3.子组件和子组件之间数据共享
1.bus.vue,数据传输对象
<script>
import Vue from 'vue'
export default new Vue()
</script>
2.数据发送方,触发自定义事件
import busVue from './bus.vue';
busVue.$emit('share',this.username)
3.数据接收方,监听自定义事件
import busVue from './bus.vue';
busVue.$on('share',function(val){
console.log('接受share数据'+val)
})
10.ref引用:
1.说明:
辅助开发者不依赖jquery的情况下,获取dom元素或组件的引用
2.使用:
在html标签或者组件标签上使用ref="ref_name"标记
则在vue实例中可用this.$refs中找到所标记的引用标签
3.场景:
使用ref的方式,可以方便的在父组件中修改子组件的数据...
比起props或者bus或者$emit传值要简单得多
4.延迟:
ref引用改变之后可能涉及到页面重新渲染,某些代码可能需要在渲染结束之后才应执行
可以使用this.$nextTick(function(){需要延迟到渲染后执行执行的})
11.js数组复习
1.foreach循环
无法被终止,一旦开启遍历会将数据全部遍历结束
2.some循环
return true之后会终止循环
3.every循环
判断数组每项是否满足一定条件,如果都满足返回true,存在不满足返回false
4.reduce循环
reduce函数,如果不指定初始值则初始值为数组第一个元素,从数组1位置开始循环
指定初始值则从数组0位置开始循环
三、案例复习
1.说明:
下载demo-cart项目并npm install、npm run serve启动项目
这是一个购物车案例
如果node版本高于17,需要在package.json中修改scrips标签
"scripts": {
"serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve",
"build": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build"
},
2.实现步骤
1.初始化项目基本结构
2.使用header组件
App.vue中
<Header></Header>
<h1>App 根组件</h1>
import Header from '@/components/Header/Header.vue'
3.通过axios请求商品列表数据
get https://www.escook.cn/api/cart
npm install axios -S
App.vue中使用axios发请求
async initCartList(){
const{data:res} = await axios.get('https://www.escook.cn/api/cart')
console.log(res)
}
将数据存到data数据中
data() {
return {
//存储获取到的购物车数据,默认为空数组
list:[]
}
},
获取数据的函数增加data转存赋值
if(res.status===200){
this.list = res.list
}
4.使用Footer组件
5.使用Goods组件
6.使用Count组件
四、深入组件逻辑复用
1.介绍:
本节共包含三个主要知识点
动态组件,实现组件的按需切换
插槽,使用组件的时候内容节点的使用和渲染
自定义指令,除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外,Vue 还允许你注册自定义的指令
2.动态组件:
通过 Vue 的 <component> 元素和特殊的 is attribute 实现的:默认组件切换会销毁组件
1.使用:
<component is="Left"></component>
或者和v-bind连用
<component :is="comName"></component>
2.缓存<KeepAlive> 是一个内置组件,它的功能是在多个组件间动态切换时缓存被移除的组件实例
<keep-alive>
<component :is="comName"></component>
</keep-alive>
3.对缓存组件的生命周期监听
组件第一次将会触发created,但是后续激活只会触发activated
组件失效的时候会触发deactivated
4.精准控制缓存组件
默认情况下keep-alive内的所有标签都会被缓存
但是如果需要对部分组件缓存或者排除部分缓存组件,可以使用include 和 exclude
prop 允许组件有条件地缓存。二者都可以用逗号分隔字符串、正则表达式或一个数组来表示:
示例:
<keep-alive exclude="Left">
<component :is="comName"></component>
</keep-alive>
5.补充说明:
exclude、exclude根据组件名称进行排除,第一优先级是根据组件内部显式声明的名称为主
如果组件内部没有显示声明名称,则使用组件时的注册名称就是组件的声明名称
组件的注册名称是给vue用的,组件的名称应该是给开发者看的,比如vue调试工具中组件会展示组件名称
3. 插槽
1.说明:
在之前的章节中,我们已经了解到组件能够接收任意类型的 JavaScript 值作为 props,但组件要如何接收模板内容呢?在某些场景中,我们可能想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。
2.使用:
<FancyButton> 组件
<FancyButton>
Click me! <!-- 插槽内容 -->
</FancyButton>
<FancyButton> 的模板
<button class="fancy-btn">
<slot></slot> <!-- 插槽出口 -->
</button>
3.插槽的出口slot可以存在多个,通过名称区分,如果不显式声明则name="default",这种带名字的称为具名插槽
<FancyButton> 组件
<template v-slot:mySlot>
<FancyButton>
Click me! <!-- 插槽内容 -->
</FancyButton>
</template>
<FancyButton> 的模板
<button class="fancy-btn">
<slot name="mySlot"></slot> <!-- 插槽出口 -->
</button>
4.v-slot 有对应的简写 #
另外子组件的属性可以在父组件中获取到,这种插槽称之为作用于插槽,接受子组件结果时可以通过结构赋值
<FancyButton> 组件
<template v-slot:mySlot="obj">
<FancyButton>
Click me! <!-- 插槽内容 -->
{{obj.msg}}
</FancyButton>
</template>
<FancyButton> 的模板
<button class="fancy-btn">
<slot name="mySlot" msg="hello vue"></slot> <!-- 插槽出口 -->
</button>
4.自定义指令
1.说明:
除了 Vue 内置的一系列指令 (比如 v-model 或 v-show) 之外,Vue 还允许你注册自定义的指令
2.私有自定义指令使用:
vue对象中再directives节点下声明私有自定义指令
directives:{
sunye:{
/* 指令第一次和元素绑定时会触发bind函数,参数为所绑定的dom元素对象 */
bind:function(el,binding){
el.style.color=binding.value
}
}
},
在标签中使用
<h1 v-sunye="colorName">App 根组件</h1>
<h1 v-sunye="'green'">App 根组件</h1>
3.生命周期:
自定义指令有一些生命周期-或者称之为钩子函数
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
4.全局声明:
将一个自定义指令全局注册到应用层级也是一种常见的做法,用在main.js中
const app = createApp({})
// 使 v-focus 在所有组件中都可用
app.directive('focus', {
/* ... */
})
五、路由:
1.说明:
路由就是一个对应关系,哈希地址(锚点地址)和组件的对应关系
工作方式,就是点击页面路由链接(本质就是A链接或者锚点链接)之后,url地址栏中哈希值发生变化
前端路由检测到地址变化,将哈希地址对应的组件渲染到页面上
2.vue中router的使用
1.安装vue-router包
npm i vue-router@3.6.5
2.创建路由模块
创建router文件夹和index.js作为路由模块
3.导入并挂载路由模块 router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
const router = new VueRouter()
Vue.use(VueRouter)
export default router
或者在main.js中vue实例化的时候进行声明
import Vue from 'vue'
import App from './App.vue'
import router from '@/router/index.js'
new Vue({
render: h => h(App),
router:router
}).$mount('#app')
4.声明路由链接和占位符
<router-view/>占位符标签,进行组件渲染的位置占位
路由关系在router/index.js中声明
/* 实例化router对象 */
const router = new VueRouter({
routes:[
{path:'/Home',component:Home},
{path:'/Movie',component:Movie},
{path:'/About',component:About}
]
}
)
3.路由嵌套
1.模板内容中有自己的(子集)路由连链接
写法一致,就是套娃而已,使用children属性
const router = new VueRouter({
routes:[
{path:'/Home',component:Home},
{path:'/Movie',component:Movie},
{path:'/About',redirect:'/About/tab1',component:About,
/* 声明子路由规则 */
children:[
{path:'tab1',component:tab1},
{path:'tab2',component:tab1},
]
},
4.动态路由:
1.处理restfull风格请求,比如说请求 /movie/1 /movie/2 /movie/3
表示请求中的地址本质上是一个参数
2.解决,使用路径参数:标记
/movie/:movieId 即可匹配到url地址 /movie/*
3.说明:
不过这里要说明一下,当参数发生变化时,会映射到相同路由
原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。
不过,这也意味着组件的生命周期钩子不会再被调用。
---如果对参数的变化需要重新渲染组件,可以通过监听router对象的属性,或者通过导航守卫
4.router对象
this.$route.params 可以获取到url中的路径/movie/:id参数信息
this.$route.query 获取查询参数/movie?id=1使用
当然一般不这么用,在组件中使用 $route 会使之与其对应路由形成高度耦合
从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。如果需要获取参数可以开启prop传参
路由模块 props:true
{path:'/Movie/:id',component:Movie,props:true},
vue模块定义参数
props: ["id"],
5.导航:
1.说明:
除了使用 <router-link> 创建 a 标签来定义导航链接,称为声明式导航
我们还可以借助 router 的实例方法,通过编写代码来实现比如说js中的location.href,称为编程式导航
2.编程式导航api
在 Vue 实例内部,你可以通过 $router 访问路由实例。因此你可以调用 this.$router.push
router.push(location, onComplete?, onAbort?)
在3中只有一个参数,所以后两个可选参数不多说明了
router.push保留历史记录、 router.replace不保留历史记录 和 router.go前进或者后退历史记录
跟 window.history.pushState、 window.history.replaceState 和 window.history.go (opens new window)好像
实际上它们确实是效仿 window.history API 的。
3.命名路由
创建路由实例的时候可以指定name
new VueRouter({
routes: [
{
path: '/user/:userId',
name: 'user',
component: User
}
]
})
使用的时候可以通过name调用,而不需要写path
router.push({ name: 'user', params: { userId: 123 } })
4.命名视图
默认router-view标签只有一个,这也表明只有一个渲染出口
如果你需要多个,可以对渲染出口视图命名(可以嵌套使用)
<router-view class="view one"></router-view>
<router-view class="view two" name="a"></router-view>
<router-view class="view three" name="b"></router-view>
路由实例定义
const router = new VueRouter({
routes: [
{
path: '/',
components: {
default: Foo,
a: Bar,
b: Baz
}
}
]
})
6.导航守卫:
1.说明:
“导航”表示路由正在发生改变,导航守卫主要用来通过跳转或取消的方式守卫导航。
这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。
--比如说可以控制不登录不能访问服务页面(通过跳转或者取消跳转的方式对导航进行限制)
2.全局前置守卫
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。
通过router对象进行声明,多在main.js或者router.js中声明
vue3的next参数作为可选参数,如果使用next需要保证next函数只会被调用一次,否则将进入无限的路由跳转死循环中
参数:
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve 这个钩子。
const router = createRouter({ ... })
router.beforeEach((to, from) => {
// ...
// 返回 false 以取消导航
return false
})
7.demo练习路由
router-five-admin-example
8.创建新的项目练习头条
1.创建项目
vue create demo-six-toutiao-example
选择vue2 eslint标准 less预处理样式
删除生成的组件,清理路由规则
2.安装 vant 库
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
JavaScript
1
https://gitee.com/qq2528825468/vue-learning.git
git@gitee.com:qq2528825468/vue-learning.git
qq2528825468
vue-learning
vue-learning
master

搜索帮助