index.js 3.6 KB

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