组件化编程

Posted Liu-h

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了组件化编程相关的知识,希望对你有一定的参考价值。

模块与组件

模块

  • 向外提供特定功能的js程序-- 一般就是一个js文件
  • 作用--复用js、简化js的编写、提高js运行效率
  • 模块化--当应用中的js都是以模块来编写的 -- 这个应用就是一个模块化的应用

组件

  • 用来实现局部(特定)功能效果的代码集合
  • 作用--复用编码 -- 简化项目编码、提高运行效率
  • 组件化 -- 当应用中的功能都是以组件来编写的 -- 这个应用就是一个组件化的应用

非单文件组件

一个文件中包含有n个组件

基本使用

定义组件--创建组件

  • 使用Vue.extend(options)创建 -- 其中options和new Vue(options)时的区别
    • 不写el -- 最终所有组件都要经过一个vm的管理 -- 由vm中的el决定服务哪个容器
    • data必须写为函数 -- 避免组件复用时--数据存在引用关系
  • 使用template可以配置组件结构
const school = Vue.extend(
        template: `
            <div>
                <h2>学校:name</h2>    
                <h2>地址:address</h2>    
            </div>
        `,
        data() 
            return 
                name: \'郑轻\',
                address: \'郑州\'
            
        
    );

    //创建student组件
    const student = Vue.extend(
        template: `
            <div>
                <h2>姓名:name</h2>    
                <h2>年龄:age</h2>    
            </div>
        `,
        data() 
            return 
                name: \'lhd\',
                age: 21
            
        
    )

