VUE学习笔记(2)--组件化编程

目录

2.组件化编程

2.1 模块与组件、模块化与组件化

2.3 render函数

2.4 ref属性

2.5 props属性

2.6 mixin(混合)

2.7 插件

2.8 scoped

2.9 总结todolist

2.10 自定义事件

2.11 全局事件总线

2.12 消息订阅与发布

2.13 nextTick

2.14 Vue封装的过度与动画

2.15 Vue脚手架配置代理

2.16 插槽

2.组件化编程

2.1 模块与组件、模块化与组件化

2.1.1.模块**

  • 理解:向外提供特定功能的js程序,一般就是一个js文件

  • 为什么:js文件很多很复杂

  • 作用:复用js,简化js的编写,提高js运行效率

2.1.2.组件

  1. 理解:用来实现局部(特定)功能效果的代码集合(html/css/js/image…..)

  2. 为什么:一个界面的功能很复杂

  3. 作用:复用编码,简化项目编码,提高运行效率

2.1.3.模块化

当应用中的js都以模块来编写的,那这个应用就是一个模块化的应用。

2.1.4.组件化

当应用中的功能都是多组件的方式来编写的,那这个应用就是一个组件化的应用。

2.2 非单文件组件

  1. 模板编写没有提示

  2. 没有构建过程,无法将ES6转换成ES5

  3. 不支持组件的CSS

  4. 真正开发中几乎不用

2.2.1非单文件组件的基本使用

Vue中使用组件的三大步骤:

1、定义组件(创建组件)

2、注册组件

3、使用组件(写组件标签)

如何定义一个组件?

使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几 乎一样,但也有点区别;

1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器

2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。

备注:使用template可以配置组件结构。

如何注册组件?

1.局部注册:靠new Vue的时候传入components选项

2.全局注册:靠Vue.component('组件名',组件)

编写组件标签(来实现组件复用):

<school></school> <student></student> <hello></hello>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>基本使用</title>
<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<!-- 准备好一个容器-->
<div id="root">
<hello></hello>
<hr>
<h1>{{msg}}</h1>
<hr>
<!-- 第三步:编写组件标签 -->
<school></school>
<hr>
<!-- 第三步:编写组件标签 -->
<student></student>
<student></student>
</div>
<div id="root2">
<hello></hello>
</div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false
​
//第一步:创建school组件
const school1 = Vue.extend({
// el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。
template: `
<div class="demo">
<h2>学校名称:{{schoolName}}</h2>
<h2>学校地址:{{address}}</h2>
<button @click="showName()">点我提示学校名</button>    
</div>
`,
data() {//
schoolName: 
address
},
methods: {
showName() {
alert(this.schoolName)
}
},
})
​
//第一步:创建student组件
const student1 = Vue.extend({
template: `
<div>
<h2>学生姓名:{{studentName}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
`,
data() {
return {
studentName: '张三',
age: 18
}
}
})
​
//第一步:创建hello组件
const hello1 = Vue.extend({
template: `
<div>        
<h2>你好啊!{{name}}</h2>
</div>
`,
data() {
return {
name: 'Tom'
}
}
})
​
//第二步:全局注册组件
Vue.component('hello', hello1)
//创建vm
new Vue({
el: '#root',
data: {
msg: '你好啊!'
},
//第二步:注册组件(局部注册)
components: {
school: school1,
student: student1
// 组件名:中转变量,如果组件名和中转变量一致如school:school则可以写为school
}
})
​
new Vue({
el: '#root2',
})
</script>
</html>
​

2.3 render函数

关于不同版本的Vue:

1、vue.js 与 vue.runtime.js的区别:

(1)vue.js是完整版的vue,包含核心功能和模板解析器

(2) vue.runtime.js是时运行版本的vue,只包含:核心功能,没有模板解析器

2、因为 vue.runtime.js 没有模板解析器 所以不能用template配置项,需要使用render函数收到createElement函数去指定具体内容

new Vue({
 render: h => h(App),
 // render(createElement){
 //  return createElement('<h1>','你好啊')
 // }
 // render:(createElement)=>{
 //  return createElement('<h1>','你好啊')
 // }
}).$mount('#app')

2.4 ref属性

ref属性:

1 被用来给元素或者子组件注册引用信息(id的替代者)

2 应用在html标签上获取真实DOM,应用在组件标签上是组件实例对象(vc)

3 使用方式:

