130 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
		
		
			
		
	
	
			130 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * @fileoverview style 插件
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								// #ifndef APP-PLUS-NVUE
							 | 
						|||
| 
								 | 
							
								const Parser = require('./parser')
							 | 
						|||
| 
								 | 
							
								// #endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								function Style () {
							 | 
						|||
| 
								 | 
							
								  this.styles = []
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								// #ifndef APP-PLUS-NVUE
							 | 
						|||
| 
								 | 
							
								Style.prototype.onParse = function (node, vm) {
							 | 
						|||
| 
								 | 
							
								  // 获取样式
							 | 
						|||
| 
								 | 
							
								  if (node.name === 'style' && node.children.length && node.children[0].type === 'text') {
							 | 
						|||
| 
								 | 
							
								    this.styles = this.styles.concat(new Parser().parse(node.children[0].text))
							 | 
						|||
| 
								 | 
							
								  } else if (node.name) {
							 | 
						|||
| 
								 | 
							
								    // 匹配样式(对非文本标签)
							 | 
						|||
| 
								 | 
							
								    // 存储不同优先级的样式 name < class < id < 后代
							 | 
						|||
| 
								 | 
							
								    let matched = ['', '', '', '']
							 | 
						|||
| 
								 | 
							
								    for (let i = 0, len = this.styles.length; i < len; i++) {
							 | 
						|||
| 
								 | 
							
								      const item = this.styles[i]
							 | 
						|||
| 
								 | 
							
								      let res = match(node, item.key || item.list[item.list.length - 1])
							 | 
						|||
| 
								 | 
							
								      let j
							 | 
						|||
| 
								 | 
							
								      if (res) {
							 | 
						|||
| 
								 | 
							
								        // 后代选择器
							 | 
						|||
| 
								 | 
							
								        if (!item.key) {
							 | 
						|||
| 
								 | 
							
								          j = item.list.length - 2
							 | 
						|||
| 
								 | 
							
								          for (let k = vm.stack.length; j >= 0 && k--;) {
							 | 
						|||
| 
								 | 
							
								            // 子选择器
							 | 
						|||
| 
								 | 
							
								            if (item.list[j] === '>') {
							 | 
						|||
| 
								 | 
							
								              // 错误情况
							 | 
						|||
| 
								 | 
							
								              if (j < 1 || j > item.list.length - 2) break
							 | 
						|||
| 
								 | 
							
								              if (match(vm.stack[k], item.list[j - 1])) {
							 | 
						|||
| 
								 | 
							
								                j -= 2
							 | 
						|||
| 
								 | 
							
								              } else {
							 | 
						|||
| 
								 | 
							
								                j++
							 | 
						|||
| 
								 | 
							
								              }
							 | 
						|||
| 
								 | 
							
								            } else if (match(vm.stack[k], item.list[j])) {
							 | 
						|||
| 
								 | 
							
								              j--
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								          }
							 | 
						|||
| 
								 | 
							
								          res = 4
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								        if (item.key || j < 0) {
							 | 
						|||
| 
								 | 
							
								          // 添加伪类
							 | 
						|||
| 
								 | 
							
								          if (item.pseudo && node.children) {
							 | 
						|||
| 
								 | 
							
								            let text
							 | 
						|||
| 
								 | 
							
								            item.style = item.style.replace(/content:([^;]+)/, (_, $1) => {
							 | 
						|||
| 
								 | 
							
								              text = $1.replace(/['"]/g, '')
							 | 
						|||
| 
								 | 
							
								                // 处理 attr 函数
							 | 
						|||
| 
								 | 
							
								                .replace(/attr\((.+?)\)/, (_, $1) => node.attrs[$1.trim()] || '')
							 | 
						|||
| 
								 | 
							
								                // 编码 \xxx
							 | 
						|||
| 
								 | 
							
								                .replace(/\\(\w{4})/, (_, $1) => String.fromCharCode(parseInt($1, 16)))
							 | 
						|||
| 
								 | 
							
								              return ''
							 | 
						|||
| 
								 | 
							
								            })
							 | 
						|||
| 
								 | 
							
								            const pseudo = {
							 | 
						|||
| 
								 | 
							
								              name: 'span',
							 | 
						|||
| 
								 | 
							
								              attrs: {
							 | 
						|||
| 
								 | 
							
								                style: item.style
							 | 
						|||
| 
								 | 
							
								              },
							 | 
						|||
| 
								 | 
							
								              children: [{
							 | 
						|||
| 
								 | 
							
								                type: 'text',
							 | 
						|||
| 
								 | 
							
								                text
							 | 
						|||
| 
								 | 
							
								              }]
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								            if (item.pseudo === 'before') {
							 | 
						|||
| 
								 | 
							
								              node.children.unshift(pseudo)
							 | 
						|||
| 
								 | 
							
								            } else {
							 | 
						|||
| 
								 | 
							
								              node.children.push(pseudo)
							 | 
						|||
| 
								 | 
							
								            }
							 | 
						|||
| 
								 | 
							
								          } else {
							 | 
						|||
| 
								 | 
							
								            matched[res - 1] += item.style + (item.style[item.style.length - 1] === ';' ? '' : ';')
							 | 
						|||
| 
								 | 
							
								          }
							 | 
						|||
| 
								 | 
							
								        }
							 | 
						|||
| 
								 | 
							
								      }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    matched = matched.join('')
							 | 
						|||
| 
								 | 
							
								    if (matched.length > 2) {
							 | 
						|||
| 
								 | 
							
								      node.attrs.style = matched + (node.attrs.style || '')
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								  }
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								/**
							 | 
						|||
| 
								 | 
							
								 * @description 匹配样式
							 | 
						|||
| 
								 | 
							
								 * @param {object} node 要匹配的标签
							 | 
						|||
| 
								 | 
							
								 * @param {string|string[]} keys 选择器
							 | 
						|||
| 
								 | 
							
								 * @returns {number} 0:不匹配;1:name 匹配;2:class 匹配;3:id 匹配
							 | 
						|||
| 
								 | 
							
								 */
							 | 
						|||
| 
								 | 
							
								function match (node, keys) {
							 | 
						|||
| 
								 | 
							
								  function matchItem (key) {
							 | 
						|||
| 
								 | 
							
								    if (key[0] === '#') {
							 | 
						|||
| 
								 | 
							
								      // 匹配 id
							 | 
						|||
| 
								 | 
							
								      if (node.attrs.id && node.attrs.id.trim() === key.substr(1)) return 3
							 | 
						|||
| 
								 | 
							
								    } else if (key[0] === '.') {
							 | 
						|||
| 
								 | 
							
								      // 匹配 class
							 | 
						|||
| 
								 | 
							
								      key = key.substr(1)
							 | 
						|||
| 
								 | 
							
								      const selectors = (node.attrs.class || '').split(' ')
							 | 
						|||
| 
								 | 
							
								      for (let i = 0; i < selectors.length; i++) {
							 | 
						|||
| 
								 | 
							
								        if (selectors[i].trim() === key) return 2
							 | 
						|||
| 
								 | 
							
								      }
							 | 
						|||
| 
								 | 
							
								    } else if (node.name === key) {
							 | 
						|||
| 
								 | 
							
								      // 匹配 name
							 | 
						|||
| 
								 | 
							
								      return 1
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    return 0
							 | 
						|||
| 
								 | 
							
								  }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								  // 多选择器交集
							 | 
						|||
| 
								 | 
							
								  if (keys instanceof Array) {
							 | 
						|||
| 
								 | 
							
								    let res = 0
							 | 
						|||
| 
								 | 
							
								    for (let j = 0; j < keys.length; j++) {
							 | 
						|||
| 
								 | 
							
								      const tmp = matchItem(keys[j])
							 | 
						|||
| 
								 | 
							
								      // 任意一个不匹配就失败
							 | 
						|||
| 
								 | 
							
								      if (!tmp) return 0
							 | 
						|||
| 
								 | 
							
								      // 优先级最大的一个作为最终优先级
							 | 
						|||
| 
								 | 
							
								      if (tmp > res) {
							 | 
						|||
| 
								 | 
							
								        res = tmp
							 | 
						|||
| 
								 | 
							
								      }
							 | 
						|||
| 
								 | 
							
								    }
							 | 
						|||
| 
								 | 
							
								    return res
							 | 
						|||
| 
								 | 
							
								  }
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								  return matchItem(keys)
							 | 
						|||
| 
								 | 
							
								}
							 | 
						|||
| 
								 | 
							
								// #endif
							 | 
						|||
| 
								 | 
							
								
							 | 
						|||
| 
								 | 
							
								module.exports = Style
							 |