1. 介绍
1.1 什么是 jquery-components
jquery 是一个操作 dom 的库,jquery 无法同 vue 和 react 一样做单页面和组件化开发。jquery-components 正是为了解决这个问题。
1.2 为什么选择 jquery-components
jquery-components 拥有 jquery 的所有 api,几乎无新增 api,赋予了 jquery 新的生命,使用 jquery 的同学可以快速上手。
2. 安装依赖
2.1 依赖
jquery-components 是核心依赖,它用于在运行时起作用。
jquery-components-loader 是 webpack 用于解析.jq
文件的 loader。
2.2 jquery-components
jquery-components 是 jquery 组件化的核心包,它提供了组件注册、解析、渲染、路由解析、事件分发等核心功能。
npm install jquery-components -S
2.3 jquery-components-loader
jquery-components-loader 是用于解析.jq 文件的 webpack 的 loader。
安装命令:
npm install jquery-components-loader -D
安装完后我们需要在 webpack.config.js 中配置它
module: {
rules: [
{
test: /\.jq/i,
loader: "jquery-components-loader"
}
],
}
3. 第一个应用
demo 代码在地址:https://github.com/fanqunxing/jquery-components-demo
3.1 安装依赖
webpack 依赖
npm install webpack webpack-cli webpack-dev-server html-webpack-plugin -D
jquery-components-loader
npm install jquery-components-loader -D
babel 和 css-loader 也需要
npm install @babel/core babel-loader css-loader -D
jquery 和 jquery-components
npm install jquery jquery-components -S
3.2 配置 webpack.config.js
根目录新建 webpack.config.js
配置如下
const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
devtool: "source-map",
mode: process.env.NODE_ENV,
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
devServer: {
compress: true,
port: 8080,
hot: true,
},
module: {
rules: [
{
test: /\.jq/i,
loader: "jquery-components-loader",
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
}
3.3 编写代码
新建 public/index.html 文件
<!DOCTYPE html>
<html lang="en">
<body>
<div id="app"></div>
</body>
</html>
新建 src 目录,目录下新建 App.jq 和 main.js
App.jq
<template>
<div>hello jquery</div>
</template>
<script>
export default function ($) {}
</script>
<style>
div {
color: red;
}
</style>
main.js
import $ from "jquery"
import { useJquery } from "jquery-components"
import App from "./App.jq"
useJquery($)
$("#app").html(App)
在 package.json 中配置 dev 启动命令
"scripts": {
"dev": "webpack serve --hot --mode=development"
}
启动命令
npm run dev
最后我们可以看到界面出现红色的hello jquery
4. vscode 插件
由于.jq
文件 vscode 无法识别,在 vscode 插件中搜索jquery-components For Highlighter
安装插件即可识别.jq
文件。
5. 生命周期
jquery-components 只有两个生命周期 mounted 和 destroy
5.1 mounted
在export default function($) {}
函数中的方法会在 mounted 的时候执行
<template>
<div class="btn">我是一个组件, 点击我~</div>
</template>
<script>
export default function ($) {
$(".btn").click(function () {
alert("hello world!")
})
}
</script>
5.2 destroy
destroy 会在组件销毁的时候调用。
使用$.on('destroy', () => {})
监听
<template>
<div class="btn">我是一个组件, 点击我~</div>
</template>
<script>
export default function ($) {
$.on("destroy", () => {
console.log("destroy")
})
}
</script>
6. 事件绑定和监听
6.1 元素的事件监听
default
的函数中默认传递了一个$
,这个$
是对jquery
的封装和扩展,包含着作用域限制和其他扩展方法。
使用$
即可对元素实现监听,同jquery
的使用方法一样。
<template>
<div class="btn">我是一个组件, 点击我~</div>
</template>
<script>
export default function ($) {
$(".btn").click(function () {
alert("hello world!")
})
}
</script>
6.2 内置事件监听
jquery-components
内置了几个系统事件,用于事件和生命周期的监听。都采用$.on('name', () => {})
监听。
- router 事件 用于监听路由
- destroy 事件 用于监听 destroy 生命周期
7. 组件
7.1 组件自定义
自定义组件是 jquery-components 的核心内容。
新建一个组件 simpCom.jq
<template>
<div class="btn">我是一个组件, 点击我~</div>
</template>
<script>
export default function ($) {
$(".btn").click(function () {
alert("hello world!")
})
}
</script>
7.2 组件引入
jquery-components 中是通过<import>标签
引入组件,如下面代码示例
<import name="simpCom" src="./simpCom.jq"></import>
<import>标签
中的的src
属性指定自定义组件的地址,name
属性指定在父组件中引用该组件时使用的标签名称
示例如下:
<import name="simpCom" src="./simpCom.jq"></import>
<template>
<div>
<simpCom></simpCom>
</div>
</template>
7.3 全局组件注册
我们声明了全局组件则不再需要引入。
使用$.component(name, compontents)
即可。
示例:
import MyBtn from "./MyBtn.jq"
$.component("MyBtn", MyBtn)
7.4 动态组件
动态组件是指在组件内部使用 html 方法挂载一个复杂组件的时候使用。
如下 js_content
里面含有<MyBtn></MyBtn>
标签,则需要声明为动态组件,以保证<MyBtn></MyBtn>
按预期渲染。
使用html
方法动态加载。
<template>
<div>
<div class="js_content"></div>
<button class="click">保存</button>
</div>
</template>
<script>
import MyBtn from "./MyBtn.jq"
let data = [{ id: 0, name: "孙悟空", content: "打妖怪" }]
export default function ($) {
$(".click").click(render)
function render(data) {
let htmls = []
data.forEach(({ name, content }) => {
htmls.push(`
<div>
<span>${name}</span>
<span>${content}</span>
<span><MyBtn></MyBtn></span>
<div>
`)
})
$(".js_content").html({
template: `<div>${htmls.join("")}</div>`,
components: { MyBtn },
})
}
}
</script>
7.5 插槽
插槽示例如下: 创建一个带插槽的组件
<template>
<div>
<slot name="header"></slot>
<slot></slot>
<div>footer</div>
</div>
</template>
在父组件中使用带插槽的组件
<import name="SlotEg" src="./SlotEg.jq"></import>
<template>
<SlotEg>
<div>default content</div>
<div slot="header">header content</div>
</SlotEg>
</template>
8. 父子组件通信
8.1 父组件向子组件传参
父组件通过 attr
和data
向子组件传递数据
场景一:使用 attr 同步传入
<import name="MyBtn" src="./MyBtn.jq"></import>
<!-- 父组件中传入name -->
<div>
<MyBtn name="父子传参"></MyBtn>
</div>
<!-- 在子组件MyBtn.jq中接受 -->
<template>
<div>按钮</div>
</template>
<script>
export default function ($) {
const name = $.el.attr("name")
console.log(name)
}
</script>
场景二:如果是异步写入 name,则需要下面方法
<import name="MyBtn" src="./MyBtn.jq"></import>
<template>
<div>
<MyBtn class="my-btn"></MyBtn>
<div class="click">触发</div>
</div>
</template>
<script>
export default function ($) {
$(".click").click(function () {
$(".my-btn").attr("name", "父子传参")
})
}
</script>
在子组件 MyBtn.jq 中使用监听到数据
<template>
<div>按钮</div>
</template>
<script>
export default function ($) {
$.on("name", function (res) {
console.log(res)
})
}
</script>
场景三:如果数据量太大或者数据格式,不适合用 attr,则可以使用 data 方法
<import name="MyBtn" src="./MyBtn.jq"></import>
<template>
<div>
<MyBtn class="my-btn"></MyBtn>
<div class="click">触发</div>
</div>
</template>
<script>
export default function ($) {
$(".click").click(function () {
$(".my-btn").data("name", { name: "父子传参" })
})
}
</script>
在子组件一样可以监听的到
<template>
<div>按钮</div>
</template>
<script>
export default function ($) {
$.on("name", function (res) {
console.log(res)
})
}
</script>
8.2 子组件向父组件传参
子组件通过 trigger
向父组件传递数据,父组件使用自定事件监听
子组件
<template>
<div class="btn">按钮</div>
</template>
<script>
export default function ($) {
$.el.click(function () {
$.el.trigger("childClick", "父组件需要的参数")
})
}
</script>
父组件
<import name="MyBtn" src="./MyBtn.jq"></import>
<template>
<div>
<MyBtn class="my-btn"></MyBtn>
</div>
</template>
<script>
export default function ($) {
$(".my-btn").on("childClick", function (evt, param) {
console.log(param)
})
}
</script>
9. less 和 scss 的使用
在<style></style>
标签中设置lang
属性,使用后需要安装相应的 loader
例如:
<style lang="less">
.app {
display: flex;
.app-content {
flex: 1;
padding: 20px;
}
}
</style>
10. 路由
10.1 配置路由
配置路由文件如下
import Guide from "./Guide.jq"
import Init from "./Init.jq"
export default [
{
path: "/guide",
component: Guide,
},
{
path: "/init",
component: Init,
},
]
10.2 注册和使用路由
在 main.js 中注册路由
import routers from "./router"
$.router(routers)
App.jq 中就可以使用 router-view 标签, <router-view></router-view>
就可以展示路由页面。
<template>
<div class="app">
<a href="#/guide">guide</a>
<a href="#/init">init</a>
<router-view></router-view>
</div>
</template>
10.3 监听路由变化
通过 router 事件即可监听
<template>
<div class="btn">按钮</div>
</template>
<script>
export default function ($) {
$.on("router", function (res) {
console.log("router", res)
})
}
</script>
10.4 路由懒加载
为了让打包体积减少,可以使用路由懒加载
const Guide = () => import("./Guide.jq")
const Init = () => import("./Init.jq")
export default [
{
path: "/guide",
component: Guide,
},
{
path: "/init",
component: Init,
},
]
10.5 子路由配置
子路由使用children
配置
const Guide = () => import("./Guide.jq")
const Init = () => import("./Init.jq")
const Hello = () => import(".Hello.jq")
export default [
{
path: "/guide",
component: Guide,
},
{
path: "/init",
component: Init,
children: [
{
path: "/hello",
component: Hello,
},
],
},
]
10.6 路由监听
通过 router 事件监听路由
<template>
<div></div>
</template>
<script>
export default function ($) {
$.on("router", function (res) {
console.log("router", res)
})
}
</script>