注册组件

  • 局部注册 -- 在new Vue时传入components选项
  • 全局注册 -- Vue.component(\'组件名\',组件)
//全局注册

//创建hello组件
const hello = Vue.extend(
    template: `
        <div>
            <h2>msg</h2>    
        </div>
    `,
    data() 
        return 
            msg: \'你好\'
        
    
);
//注册hello组件---全局注册
// \'hello\', hello -- \'组件名\',创建组件时使用的变量名
Vue.component(\'hello\', hello);

//局部注册

new Vue(
    el: \'#root\',
    //注册组件--局部
    components: 
        //school: school -- 组件名,创建组件时使用的变量名 
        // school: school,--前后一致可简写
        school,
        // student: student
        student
    
)

使用组件

  • 在body标签里写组件标签
<div id="root">
    <!-- 使用组件 -->
    <hello></hello>
    <hr>
    <school></school>
    <hr>
    <student></student>
</div>

注意事项

组件名

  • 一个单词组成
    • 写法1 -- 首字母小写
    • 写法2 -- 首字母大写
  • 多个单词组成
    • 写法1 -- kebab-case命名
    • 写法2 -- CamelCase命名 -- 需要vue脚手架支持
  • 组件名尽可能回避HTML中已有的元素名称
  • 可使用name配置项指定组件在开发者工具中呈现的名字
const student = Vue.extend(
    name: \'xuesheng\',
    template: `
        <div>
            <h2>姓名:name</h2>    
            <h2>年龄:age</h2>    
        </div>
    `,
    data() 
        return 
            name: \'lhd\',
            age: 21
        
    
)
new Vue(
    el: \'#root\',
    components: 
        student
    
)

组件标签

  • 写法1 --
  • 写法2 --
  • 不使用脚手架时 -- 会导致后续组件不能渲染
<div id="root">
    <student />
    <student />
    <student />
</div>

简写方式

const student = Vue.extend(options) -- const student = options

const student = (
    name: \'xuesheng\',
    template: `
        <div>
            <h2>姓名:name</h2>    
            <h2>年龄:age</h2>    
        </div>
    `,
    data() 
        return 
            name: \'lhd\',
            age: 21
        
    
)

组件嵌套

  • school里嵌套student
    • 先创建student组件 -- 再创建school组件
    • school组件内部 -- 定义components属性
    • components内部写入student组件名
    • school组件的template内写入student标签
//创建student组件
const student = Vue.extend(
    template: `
        <div>
            <h2>姓名:name</h2>    
            <h2>年龄:age</h2>    
        </div>
    `,
    data() 
        return 
            name: \'lhd\',
            age: 21
        
    
);

//创建school组件
const school = Vue.extend(
    template: `
        <div>
            <h2>学校:name</h2>    
            <h2>地址:address</h2>
    //写入student标签
            <student></student>    
        </div>
    `,
    data() 
        return 
            name: \'郑轻\',
            address: \'郑州\'
        
    ,
    //写入components属性
    components: 
        student
    
);

需在vm下创建app组件 -- 管理所有的组件

<script>

    //创建student组件
    const student = Vue.extend(
        template: `
            <div>
                <h2>姓名:name</h2>    
                <h2>年龄:age</h2>    
            </div>
        `,
        data() 
            return 
                name: \'lhd\',
                age: 21
            
        
    );

    //创建school组件
    const school = Vue.extend(
        template: `
            <div>
                <h2>学校:name</h2>    
                <h2>地址:address</h2>
                <student></student>    
            </div>
        `,
        data() 
            return 
                name: \'郑轻\',
                address: \'郑州\'
            
        ,
        components: 
            student
        
    );

    //创建hello组件
    const hello = Vue.extend(
        template: `
            <div>
                <h2>msg</h2>    
            </div>
        `,
        data() 
            return 
                msg: \'你好\'
            
        
    );

    //创建app组件
    const app = Vue.extend(
        template: `
            <div>
                <hello></hello>  
                <hr>
                <school></school>
                  
            </div>
        `,
        data() 
            return 
                msg: \'你好\'
            
        ,
        components: 
            school,
            hello
        
    );

    new Vue(
        el: \'#root\',
        template: `
            <app></app>
        `,
        components: 
            app
        
    )
</script>

VueCpmpotent

以上述代码为例--分析VueCompotent

school组件本质是一个名为VueCompotent的构造函数 -- 是Vue.extend生成的

使用组件时 --只需写组件标签 --Vue解析时会自动创建school组件的实例对象

每次调用Vue.extend -- 都会返回一个新的VueCompotent

关于this指向

组件配置中 -- data中的函数、method中的函数、watch中的函数、computed中的函数 -- this均是VueCompotent实例对象

const school = Vue.extend(
    template: `
        <div>
            <button @click=\'schoolName\'>点击返回this</button>  
        </div>
    `,
    methods: 
        schoolName() 
            console.log(\'school\', this);
        
    
);

new Vue(options)配置中 -- data中的函数、method中的函数、watch中的函数、computed中的函数 -- this均是Vue实例对象

VueCompotent可简称为vc

Vue简称为vm

内置关系

  • 一个重要的内置关系 -- VueCompotent.prototype._ _proto _ _ = Vue.prototype
  • 目的 -- 让vc可以访问到vm原型上的属性和方法

单文件组件

基本结构

组件内部标签

  • template --- 写入组件所需结构
<template>
  <!-- 组件的结构 -->
  <div id="demo">
    <h2>学校: name </h2>
    <h2>地址: address </h2>
  </div>
</template>
  • script --- 写入组件交互相关内容 --- 通过ES6语法暴露将代码出去
<script>
// 组件交互相关的代码--数据、方法等
// export default --- ES6语法-向外暴露 -- 简写形式
export default 
  name: "School",
  data() 
    return 
      name: "郑轻",
      address: "郑州",
    ;
  ,
;
/* --不用简写的形式
        const School = Vue.extend(

        )
        export default School
    */
</script>
  • style --- 写入组件的样式 --- 没有可不写
<style>
/* 组件的样式 */
#demo 
  background-color: aquamarine;

</style>

app组件内部结构

  • template --- 内部写入引入的组件标签
<template>
  <!-- 组件的结构 -->
  <div>
    <School></School>
    <Student></Student>
  </div>
</template>
  • script --- 引入组件
<script>
//引入组件
//文件后缀可写可不写
import School from "./School.vue";
import Student from "./Student.vue";
// 组件交互相关的代码--数据、方法等
// export default --- ES6语法-向外暴露 -- 简写形式
export default 
  name: "App",
  components: 
    School,
    Student,
  ,
;
</script>

js内部结构

  • 引入app组件
import App from \'./App.vue\'

new Vue(
    el: \'#root\',
    //该标签可写入html文件下的#root下
    tempate:`<App></App>`
    components:  App 
)

html内部结构

  • 引入js文件
<body>
    <div id="root">
        //该标签可写入js文件的vm下
        <App></App>
    </div>
    <script src="../../../js/vue.js"></script>
    <script src="./main.js"></script>
</body>

Vue脚手架

简介

具体步骤

全局安装 -- npm install -g @vue/cli -- 安装完后--输入vue --出现下图内容表示安装成功

切换到需要创建vue脚手架的文件夹下 --- 创建脚手架项目

输入提示的命令

点击网址 -- http://localhost:8080/ -- 出现下图页面

内部有vue自动创建的helloword组件

脚手架结构

相关文件

  • babel.config.js --- es6转换为es5代码
  • package.json、package-lock.json --- nodejs
  • README.md --- 对项目进行说明解释 --- 用来写笔记

命令行输入 npm run serve 后

  • 自动跳到main.js文件下 --- main.js文件引入了App.vue组件
  • 跳转到App.vue --App.vue组件下 引入了Student.vue和School.vue
  • 跳转到Student.vue和School.vue文件
  • 之后再跳转回main.js文件 -- index.html文件引入了main.js
  • 跳转至 index.html --- 就可以输出页面了

不同版本的vue

  • vue.js与vue.runtime.xxx.js的区别
    • vue.js -- 完整版vue --- 包含核心功能+模板解析器
    • vue.runtime.xxx.js -- 运行版vue --- 只包含核心功能 --- 没有模板解析器
      • 不能使用template配置项
      • 需使用render函数接收到的createElement函数去指定具体内容
//该文件是整个项目的入口文件

// 引入vue -- 残缺版vue -- 缺少模板解析器 -- 不能使用template配置项
// 解决方法 -- 1、引入完整版vue  2、使用render函数
// 完整版vue -- vue/dist/vue
import Vue from \'vue\'
// 引入app组件 -- 是所有组件的父组件
import App from \'./App.vue\'

// 关闭vue的生产提示
Vue.config.productionTip = false

// 创建vue实例
new Vue(
  // 将app组件放入容器中
  /**
   * render--是一个函数 -- vue自动调用 -- render里传入一个createElement函数--创建具体元素
   * createElement(\'h1\',\'你好\') --- 标签名 ,标签里的内容
   * render(createElement)
   *    return createElement(\'h1\',\'你好\')
   * 
   * 
   * 简写为箭头函数
   * render:(createElement)=>
   *    return createElement(\'h1\',\'你好\')
   * 
   * render:createElement=> createElement(\'h1\',\'你好\')
   *render:c=> c(\'h1\',\'你好\')
   函数内为组件时--只写一个标签名就行
   render: h => h(App)
   */
  render: h => h(App),
  // 写入容器的id --- 相当于 el:\'#app\'
).$mount(\'#app\')

修改默认配置

  • vue脚手架隐藏了所有webpack相关的配置 -- 查看具体webpack配置
  • 执行 vue inspect > output.js --- 查看vue脚手架的默认配置
  • vue.config.js--对脚手架进行个性化定制 --- https://cli.vuejs.org/zh

ref属性

  • 用来给元素或子组件注册引用信息 --- id的替代者
  • 应用在html标签上获取的是真实DOM元素 --- 应用在组件标签上获取的是组件实例对象

使用方式

<template>
  <div>
    <h1 v-text="msg" ref="title"></h1>
    <button ref="btn" @click="showDom">点击输出DOM</button>
    <School ref="sch"></School>
  </div>
</template>

<script>
import School from "./components/School.vue";
export default 
  components:  School ,
  data() 
    return 
      msg: "我在学习Vue",
    ;
  ,
  methods: 
    showDom() 
      console.log(this.$refs.title);	//真实DOM元素
      console.log(this.$refs.btn);		//真实DOM元素
      console.log(this.$refs.sch);		//School组件的实例对象--vc
    ,
  ,
;
</script>

props配置

让组件接收外部传来的数据

  • 传递数据
//App.vue

<template>
  <div>
    <Student name="lhd" age="21" sex="女" />
  </div>
</template>
  • 接收数据
//School.vue

//简单接收
props: ["name", "age", "sex"],
// 限制类型
// props: 
//   name: String,
//   age: Number,
//   sex: String,
// ,
//限制类型、必要性、指定默认值
props: 
  name: 
    type: String,
    required: true,
  ,
  age: 
    type: Number,
    default: 21,
  ,
,
  • 注意点

    • props是只读的--Vue底层会监测对props的修改 --- 若进行了修改会发出警告

    • 若一定要修改 --- 复制props的内容到data中 --- 修改data中的数据

mixin混入

把多个组件共用的配置提取成一个混入对象

使用方法

创建一个js文件 -- 定义混合

//将该文件暴露出去
export const mix = 
    methods: 
        showName() 
            alert(this.name);
        ,
    

在需要使用该配置的文件下引入--局部混入

/引入文件
import  mix  from "../mix";
//通过mixins配置使用 -- 必须写为数组形式
mixins: [mix],

全局混入--在main.js文件下引入 -- Vue.mixin(mix)

插件

用于增强Vue

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

定义插件

export default
    install(Vue)
        
    

添加全局指令

Vue.prototype.hello=() =>alert(\'你好呀\')

使用插件

//main.js

//引入插件
import plugin from "./plugin";

//使用插件
Vue.use(plugin);

//Student.vue
<button @click="demo">点击输出你好</button>
methods: 
  demo() 
    this.hello();
  ,
,

scoped样式

让样式在局部生效 --- 放置冲突

<style scoped>

</style>

组件化编码流程

  • 拆分静态组件 --- 组件要按功能点拆分,命名不要与html元素冲突

  • 实现动态组件 -- 考虑好数据的存放位置,数据是单个组件用还是多个组件用

    • 单个组件用 --- 放在组件自身
    • 多个组件用 --- 放在所用组件共同的父组件上 - 状态提升
  • 实现交互 --- 从绑定事件开始

  • props适用于

    • 父组件 --> 子组件 通信
    • 子组件 --> 父组件 通信 -- 要求父组件先给子一个函数
    • 使用v-model时 -- v-model绑定的值不能是props传过来的值 -- props是不能修改的
    • props传过来的值若是对象类型 -- 修改对象中的属性时Vue不会报错 -- 但不推荐

补充--浏览器本地存储

webStrorage

  • 存储大小一般支持5MB左右
  • 浏览器端通过window.localStorage和window.sessionStorage属性来实现本地存储机制

相关API

  • .setItem("key","value") --- 接收一个键和值作为参数 -- 把键值对添加到存储中 --- 若键名存在 -- 更新其对应的值
<button onclick="saveData()">点击保存一个数据</button>
<button onclick="saveData()">点击保存一个对象数据</button>

<script>
    	let person =  name: "wzh", age: 22 ;
        function saveData() 
            localStorage.setItem(\'name\', \'lhd\');
    		localStorage.setItem(\'p\', JSON.stringify(person));
        
</script>

  • .getItem(\'key\') --- 接收一个键名作为参数 --- 返回对应的值
<button onclick="readData()">点击读取一个数据</button>

function readData() 
    console.log(localStorage.getItem(\'name\'));
    const result = localStorage.getItem(\'p\');
    console.log(JSON.parse(result));

  • .removeItem(\'key\') --- 接收一个键名作为参数 --- 并把该键名从存储中删除
<button onclick="deleteData()">点击删除一个数据</button>

function deleteData() 
    localStorage.removeItem(\'name\');

  • .clear() --- 清空存储中所有数据
<button onclick="clearData()">点击清空数据</button>

function clearData() 
    localStorage.clear();

注意

  • sessionStorage --- 存储的内容会随着浏览器窗口关闭而消失
  • localStorage --- 存储的内容需手动清除才能消失
  • .getItem(\'key\') --- 若获取不到对应的value -- getItem的返回值为null
  • JSON.parse(null) --- 结果依然是null

组件自定义事件

  • 一种组件间通信的方式 --- 适用于 子组件给父组件传递数据
  • 使用场景 --- 子组件给父组件传递数据---- 要在父组件中给子组件绑定自定义事件 --- 事件的回调在父组件中
  • 绑定自定义事件
    • 方法一 ---- 通过v-on/@
<!-- 通过父组件给子组件绑定一个自定义事件--实现子组件给父组件传递内容--方法一通过v-on/@ -->
<Student @name="getStudentName" @demo="mul"></Student>

methods: 
	getStudentName(name) 
	  console.log("App收到了学生名", name);
	,
	//传递多个参数
	// getStudentName(name, ...params) 
	//   console.log("App收到了学生名", name, params);
	// ,
,


  • 方法二 ---- 通过ref

<!-- 通过父组件给子组件绑定一个自定义事件--实现子组件给父组件传递内容--方法二通过ref -->
<Student ref="student"></Student> 

mounted() 
  // 绑定自定义事件
this.$refs.student.$on("name", this.getStudentName);
  // 只能使用一次
  // this.$refs.student.$on.once("name", this.getStudentName);
,
  • 若想让事件只触发一次 --- 使用once修饰符或$once方法

  • 触发自定义事件

this.$emit("name", this.name);
  • 解绑自定义事件
//解绑单个事件
this.$off("name");
//解绑多个事件
this.$off(["name", "demo"]);
//解绑全部事件
this.$off();
  • 组件可绑定原生DOM事件 --- 需使用native修饰符
<Student @click.native="mul"></Student>
  • 注意
    • 通过 ref绑定自定义事件时 --- 回调要么配置在methods中;要么使用箭头函数;否则this指向会出问题 --- 默认this指向的是被绑定自定义事件的组件

全局事件总线

一种组件间通信的方式 --- 适用于任意组件间通信

安装全局事件总线 ---- 在vm的原型上

new Vue(
    ...
    beforeCreate() 
        Vue.prototype.$bus = this
    
)

使用事件总线

接收数据--在接收数据的组件中给$bus绑定自定义事件 --- 事件的回调留在该组件本身

//写法一
methods: 
  getStudentName(name) 
    console.log(name);
  ,
,
mounted() 
  this.$bus.$on("stu", this.getStudentName);
,

写法二
mounted() 
  this.$bus.$on("stu", (name) => 
  	console.log(name);
  );
,

提供数据 --- 在需要获取数据的组件上添加自定义组件

methods: 
  sendSchoolName(name) 
    this.$bus.$emit("stu", this.name);
  ,
,

最好在beforeDestroy钩子中 --- 用$off解绑当前组件所用到的事件

消息订阅与发布

  • 一种组件间通信的方式 --- 适用于任意组件间通信
  • 需使用第三方库 ---- pubsub-js
  • 在需要接收数据和需要传递数据的组件上引入该库 --- import pubsub from "pubsub-js";
  • 接收数据 ---- 接收数据的组件需订阅信息 --- 订阅的回调留在该组件自身
    • 最好在beforeDestroy钩子中 ---- 取消订阅
mounted() 
  this.pubId = pubsub.subscribe("msg", (msgName, data) => 
    console.log("订阅号msg发布了消息", msgName, data);
  );
,
beforeDestroy() 
  pubsub.unsubscribe(this.pubId);
,
  • 提供数据 ---- 提供数据的组件需发布信息
methods: 
  sendSchoolName() 
    pubsub.publish("msg", "你好呀");
  ,
,

nextTick( )

  • 语法 --- this.$nextTick(回调函数)
  • 作用 ---- 下次DOM更新结束后执行其指定的回调
  • 使用场景 ---- 改变数据后 -- 基于更新后的新DOM进行某些操作时 -- 在nextTick所指定的回调函数中执行

过渡与动画

作用 --- 在插入、更新和移除DOM元素时 --- 在合适的时候给元素添加样式类名

写法

  • 元素进入的样式
    • v-enter ---- 进入的起点
    • v-enter-active ---- 进入的过程
    • v-enter-to ---- 进入的终点
// 进入的起点 --- 若transition配置了name属性--则写name的值 --- 若没有配置则写v
.hello-enter 
  transform: translateX(-100%);

// 进入的动画效果 
.hello-enter-active 
  transition: 0.5s linear;

// 进入的终点
.hello-enter-to 
  transform: translateX(0px);

  • 元素离开的样式
    • v-leave ---- 进入的起点
    • v-leave-active ---- 进入的过程
    • v-leave-to ---- 进入的终点
//离开的起点 
.hello-leave 
  transform: translateX(0px);

//离开的动画效果 
.hello-leave-active 
  transition: 0.5s linear;

//离开的终点 
.hello-leave-to 
  transform: translateX(-100%);
 
  • 使用包裹要过渡的元素 ---- 并配置name属性
<button @click="isShow = !isShow">点击显示/隐藏</button>
<transition appear name="hello">
  <h1 v-show="isShow" >HELLO</h1>
</transition>
  • 若有多个元素要进行过渡 --- 使用 ,且每个元素都要指定key值
<button @click="isShow = !isShow">点击显示/隐藏</button>
<transition appear name="hello">
  <h1 v-show="isShow" >HELLO</h1>
  <h1 v-show="isShow" >你好</h1>
</transition>

sciter jsx 组件化编程

sciter 组件编程

入口文件:main.htm

<html>
    <head>
       <style src="./css/style.css" />
       <script type

以上是关于组件化编程的主要内容,如果未能解决你的问题,请参考以下文章

sciter案例 TodoList 带你入门 sciter 组件化编程

React 面向组件化编程

sciter jsx 组件化编程

JQUERY下的组件化编程之基本框架

vue组件化编程

4.React的组件化编程