打标识:
<h1 v-text="msg" ref="title"></h1>
<button @click="show" ref="btn">点我点击上方的dom</button>
<School ref="sch"></School>
​
获取:
 console.log(this.$refs.title);//真实DOM
 console.log(this.$refs.btn);//真实DOM
 console.log(this.$refs.sch); //School组件的实例对象(vc)

2.5 props属性

功能:用来接收外部组件传进来的数据

1 传递数据:<Student name="lisi" sex="男" :age="18"></Student>

2 接收数据:

  • 简单接收:props: ["name", "age", "sex"]

  • 接收同时对数据进行类型限制

 props: {
​
  name:string,
​
  age:number,
​
  sex:String
​
 },

3 接收同时对数据进行类型限制+默认值+必要值限定

 props: {
  name: {
   string,
   required: true,
  },
  age: {
   string,
   defalut: 99,
  },
 },

优先级:props > date

不能修改props的值,Vue底层会检测到props的修改,如进行了修改 会发出警告

若想要进行修改,name复制props内容到date一份 然后修改date的内容

2.6 mixin(混合)

功能:把多个组件共有的的公共配置提取成一个混入对象

使用方式:

1 定义混合

const mixin = {
  methods: {
    show() {
     alert(this.name);
   },
   },
   mounted(){
    console.log('你好啊');     
   }
}
const mixin2 = {
  data() {
   return {
      x:100,
     y:100
   }
  },
}

2 使用混合

import { mixin, xixin2 } from "../mixin"
//全局
Vue.mixin(mixin)
//局部
import { mixin, xixin2 } from "../mixin"
mixins: [mixin, xixin2]

2.7 插件

功能:用于增强vue

本质:包含install方法的一个对象,install的第一个参数是vue,第二个参数以后是插件使用者传递的数据

定义插件:

const obj = {
  install(Vuex,x,y){
   //定义混入
    Vue.mixin({
      data() {
       return {
         x:100,
          y:100
        }
     },
   })
    //给vue原型上添加hello方法(vm和vc都可以用)
    Vue.prototype.hello=()=>{alert('你好啊')}
   //添加全局过滤器
   Vue.filter(...)
     //添加全局指令
     Vue.directive(...) 
  }
}

使用插件

Vue.use(plugins,x,y)

2.8 scoped

作用:让样式在局部生效,防止冲突

写法:<style scoped></style>

PS:选择lang="less" 保存错误, 安装插件 npm i less-loader@7

2.9 总结todolist

1、组件化编码流程

1) 拆分静态组件:组件要按照功能点拆分,命名不要与HTML冲突

2) 实现动态组件:考录好存放位置,数据在一个组件使用,还是一些组件使用

一个组件使用:放在自身

一些组件使用:放在他们共同的父组件APP身上(状态提升)

3 )实现交互:从绑定事件开始

2、props适用于:

1) 父组件==》子组件 通信

2 )子组件==》父组件 通信(父给子一个函数)

3、使用v-modle要注意:v-modle绑定的值不能是props传过来的值,因为props的值不能修改

4、props传过来的值若是对象的值,修改对象的属性值不会报错,但不推荐这样用

2.10 自定义事件

1、一种组件间的通信方式,适用于子组件==》父组件

2、使用场景:A:父组件,B:子组件,B给A传数据。那么在A中给B绑定自定义事件(事件回调在A中)

2、绑定自定义事件:

1 在父组件中:<Student v-on:atstudent="getStudentName" />或<Student @atstudent="getStudentName" />

2 在父组件中:

<Student ref="student" />

mounted() {

this.$refs.student.$on("atstudent", this.getStudentName);

},

3 若想让自定义事件只触发一次,用once修饰符,或$once方法

4、触发自定义事件 this.$emit("atstudent",数据);

5、解绑自定义事件 this.$off("atstudent");

6、组件上可以使用绑定原生dom事件。需要使用native修饰符

7、注意:使用this.$refs.xxx.$on("atstudent", 回调);绑定自定义事件时,要么配置在methods中,要么使用箭头函数,否则this出现问题

2.11 全局事件总线

1、一种组件间的通信方式,适用于任何组件间的通信

2、安装全局事件总线:

new Vue({

//安装全局事件总线 $bus就是当前应用的vm

beforeCreate(){

Vue.prototype.$bus=this

}

})

3、使用全局事件总线:

A向B传数据

1 提供数据: this.$bus.$emit("hello", xxx);

2 接收数据:B若想接收数据,则在B中给$bus绑定自定义事件,事件的回调留在B组件自身

