瀏覽代碼

Add x-show

Caleb Porzio 5 年之前
父節點
當前提交
526ddc1317
共有 9 個文件被更改,包括 123 次插入13 次删除
  1. 14 5
      README.md
  2. 2 2
      dist/mix-manifest.json
  3. 36 2
      dist/project-x.js
  4. 0 0
      dist/project-x.min.js
  5. 1 1
      index.html
  6. 1 1
      package.json
  7. 25 0
      src/component.js
  8. 2 2
      src/utils.js
  9. 42 0
      test/show.spec.js

+ 14 - 5
README.md

@@ -11,7 +11,7 @@ Think of it like [Tailwind](https://tailwindcss.com/) for JavaScript.
 ## Install
 Add the following script to the end of your `<head>` section.
 ```html
-<script src="https://cdn.jsdelivr.net/gh/calebporzio/project-x@v0.3.0/dist/project-x.min.js" defer></script>
+<script src="https://cdn.jsdelivr.net/gh/calebporzio/project-x@v0.4.0/dist/project-x.min.js" defer></script>
 ```
 
 ## Use
@@ -24,8 +24,7 @@ Add the following script to the end of your `<head>` section.
     <button x-on:click="open = true">Open Dropdown</button>
 
     <ul
-        class="hidden"
-        x-bind:class="{ 'hidden': ! open }"
+        x-show="open"
         x-on:click.away="open = false"
     >
         Dropdown Body
@@ -39,8 +38,8 @@ Add the following script to the end of your `<head>` section.
     <button x-bind:class="{ 'active': tab === 'foo' }" x-on:click="tab = 'foo'">Foo</button>
     <button x-bind:class="{ 'active': tab === 'bar' }" x-on:click="tab = 'bar'">Bar</button>
 
-    <div class="hidden" x-bind:class="{ 'hidden': tab !== 'foo' }">Tab Foo</div>
-    <div class="hidden" x-bind:class="{ 'hidden': tab !== 'bar' }">Tab Bar</div>
+    <div x-show="tab === 'foo'">Tab Foo</div>
+    <div x-show="tab === 'bar'">Tab Bar</div>
 </div>
 ```
 
@@ -51,6 +50,7 @@ There are 7 directives available to you:
 | Directive
 | --- |
 | [`x-data`](#x-data) |
+| [`x-show`](#x-show) |
 | [`x-bind`](#x-bind) |
 | [`x-on`](#x-on) |
 | [`x-model`](#x-model) |
@@ -105,6 +105,15 @@ You can also mix-in multiple data objects using object destructuring:
 
 ---
 
+### `x-show`
+**Example:** `<div x-show="open"></div>`
+
+**Structure:** `<div x-show="[expression]"></div>`
+
+`x-show` toggles the `display: none;` style on the element depending if the expression resolves to `true` or `false`.
+
+---
+
 ### `x-bind`
 **Example:** `<input x-bind:type="inputType">`
 

+ 2 - 2
dist/mix-manifest.json

@@ -1,4 +1,4 @@
 {
-    "/project-x.js": "/project-x.js?id=bd450a04a07206020f63",
-    "/project-x.min.js": "/project-x.min.js?id=aca2ba4b017885bdd4a5"
+    "/project-x.js": "/project-x.js?id=a11dbcb0d5ba1786312d",
+    "/project-x.min.js": "/project-x.min.js?id=d07f1a5dd55fedec39a4"
 }

+ 36 - 2
dist/project-x.js

@@ -950,6 +950,14 @@ function () {
 
               break;
 
+            case 'show':
+              var _this$evaluateReturnE4 = _this.evaluateReturnExpression(expression),
+                  output = _this$evaluateReturnE4.output;
+
+              _this.updateVisibility(el, output);
+
+              break;
+
             case 'cloak':
               el.removeAttribute('x-cloak');
               break;
@@ -1019,6 +1027,19 @@ function () {
 
               break;
 
+            case 'show':
+              var _self$evaluateReturnE4 = self.evaluateReturnExpression(expression),
+                  output = _self$evaluateReturnE4.output,
+                  deps = _self$evaluateReturnE4.deps;
+
+              if (self.concernedData.filter(function (i) {
+                return deps.includes(i);
+              }).length > 0) {
+                self.updateVisibility(el, output);
+              }
+
+              break;
+
             default:
               break;
           }
@@ -1111,6 +1132,19 @@ function () {
     value: function updateTextValue(el, value) {
       el.innerText = value;
     }
+  }, {
+    key: "updateVisibility",
+    value: function updateVisibility(el, value) {
+      if (!value) {
+        el.style.display = 'none';
+      } else {
+        if (el.style.length === 1 && el.style.display !== '') {
+          el.removeAttribute('style');
+        } else {
+          el.style.removeProperty('display');
+        }
+      }
+    }
   }, {
     key: "updateAttributeValue",
     value: function updateAttributeValue(el, attrName, value) {
@@ -1388,12 +1422,12 @@ function saferEvalNoReturn(expression, dataContext) {
   return new Function(['$data'].concat(_toConsumableArray(Object.keys(additionalHelperVariables))), "with($data) { ".concat(expression, " }")).apply(void 0, [dataContext].concat(_toConsumableArray(Object.values(additionalHelperVariables))));
 }
 function isXAttr(attr) {
-  var xAttrRE = /x-(on|bind|data|text|model|cloak|ref)/;
+  var xAttrRE = /x-(on|bind|data|text|model|show|cloak|ref)/;
   return xAttrRE.test(attr.name);
 }
 function getXAttrs(el, type) {
   return Array.from(el.attributes).filter(isXAttr).map(function (attr) {
-    var typeMatch = attr.name.match(/x-(on|bind|data|text|model|cloak|ref)/);
+    var typeMatch = attr.name.match(/x-(on|bind|data|text|model|show|cloak|ref)/);
     var valueMatch = attr.name.match(/:([a-zA-Z\-]+)/);
     var modifiers = attr.name.match(/\.[^.\]]+(?=[^\]]*$)/g) || [];
     return {

文件差異過大導致無法顯示
+ 0 - 0
dist/project-x.min.js


+ 1 - 1
index.html

@@ -5,7 +5,7 @@
             [x-cloak] { display: none; }
         </style>
 
-        <script src="https://cdn.jsdelivr.net/gh/calebporzio/project-x@v0.3.0/dist/project-x.min.js" defer></script>
+        <script src="https://cdn.jsdelivr.net/gh/calebporzio/project-x@v0.4.0/dist/project-x.min.js" defer></script>
     </head>
     <body>
         <div x-data="{ foo: 'bar' }">

+ 1 - 1
package.json

@@ -1,7 +1,7 @@
 {
   "main": "dist/project-x.js",
   "name": "project-x",
-  "version": "0.3.0",
+  "version": "0.4.0",
   "repository": {
     "type": "git",
     "url": "git://github.com/calebporzio/project-x.git"

+ 25 - 0
src/component.js

@@ -67,6 +67,11 @@ export default class Component {
                         this.updateTextValue(el, output)
                         break;
 
+                    case 'show':
+                        var { output } = this.evaluateReturnExpression(expression)
+                        this.updateVisibility(el, output)
+                        break;
+
                     case 'cloak':
                         el.removeAttribute('x-cloak')
                         break;
@@ -114,6 +119,14 @@ export default class Component {
                         }
                         break;
 
+                    case 'show':
+                        var { output, deps } = self.evaluateReturnExpression(expression)
+
+                        if (self.concernedData.filter(i => deps.includes(i)).length > 0) {
+                            self.updateVisibility(el, output)
+                        }
+                        break;
+
                     default:
                         break;
                 }
@@ -208,6 +221,18 @@ export default class Component {
         el.innerText = value
     }
 
+    updateVisibility(el, value) {
+        if (! value) {
+            el.style.display = 'none'
+        } else {
+            if (el.style.length === 1 && el.style.display !== '') {
+                el.removeAttribute('style')
+            } else {
+                el.style.removeProperty('display')
+            }
+        }
+    }
+
     updateAttributeValue(el, attrName, value) {
         if (attrName === 'value') {
             if (el.type === 'radio') {

+ 2 - 2
src/utils.js

@@ -61,7 +61,7 @@ export function saferEvalNoReturn(expression, dataContext, additionalHelperVaria
 }
 
 export function isXAttr(attr) {
-    const xAttrRE = /x-(on|bind|data|text|model|cloak|ref)/
+    const xAttrRE = /x-(on|bind|data|text|model|show|cloak|ref)/
 
     return xAttrRE.test(attr.name)
 }
@@ -70,7 +70,7 @@ export function getXAttrs(el, type) {
     return Array.from(el.attributes)
         .filter(isXAttr)
         .map(attr => {
-            const typeMatch = attr.name.match(/x-(on|bind|data|text|model|cloak|ref)/)
+            const typeMatch = attr.name.match(/x-(on|bind|data|text|model|show|cloak|ref)/)
             const valueMatch = attr.name.match(/:([a-zA-Z\-]+)/)
             const modifiers = attr.name.match(/\.[^.\]]+(?=[^\]]*$)/g) || []
 

+ 42 - 0
test/show.spec.js

@@ -0,0 +1,42 @@
+import projectX from 'project-x'
+import { wait } from 'dom-testing-library'
+
+global.MutationObserver = class {
+    observe() {}
+}
+
+test('x-show toggles display: none; with no other style attributes', async () => {
+    document.body.innerHTML = `
+        <div x-data="{ show: true }">
+            <span x-show="show"></span>
+
+            <button x-on:click="show = false"></button>
+        </div>
+    `
+
+    projectX.start()
+
+    expect(document.querySelector('span').getAttribute('style')).toEqual(null)
+
+    document.querySelector('button').click()
+
+    await wait(() => { expect(document.querySelector('span').getAttribute('style')).toEqual('display: none;') })
+})
+
+test('x-show toggles display: none; with no other style attributes', async () => {
+    document.body.innerHTML = `
+        <div x-data="{ show: true }">
+            <span x-show="show" style="color: blue;"></span>
+
+            <button x-on:click="show = false"></button>
+        </div>
+    `
+
+    projectX.start()
+
+    expect(document.querySelector('span').getAttribute('style')).toEqual('color: blue;')
+
+    document.querySelector('button').click()
+
+    await wait(() => { expect(document.querySelector('span').getAttribute('style')).toEqual('color: blue; display: none;') })
+})

部分文件因文件數量過多而無法顯示