Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                #app
  .control
    // 第一個按鈕切換gather狀態,用v-model雙向綁定資料
    input(type="checkbox", v-model="gather")
    // 後面四個按鈕,對應卡片的開啟狀態,用v-model雙向綁定資料
    input(type="checkbox", v-for="card in cards", v-model="card.open")
    button(@click="shuffle") Shuffle
    button(@click="startGame") startGame
  h2 {{ state }}
  .cards(:class="{gather: gather}")
    .card(v-for="card in cards",
          :class="{open: card.open}",
          :data-order="card.id",
          @click="openCard(card)")
      .face.back 
      .face.front {{ getSymbol(card.label) }}
              
            
!

CSS

              
                @mixin size($w, $h: $w)
  width: $w
  height: $h

@mixin flexCenter
  display: flex
  justify-content: center
  align-items: center
  
// vw表示view width,螢幕可視範圍寬度的百分比
$cardWidth: 15vw

@mixin setLeftPos($l, $w: $cardWidth)
  // 減掉卡片寬度的一片,偏移回去
  // 要使用變數,需要加井字號轉成文字,#{$變數}
  left: calc(#{$l} - #{$w/2})

html, body
  background-color: #102438
  color: white
  +flexCenter

.cards
  // vw表示view height,螢幕可視範圍高度的百分比
  // 範例這行拿掉仍然可以動,因為有針對個別card設定位置
  // +size(100%, 80vh)
  .card
    +size($cardWidth, $cardWidth*1.4)
    position: absolute
    top: 35%
    cursor: pointer
    +setLeftPos(30%)
    transform: rotateY(0deg)
    // 保持三維空間,才會正確顯示卡片預先轉過去的另一面
    transform-style: preserve-3d
    transition: transform 1s, left 0.5s, top 0.5s
    box-shadow: 0px 10px 30px rgba(black, 0.2)
    .face
      // 轉到背面就看不到
      backface-visibility: hidden
      background-color: #fff
      color: black
      +size(100%)
      position: absolute
      left: 0
      top: 0
      border-radius: 5px
      &.front
        background-color: white
        transform: rotateY(180deg)
        +flexCenter
        font-size: 90px
      &.back
        // 往內撐開,卡片大小不變
        box-sizing: border-box
        padding: 10px
        
        $colorRed: #ed4747
        &:before
          // 不加這個框框會偏右下歪掉
          box-sizing: border-box
          content: ""
          display: block
          +size(100%)
          border: 3px solid $colorRed
          // 卡片背面花色,用兩個斜線拼成x,寬高8p排列滿整個畫面
          background-image: linear-gradient(-60deg, transparent 40%, $colorRed 40%, $colorRed 60%, transparent 60%), linear-gradient(60deg, transparent 40%, $colorRed 40%, $colorRed 60%, transparent 60%)
          background-size: 8px 8px
    &.open
      // 顯示正面
      transform: rotateY(180deg)
    
    @for $i from 1 through 4
      // 卡片的排列,依照次序從距離畫面左側20%開始
      &[data-order="#{$i}"]
        +setLeftPos(#{$i*20%})
    &:hover
      top: 30%
  &.gather
    cursor: pointer
    .card
      top: 20%
      +setLeftPos(50%)
      transform: rotate(360deg)
    &:hover
      // gather時,移過去卡片以每隔5度的方式扇行轉開
      @for $i from 1 through 4
        .card[data-order="#{$i}"]
          transform: rotate(#{$i*5 + 350}deg)
  
              
            
!

JS

              
                var vm = new Vue({
  el: "#app",
  data: {
    gather: true,
    state: "Press the cards to start a game!",
    // symbols和cards都有共同的資料label
    symbols: [
      {label: "spades",symbol: "♠" },
      {label: "hearts",symbol: "♥" },
      {label: "diamonds",symbol: "♦" },
      {label: "clubs",symbol: "♣" }
    ],
    cards: [
      // id和HTML的:data-order相關,CSS依此排列順序
      {
        id: 1,label: "spades",open: false
      },
      {
        id: 2,label: "hearts", open: false
      },
      {
        id: 3,label: "clubs", open: false
      },
      {
        id: 4,label: "diamonds", open: false
      }
    ],
    question: null,
    mode: "",
    count: 0
  },
  methods: {
    shuffle() {
      // 隨機洗亂順序
      let newOrder = [1,2,3,4].sort((a,b)=>Math.random()>0.5 ? 1 : -1)
      // 把新順序的數字指定給card的id
      // HTML的card.id和:data-order關聯,後者又跟CSS的+setLeftPos相關,達成洗牌效果
      this.cards.forEach((card, cid)=>card.id=newOrder[cid])
    },
    turnAll(state) {
      this.cards.forEach(card=>card.open=state)
    },
    startGame() {
      this.mode = ""
      this.question = this.symbols[parseInt(Math.random()*4)]  // 大於0小於4的整數
      this.turnAll(false)
      this.gather = true
      this.state = "Ready"
      
      // 隔1秒,離開gather狀態
      setTimeout(()=>{
        this.gather = false
        this.state = "Your mission is..."
      }, 1000)
      
      // 隔2秒,翻開所有卡片,提示要找的卡片花色
      setTimeout(()=>{
        this.turnAll(true)
        this.state="Find " + this.question.label + " " + this.question.symbol + " !"
      }, 2000)
      
      // 隔4秒,蓋上所有卡片
      setTimeout(()=>{
        this.turnAll(false)
        this.state="Get ready"
      }, 4000)
      
      this.count = 0
      
      // 隔6秒,開始洗牌,洗6次
      setTimeout(()=>{
        
        // 定義洗牌函式
        let startShuffle= ()=> {
          this.shuffle()
          console.log("Shuffle:第" + this.count + "次")
          
          // 洗牌6次
          if(this.count++ < 6) {
            setTimeout(startShuffle, 300)
          } else {
            // 洗完牌進入答題模式
            this.state = "Please Pick out " + this.question.label + this.question.symbol
            this.mode = "answer"
          }
        }
        
        startShuffle()
      }, 6000)
    },
    getSymbol(label) {
      let result = this.symbols.find(s=> s.label==label)
      return result ? result.symbol : label
    },
    getCard(label) {
      return this.cards.find(card=> card.label == label)
    },
    openCard(card) {
      // 進入答題模式,可以翻牌
      if (this.mode == "answer") {
        card.open = !card.open
        
        // 比對抽的卡片是否正確
        if (card.label == this.question.label) {
          this.state = "You win :)"
        } else {
          this.state = "You lose >.<"
          
          setTimeout(()=>{
            // 找到正確的卡片,翻開
            let card = this.getCard(this.question.label)
            card.open = true
          }, 1000)
          
          setTimeout(()=>{
            // 重新開始遊戲
            this.startGame()
          }, 3000)
        }
      } else {
        // 不在答題模式,點擊卡片開始遊戲
        this.startGame()
      }
    }
  },
  mounted() {
    // 一進來就開始遊戲
    // this.startGame()
  }
})
              
            
!
999px

Console