methods: {
 demo(data){{…}
 },
 mounted() {
  this.$bus.$on("hello", (data) => {
   console.log("我是school组件,收到了数据", this.demo);
  });
 }

4、最好在beforeDestroy钩子中,解绑当前组件所用到的事件

2.12 消息订阅与发布

第三方库pubsub.js

1、一种组件间的通信方式,适用于任何组件间的通信

2、使用步骤:

  • 1 安装pubsub.js:npm i pubsub-js

  • 2 引入:import pubsub from "pubsub-js"

  • 3 接收数据:B若想接收数据,则在B中给$bus绑定自定义事件,事件的回调留在B组件自身

    methods: {
    
    demo(data){{…}
    
    },
    
    mounted() {
    
    this.pubId= pubsub.subscribe('xxx',this.demo)//订阅消息
    
    }
  • 4 提供数据:pubsub.publish("xxx", 数据)

3、最好在beforeDestroy钩子中,解绑当前组件所用到的事件

pubsub.unsubscribe(pubId)

2.13 nextTick

  1. 语法:this.$nextTick(回调函数)

  2. 作用:在下一次 DOM 更新结束后执行其指定的回调。

  3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。

2.14 Vue封装的过度与动画

第三方库:annimate.css

Animate.css | A cross-browser library of CSS animations.

  1. 作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。

  1. 写法:

  2. 准备好样式:

  • 元素进入的样式:

  1. v-enter:进入的起点

  2. v-enter-active:进入过程中

  3. v-enter-to:进入的终点

  • 元素离开的样式:

  1. v-leave:离开的起点

  2. v-leave-active:离开过程中

  3. v-leave-to:离开的终点

  4. 使用<transition>包裹要过度的元素,并配置name属性: <transitionname="hello"> <h1v-show="isShow">你好啊!</h1> </transition>

  5. 备注:若有多个元素需要过度,则需要使用:<transition-group>,且每个元素都要指定key值。

2.15 Vue脚手架配置代理

方法一

在vue.config.js中添加如下配置:

devServer:{
​
 proxy:"http://localhost:5000"
​
}

说明:

  1. 优点:配置简单,请求资源时直接发给前端(8080)即可。

  2. 缺点:不能配置多个代理,不能灵活的控制请求是否走代理。

  3. 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)

方法二

编写vue.config.js配置具体代理规则:

module.exports={
​
  devServer: {
    proxy: {
    '/api1': {// 匹配所有以 '/api1'开头的请求路径
    target: '[http://localhost:5000',//](http://localhost:5000',/) 代理目标的基础路径
    changeOrigin: true,
    pathRewrite: {'^/api1': ''}
   },
    '/api2': {// 匹配所有以 '/api2'开头的请求路径
     target: '[http://localhost:5001',//](http://localhost:5001',/) 代理目标的基础路径
     changeOrigin: true,
     pathRewrite: {'^/api2': ''}
    }
  }
 }
}
/*
  changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
  changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
  changeOrigin默认值为true
*/

说明:

  1. 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。

  2. 缺点:配置略微繁琐,请求资源时必须加前缀。

2.16 插槽

  1. 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件

  2. 分类:默认插槽、具名插槽、作用域插槽

  3. 使用方式:

1 默认插槽

//父组件中:
   <Category>
       <div>html结构1</div>
  </Category>
//子组件中:
 <template>
     <div>
       <!-- 定义插槽 -->
        <slot>插槽默认内容...</slot>
      </div>
  </template>
​

2 具名插槽

//父组件中:
    <Category>
      <template slot="center">
              <div>html结构1</div>
      </template>
      <template v-slot:footer>
           <div>html结构2</div>
      </template>
    </Category>
//子组件中:
   <template>
      <div>
        <!-- 定义插槽 -->
        <slot name="center">插槽默认内容...</slot>
       <slot name="footer">插槽默认内容...</slot>
      </div>
    </template>

3 作用域插槽

  1. 理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)

  2. 具体编码:

//父组件中:
<Category>
    <template scope="scopeData">
    <!-- 生成的是ul列表 -->
    <ul>
    <li v-for="g in scopeData.games" :key="g">{{g}}</li>
    </ul>
    </template>
</Category>
<Category>
    <template slot-scope="scopeData">
    <!-- 生成的是h4标题 -->
    <h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
    </template>
</Category>
//子组件中:
    <template>
       <div>
       <slot :games="games"></slot>
      </div>
    </template>
    <script>
      export default {
        name:'Category',
        props:['title'],
        //数据在子组件自身
        data() {
          return {
            games:['红色警戒','穿越火线','劲舞团','超级玛丽']
          }
        },
      }
    </script>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值