做pc端网站价位,wordpress标签作用,潍坊外贸建站,网页布局结构写在前面 如今#xff0c;在项目中使用React、Vue等框架作为技术栈已成为一种常态#xff0c;在享受带来便利性的同时#xff0c;也许我们渐渐地遗忘原生js的写法。 现在#xff0c;是时候回归本源#xff0c;响应原始的召唤了。本文将一步一步带领大家封装一套属于自己的…写在前面 如今在项目中使用React、Vue等框架作为技术栈已成为一种常态在享受带来便利性的同时也许我们渐渐地遗忘原生js的写法。 现在是时候回归本源响应原始的召唤了。本文将一步一步带领大家封装一套属于自己的DOM操作库我将其命名为qnode。 功能特性 qnode吸收了jquery优雅的链式写法并且融入了我个人的一些经验和思考 自定义DOM工厂模式缓存节点、跨文件操作快速优雅地创建新的DOM节点CSS3样式前缀自动识别和添加大家可能会比较疑惑什么是DOM工厂模式 实际上是这样有一些需要共享的节点、数据和方法它在某个文件中定义在另一个文件中调用。我最初的方式是在文件中暴露export出这些东西但是后来发现文件多了这种方式很难维护而且需要引入很多的文件非常麻烦。 于是在不断的摸索和思考中想出了DOM工厂模式这个概念咱们可以这么理解DOM工厂就是取快递的地方不管是从哪里发来的货品统一送到这里然后再由特定的人群来取。 当然未来还有很长的路要走我会不断地探索和改进融入更多的想法和改进。 目录结构 qnode
├── QNode.js
├── README.md
├── api.js
├── core
│ ├── attr.js
│ ├── find.js
│ ├── index.js
│ ├── klass.js
│ ├── listener.js
│ ├── node.js
│ └── style.js
├── index.js
├── q.js
└── tools.js
复制代码q.js是DOM操作的集合融合了所有core的方法QNode.js是工厂模式提供节点、数据以及方法的缓存和获取core目录下的文件是DOM操作的具体方法编写代码 core/attr.js内容属性操作 import { isDef } from ../toolsexport function text (value) {if (!isDef(value)) {return this.node.textContent}this.node.textContent valuereturn this
}export function html (value) {if (!isDef(value)) {return this.node.innerHTML}this.node.innerHTML valuereturn this
}export function value (val) {if (!isDef(val)) {return this.node.value}this.node.value valreturn this
}export function attr (name, value) {if (!isDef(value)) {return this.node.getAttribute(name)}if (value true) {this.node.setAttribute(name, )} else if (value false || value null) {this.node.removeAttribute(name)} else {this.node.setAttribute(name, value)}return this
}
复制代码core/find.js节点信息获取 export function tagName () {return this.node.tagName
}export function current () {return this.node
}export function parent () {return this.node.parentNode
}export function next () {return this.node.nextSibling
}export function prev () {return this.node.previousSibling
}export function first () {return this.node.firstChild
}export function last () {return this.node.lastChild
}export function find (selector) {return this.node.querySelector(selector)
}
复制代码core/klass.jsclass样式操作 import { isArray } from ../toolsexport function addClass (cls) {let classList this.node.classListlet classes isArray(cls) ? cls : [].slice.call(arguments, 0)classList.add.apply(classList, classes.filter(c c).join( ).split( ))return this
}export function removeClass (cls) {let classList this.node.classListlet classes isArray(cls) ? cls : [].slice.call(arguments, 0)classList.remove.apply(classList, classes.filter(c c).join( ).split( ))return this
}export function hasClass (cls) {let classList this.node.classList// 若有空格则必须满足所有class才返回trueif (cls.indexOf( ) ! -1) {return cls.split( ).every(c classList.contains(c))}return classList.contains(cls)
}
复制代码core/listener.js事件监听处理 export function on (type, fn, useCapture false) {this.node.addEventListener(type, fn, useCapture)return this
}export function off (type, fn) {this.node.removeEventListener(type, fn)return this
}
复制代码core/node.jsDOM操作 import { createFragment } from ../api
import { getRealNode, isArray } from ../toolsexport function append (child) {let realNode nullif (isArray(child)) {let fragment createFragment()child.forEach(c {realNode getRealNode(c)if (realNode) {fragment.appendChild(realNode)}})this.node.appendChild(fragment)} else {realNode getRealNode(child)if (realNode) {this.node.appendChild(realNode)}}return this
}export function appendTo (parent) {parent getRealNode(parent)if (parent) {parent.appendChild(this.node)}return this
}export function prepend (child, reference) {let realNode nulllet realReference getRealNode(reference) || this.node.firstChildif (isArray(child)) {let fragment createFragment()child.forEach(c {realNode getRealNode(c)if (realNode) {fragment.appendChild(realNode)}})this.node.insertBefore(fragment, realReference)} else {realNode getRealNode(child)if (realNode) {this.node.insertBefore(realNode, realReference)}}return this
}export function prependTo (parent, reference) {parent getRealNode(parent)if (parent) {parent.insertBefore(this.node, getRealNode(reference) || parent.firstChild)}return this
}export function remove (child) {// 没有要移除的子节点则移除本身if (!child) {if (this.node.parentNode) {this.node.parentNode.removeChild(this.node)}} else {let realNode nullif (isArray(child)) {child.forEach(c {realNode getRealNode(c)if (realNode) {this.node.removeChild(realNode)}})} else {realNode getRealNode(child)if (realNode) {this.node.removeChild(realNode)}}}return this
}
复制代码core/style.js内联样式操作 import { isDef, isObject } from ../toolsconst htmlStyle document.documentElement.style
const prefixes [webkit, moz, ms, o]
const prefixLen prefixes.lengthfunction getRealStyleName (name) {if (name in htmlStyle) {return name}// 首字母大写let upperName name[0].toUpperCase() name.substr(1)// 前缀判断for (let i 0; i prefixLen; i) {let realName prefixes[i] upperNameif (realName in htmlStyle) {return realName}}// 都不支持则返回原值return name
}export function css (name) {if (!this.computedStyle) {this.computedStyle window.getComputedStyle(this.node)}if (!isDef(name)) {return this.computedStyle}return this.computedStyle[name]
}export function style (a, b) {if (isObject(a)) {Object.keys(a).forEach(name {name getRealStyleName(name)this.node.style[name] a[name]})} else {a getRealStyleName(a)if (!isDef(b)) {return this.node.style[a]}this.node.style[a] b}return this
}export function show () {if (this.node.style.display none) {this.node.style.display }return this
}export function hide () {this.node.style.display nonereturn this
}export function width () {return this.node.clientWidth
}export function height () {return this.node.clientHeight
}
复制代码core/index.js所有操作集合 import * as attr from ./attr
import * as find from ./find
import * as klass from ./klass
import * as listener from ./listener
import * as node from ./node
import * as style from ./styleexport default Object.assign({},attr,find,klass,listener,node,style
)
复制代码api.jsDOM API // 创建dom节点
export function createElement (tagName) {return document.createElement(tagName)
}// 创建dom节点片段
export function createFragment () {return document.createDocumentFragment()
}
复制代码tools.js工具方法 import { createElement } from ./apiexport const Q_TYPE (typeof Symbol function Symbol(q)) || 0x89bc
export const QNODE_TYPE (typeof Symbol function Symbol(QNode)) || 0x7b96// 占位node节点
export const emptyNode createElement(div)export function isQ (ele) {return ele ele.node ele.__type__ Q_TYPE
}/*** 判断值是否定义* param {any} t* returns {boolean}*/
export function isDef (t) {return typeof t ! undefined
}/*** 判断是否为字符串* param {any} t* returns {boolean}*/
export function isString (t) {return typeof t string
}/*** 是否为对象* param {any} t* param {boolean} [includeArrayfalse] 是否包含数组* returns {boolean}*/
export function isObject (t) {return t typeof t object
}/*** 判断是否为数组* param {any} t* returns {boolean}*/
export function isArray (t) {if (Array.isArray) {return Array.isArray(t)}return Object.prototype.toString.call(t) [object Array]
}// 判断是否为dom元素
export function isElement (node) {if (isObject(HTMLElement)) {return node instanceof HTMLElement}return node node.nodeType 1 isString(node.nodeName)
}export function getRealNode (ele) {if (isElement(ele)) {return ele} else if (isQ(ele)) {return ele.node}return null
}
复制代码q.js import { createElement } from ./api
import { Q_TYPE, isElement, isString, emptyNode } from ./tools
import core from ./coreclass Q {constructor (selector) {let nodeif (isElement(selector)) {node selector} else if (isString(selector)) {if (selector[0] $) {node createElement(selector.substring(1))} else {node document.querySelector(selector)}}// node不存在则创建一个占位node避免操作dom报错this.node node || emptyNodethis.__type__ Q_TYPE}
}// 集合
Object.assign(Q.prototype, core)export default function q (selector) {return new Q(selector)
}
复制代码QNode.js import { QNODE_TYPE, isQ, isArray } from ./tools
import q from ./qexport default class QNode {constructor () {this.__type__ QNODE_TYPEthis.qNodes {}this.store {}this.methods {}}q (selector) {return q(selector)}getNode (name) {return this.qNodes[name]}setNode (name, node) {if (isArray(node)) {this.qNodes[name] node.map(n isQ(n) ? n : q(n))} else {this.qNodes[name] isQ(node) ? node : q(node)}return this.qNodes[name]}getStore (name) {return this.store[name]}setStore (name, value) {this.store[name] valuereturn value}getMethod (name) {return this.methods[name]}execMethod (name) {let fn this.methods[name]return fn fn.apply(this, [].slice.call(arguments, 1))}setMethod (name, fn) {let thisFn fn.bind(this)this.methods[name] thisFnreturn thisFn}
}
复制代码index.js import q from ./q
import QNode from ./QNodeexport {q,QNode
}export default {q,QNode
}
复制代码到这里为止所有代码已经编写完成了。 API Reference q获取|创建节点 参数 #id 根据id获取节点.class 根据class获取节点tagName 根据标签获取节点$tagName 创建新的节点备注如果有多个节点则只获取第一个 方法 attr text: str 【设置文本内容若无参数则获取文本内容】html: str 【设置html若无参数则获取html】value: val 【设置表单值若无参数则获取表单值】attr: name, value 【设置name属性的值若value无参数则获取name的值】find tagName 【获取节点名称】current 【获取节点本身】parent 【获取父节点】next 【获取后一个节点】prev 【获取上一个节点】first 【获取第一个子节点】last 【获取最后一个子节点】find: #id | .class | tagName 【找子节点】class addClass: str | arr | a, b, ... 【添加样式class】removeClass: str | arr | a, b, ... 【移除样式class】hasClass: str 【是否含有样式class】listener on: type, fn, useCapturefalse 【添加事件监听】off: type, fn 【移除事件监听】node append: node | nodeList 【填充子节点到最后】appendTo: parent 【填充到父节点中最后】prepend: node | nodeList, reference 【填充子节点到最前或指定节点前】prependTo: parent, reference【填充到父节点中最前或指定节点前】remove: child 【移除子节点若无参数则移除自身】style css: name 【获取css文件中定义的样式】style: (name, value) | object 【1.设置或获取内联样式2.设置一组样式】show 【显示节点】hide 【隐藏节点】width 【获取节点宽度】height 【获取节点高度】QNode节点仓库包括数据和方法 方法 q: 同上述qgetNode: name 【获取节点】setNode: name, node 【设置节点返回节点】getStore: name 【获取数据】setStore: name, value 【设置数据返回数据】getMethod: name 【获取方法】setMethod: name, fn 【设置方法返回方法this绑定到qnode】execMethod: name 【执行方法name后面可以传入方法需要的参数this为qnode】结语 本文到这里就要结束了读者对文中的代码感兴趣的话建议自己动手试试在编程这块儿实践才能出真知。 写完之后是不是跃跃欲试呢下一篇文章我将基于本文封装的DOM库来开发无限循环轮播图详细请看下文原生js系列之无限循环轮播图。 附本文源码