index.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /**
  2. * @fileoverview style 插件
  3. */
  4. // #ifndef APP-PLUS-NVUE
  5. const Parser = require('./parser')
  6. // #endif
  7. function Style () {
  8. this.styles = []
  9. }
  10. // #ifndef APP-PLUS-NVUE
  11. Style.prototype.onParse = function (node, vm) {
  12. // 获取样式
  13. if (node.name === 'style' && node.children.length && node.children[0].type === 'text') {
  14. this.styles = this.styles.concat(new Parser().parse(node.children[0].text))
  15. } else if (node.name) {
  16. // 匹配样式(对非文本标签)
  17. // 存储不同优先级的样式 name < class < id < 后代
  18. let matched = ['', '', '', '']
  19. for (let i = 0, len = this.styles.length; i < len; i++) {
  20. const item = this.styles[i]
  21. let res = match(node, item.key || item.list[item.list.length - 1])
  22. let j
  23. if (res) {
  24. // 后代选择器
  25. if (!item.key) {
  26. j = item.list.length - 2
  27. for (let k = vm.stack.length; j >= 0 && k--;) {
  28. // 子选择器
  29. if (item.list[j] === '>') {
  30. // 错误情况
  31. if (j < 1 || j > item.list.length - 2) break
  32. if (match(vm.stack[k], item.list[j - 1])) {
  33. j -= 2
  34. } else {
  35. j++
  36. }
  37. } else if (match(vm.stack[k], item.list[j])) {
  38. j--
  39. }
  40. }
  41. res = 4
  42. }
  43. if (item.key || j < 0) {
  44. // 添加伪类
  45. if (item.pseudo && node.children) {
  46. let text
  47. item.style = item.style.replace(/content:([^;]+)/, (_, $1) => {
  48. text = $1.replace(/['"]/g, '')
  49. // 处理 attr 函数
  50. .replace(/attr\((.+?)\)/, (_, $1) => node.attrs[$1.trim()] || '')
  51. // 编码 \xxx
  52. .replace(/\\(\w{4})/, (_, $1) => String.fromCharCode(parseInt($1, 16)))
  53. return ''
  54. })
  55. const pseudo = {
  56. name: 'span',
  57. attrs: {
  58. style: item.style
  59. },
  60. children: [{
  61. type: 'text',
  62. text
  63. }]
  64. }
  65. if (item.pseudo === 'before') {
  66. node.children.unshift(pseudo)
  67. } else {
  68. node.children.push(pseudo)
  69. }
  70. } else {
  71. matched[res - 1] += item.style + (item.style[item.style.length - 1] === ';' ? '' : ';')
  72. }
  73. }
  74. }
  75. }
  76. matched = matched.join('')
  77. if (matched.length > 2) {
  78. node.attrs.style = matched + (node.attrs.style || '')
  79. }
  80. }
  81. }
  82. /**
  83. * @description 匹配样式
  84. * @param {object} node 要匹配的标签
  85. * @param {string|string[]} keys 选择器
  86. * @returns {number} 0:不匹配;1:name 匹配;2:class 匹配;3:id 匹配
  87. */
  88. function match (node, keys) {
  89. function matchItem (key) {
  90. if (key[0] === '#') {
  91. // 匹配 id
  92. if (node.attrs.id && node.attrs.id.trim() === key.substr(1)) return 3
  93. } else if (key[0] === '.') {
  94. // 匹配 class
  95. key = key.substr(1)
  96. const selectors = (node.attrs.class || '').split(' ')
  97. for (let i = 0; i < selectors.length; i++) {
  98. if (selectors[i].trim() === key) return 2
  99. }
  100. } else if (node.name === key) {
  101. // 匹配 name
  102. return 1
  103. }
  104. return 0
  105. }
  106. // 多选择器交集
  107. if (keys instanceof Array) {
  108. let res = 0
  109. for (let j = 0; j < keys.length; j++) {
  110. const tmp = matchItem(keys[j])
  111. // 任意一个不匹配就失败
  112. if (!tmp) return 0
  113. // 优先级最大的一个作为最终优先级
  114. if (tmp > res) {
  115. res = tmp
  116. }
  117. }
  118. return res
  119. }
  120. return matchItem(keys)
  121. }
  122. // #endif
  123. module.exports = Style