都2022年了不会还有人不会vue吧
快跟着js同学 学学vue吧
本文章是Vue超详宝典的续集
文章目录
Vue生命周期
- 生命周期回调函数,生命周期函数,生命周期钩子
- Vue在关键的时候帮我们调用一些特殊名称的函数
- 生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的
- 生命周期函数中的this指向的是vm或组件的实例对象
小案例–>div 透明度渐变
<div id="root">
{{name}}
<div :style={opacity}>
hello
</div>
</div>
new Vue({
el:'#root',
data:{
name:'小明',
opacity:1
},
// vue完成模板的解析并把初始值的真实dom元素放入页面后,挂在完毕调用mounted
mounted(){
setInterval(()=>{
this.opacity-=0.01
if(this.opacity<=0) this.opacity=1
},30)
}
})
增加需求,现在想让渐渐消失的消失的效果能够随时停止
<button @click="stop">点我停止</button>
<button @click="opacity=1">点我恢复</button>
methods:{
stop(){
this.$destroy()
}
},
mounted(){
this.timer=setInterval(()=>{
this.opacity-=0.01
if(this.opacity<=0) this.opacity=1
},30)
},
beforeDestroy(){
console.log('vm即将跑路')
clearInterval(this.timer)
}
生命周期示意图
beforeCreate(){
console.log("beforeCreate")
},
created(){
console.log("created")
},
beforeMount(){
console.log("beforeMount")
},
mounted(){
console.log("mounted")
}
常用的生命周期钩子
- mounted 发送ajax请求,启动定时器,绑定自定义事件,订阅消息等【初始化操作】
- beforeDestroy :清除定时器,解除自定义事件,取消消息订阅等【收尾工作】
销毁Vue实例
- 销毁后借助Vue开发者工具看不到任何信息
- 销毁后自定义事件会失效,但原生DOM事件依然有效
- 一般不会再beforeDestroy操作数据,因为即使操作数据,也不会再触发更新流程了
Vue组件化编程
传统方式带来的问题代码复用率低,且不好维护
组件方式
非单文件组件
我们首先简要的说一下Vue中使用组件的三大步骤
- 定义或者叫做创建组件
- 注册组件(全局注册或者局部注册)
- 使用组件 (写组件标签)
如何定义一个组件
- 使用
Vue.extend(options)
创建,其中options和new Vue(options)时传入的那个options几乎一样,但是区别如下: - el不要写 ,因为最终所有的组件都要被一个vm管理,由vm决定服务,由vm中的el决定服务哪个容器,.
- data必须要写成函数–避免组件被重复使用时,数据存在引用关系
- 使用
template
可以配置组件结构
如何注册组件
- 局部注册:靠new Vue的时候传入components选项
- 全局注册:靠Vue.component(‘组件名’,组件)
编写组件标签
<组件名></组将名>
案例演示
<div id="root">
<!-- 3编写组件标签 -->
<school></school>
<hello></hello>
<hr>
<student></student>
</div>
Vue.config.productionTip=false
// 1创建school 组件
const school=Vue.extend({
// el:'#root' 一定不要写el配置项,
template:`
<div>
<h3>学校{{schoolName}}</h3>
<h3>地址{{address}}</h3>
</div>
`,
data(){
return{
schoolName:'Vue学院',
address:'B站'
}
}
})
// 创建student 组件
const student=Vue.extend({
// el:'#root' 一定不要写el配置项理,
template:`
<div>
<h3>学生{{studentName}}</h3>
<h3>年龄{{age}}</h3>
</div>
`,
data(){
return{
studentName:'小明',
age:12
}
}
})
// 1创建全局组件
const hello=Vue.extend({
template:`
<div>
<h2>{{name}}</h2>
</div>
`,
data(){
return{
name:'全局组件'
}
}
})
// 注册全局组件
Vue.component('hello',hello)
new Vue({
el:'#root',
// 2注册组件 (局部注册)
components:{
school:school,
student:student
}
})
组件的注意点
关于组件名的注意事项
- 一个单词组组成:第一种写法(首字母小写) :school 第二种写法:首字母大写:School
- 多个单词组成:第一种写法
kebab-case命名
my-school 第二种写法:CamelCase命名
MySchool (但是需要脚手架) - 组件名尽量回避HTML中已有元素的名称,例如 h2,H2都不行,可以使用name配置项指定组件在开发者工具中呈现的名字
组件标签的使用和注意事项
- 第一种写法:
<school></school>
- 第二种写法:
<school/>
- 不使用脚手架时,
<school/>
会导致后续组件不能渲染 - 一个简写方式
const school= Vue.extend(options)
可以简写为const school=options
组建的嵌套
组件可以像这幅图一样进行嵌套
<div id="root">
<!-- 这个也可以直接放在vue的template里面 -->
<app></app>
</div>
Vue.config.productionTip=false
// 创建student组件作为school的子组件
// 子组件一定要在调用之前也就是父组件之前初始化完毕
const student=Vue.extend({
name:'student',
template:`
<div>
<h3>学生{{studentName}}</h3>
<h3>年龄{{age}}</h3>
</div>
`,
data(){
return{
studentName:'小明',
age:12
}
}
})
// 1创建school组件student的父组件
const school=Vue.extend({
template:`
<div>
<h3>学校{{schoolName}}</h3>
<h3>地址{{address}}</h3>
<!-- 使用子组件 -->
<student></student>
</div>
`,
data(){
return{
schoolName:'Vue学院',
address:'B站'
}
},
// 注册子组件
components:{
student:student
}
})
// 创建hell组件
const hello=Vue.extend({
name:'hello',
template:`
<div>
<h2>{{name}}</h2>
</div>
`,
data(){
return{
name:'hello组件'
}
}
})
// 创建一个app组件作为管理组件
const app=Vue.extend({
name:'app',
template:`
<div>
<hello></hello>
<school></school>
</div>
`,
components:{
hello,
school
}
})
new Vue({
el:'#root',
// 2注册组件 (局部注册)
components:{
app
}
})
VueComponent
- school 组件本质是一个为VueComponent的构造函数,是Vue.extend生成的
- 我们只需要写
<school/> 或者 <school></school>
Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options) - 每次调用Vue.extend返回的都是一个全新的VueComponent
关于this的指向
- 组件配置中:data函数,methods中的函数,watch中的函数,computed中的函数,它们的this均是【VueComponents实例对象】
- .new Vue(options)配置中data函数,methods中的函数,watch中的函数,computed中的函数,它们的this均是【Vue实例对象】
- VueComponent 的实例对象,以后简称vc也可以简称为组件实例对象
重要的内置关系
- 一个重要的内置关系,
VueComponent.prototype.__proto__===Vue.prototype
- 为什么要有这个关系,让组件实例对象vc可以访问到Vue原型上的属性,方法。
// 定义一个构造
function Demo(){
this.a=1
this.b=2
}
// 创建一个Demo的实例对象
const d=new Demo()
// 显示原型属性
console.log(Demo.prototype)
// 隐式原型属性
console.log(d.__proto__)
// 显示原型属性操作原型对象,追加一个x属性
Demo.prototype.x=99
console.log('@'+d.__proto__.x)
单文件组件
首先我们应该先知道单文件组件是个啥?
据我所了解这个单文件组件就是一个个后缀名为 .vue的文件原本的代码都放在html,css ,js
中但是现在可以放在.vue文件中我们将之前写的非单文件组件写成单文件组件。
学校模块
<template>
<div>
<h3>学校{{schoolName}}</h3>
<h3>地址{{address}}</h3>
</div>
</template>
<script>
export default{
name:'School',
data(){
return{
schoolName:'Vue学院',
address:'B站'
}
}
}
</script>
学生模块
<template>
<div id="abc">
<h3>学生{{studentName}}</h3>
<h3>年龄{{age}}</h3>
</div>
</template>
<script>
export default{
name:'Student',
data(){
return{
studentName:'小明',
age:12
}
}
}
</script>
<style>
#abc{
background-color: aqua;
}
</style>
App.vue
<template>
<div>
<School></School>
<Student></Student>
</div>
</template>
<script>
import School from './School.vue'
import Student from './Student.vue'
export default{
name:'App',
components:{
School,
Student
}
}
</script>
import App from './App.vue'
new Vue({
el:'root',
template:`<App></App>`
components:{App},
})
但是现在运行并不能运行成功因为浏览器不认识我们写的东西,所以我们需要对我们写的.vue文件进行解析,这里我用到的是vue-cli脚手架,然后在脚手架里写的东西才可以被解析。
vue脚手架以及目录结构简介
vue create 脚手架名称
现在将我们的组件放进脚手架中
- 将我们写的组件进行替换
- 运行
npm run serve
第一次运行说我的组件名不合乎规范?干
然后我直接修改配置将提示关掉
找到vue.config.js修改配置
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
//关闭eslint校验
lintOnSave: false
})
render函数
我们先把rander给注了用我们自己的方式写 template:
, components:{App},
然后我们看一下报了一个错,大致的意思就是这个模板的编译不可用,如果说我们用的是vue.js怎么可能会出现这样的情况,所以我们Vue的导入模块发现了问题
从这里可以看出引入的是一个runtime版的js。
关于vue的两个不同的版本
- vue.js是完整的Vue,包含着核心功能+模板解析器
- vue.runtime.xxx.js是运行版的Vue,只包含着核心功能
- vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容
ref属性
- 被用来给元素或子组件注册引用信息(id的代替者)
- 应用在html标签上获取的是真实地DOM元素,应用在组件的标签上是组件的实例对象(vc)
- 使用方式:
<template>
<div>
<h1 v-text="msg" ref="title"></h1>
<button ref="btn" @click="showDOM()">点我输出上方DOM元素</button>
<School ref="sch"></School>
<Student></Student>
</div>
</template>
<script>
import School from './components/School.vue'
import Student from './components/Student.vue'
export default{
name:'App',
components:{
School,
Student
},
data:{
return{
mas:'同学你好'
}
},
methods:{
showDOM(){
// 真实DOM元素
console.log(this.$refs.title)
console.log(this.$refs.btn)
// School组件的实例对象
console.log(this.$refs.sch)
}
}
}
</script>
props配置
让组件接收外部传过来的数据
- 传递数据:
<Demo name="xxx"
- 接收数据:第一种方式(只接受)
props:['name']
, - 第二种方式(限制类型)
props:{ name :String }
- 第三种方式(限制类型,限制必要性,指定默认值)
props:{
name:{
type:String,//类型
required:true.//必要性
default:'老王' // 默认值
}
}
备注props是只读的,Vue底层会监视你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要进行修改,那么请复制props的内容到data中一份,然后去修改data中的数据
<!-- 虽然 `19` 是个常量,我们还是需要使用 v-bind -->
<!-- 因为这是一个 JavaScript 表达式而不是一个字符串 -->
<Student :age="19" name="张三"></Student>
<h3>学生{{name}}</h3>
<h3>年龄{{myAge}}</h3>
<button @click="updataAge">点击修改年龄</button>
</div>
</template>
<script>
export default{
name:'Student',
data(){
return{
msg:'我是个学生',
// 找了个中间变量来负责承上启下
myAge:this.age
}
},
methods:{
updataAge(){
this.myAge++
}
},
// 接收的同时对参数进行限制
props:{
name:String,
age:Number
}
}
mixin(混入)
可以把多个组件共用的配置提取成一个混入对象
使用方式:
- 定义混入:
{ data() {....}, methods:{....} ...}
- 使用混入:全局使用 :
Vue.mixin(xxx)
,局部使用:mixins:['xxx']
现在假设在多个组件中都有一个相同的方法,我们想把这方法在外部抽取成一个
首先做一个混入
export const hunhe={
methods:{
showName(){
alert(this.name)
}
},
mounted(){
console.log('你好啊')
}
}
export const hunhe2={
data(){
return {
x:100,
y:200
}
}
}
// 引入混入
import {hunhe,hunhe2} from '../mixin.js'
//使用混入
mixins:[hunhe,hunhe2]
==============================================
<!-- 正常引入方法即可 -->
<button @click="showName">点我展示名字</button>
全局使用
// 全局使用mixin
import {hunhe} from './mixin'
Vue.mixin(hunhe)
Vue插件
插件 (Plugins) 是一种能为 Vue 添加全局功能的工具代码。一个插件可以是一个拥有 install() 方法的对象,也可以直接是一个安装函数本身。安装函数会接收到安装它的应用实例和传递给 app.use() 的额外选项作为参数:
const myPlugin = {
install(app, options) {
// 配置此应用
}
}
编写一个插件
// plugins/i18n.js
export default {
install: (app, options) => {
// 在这里编写插件代码
}
}
引入插件
import plugins from './plugins'
// 使用插件
Vue.use(plugins)
export default{
install(Vue){
// 全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
}),
// 定义全局指令
Vue.directive('fbind',{
// 指令与元素绑定时 (一上来)
bind(element,binding){
element.value=binding.value
},
// 指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
// 指令所在的模板被重新解析时
update(element,binding){
element.value=binding.value
}
}),
// 全局混入
Vue.mixin({
data(){
return {
x:100,
y:200
}
}
})
}
}
scoped样式
scoped有什么用
scoped 属性是 style 标签上的一个特殊属性(布尔值)。表示当前style 里的样式只属于当前模块。(作用域、私有化的思想),关于css的作用域问题,即使是模块化编程下,在对应的模块的js中import css进来,这个css仍然是全局的。导致在css中需要加上对应模块的html的id/class 使用css选择器 保证css的作用域不会变成全局 而被其它模块的css污染。
本文创作时间 一周
创作不易,你们的点赞和关注便是对我的最大的支持
连更中…