Having seen Real extend their lead to four points with a 4-1 win over Real Sociedad on Saturday, Barca fell behind to Denis Cheryshev's goal in the 30th minute.
Neymar equalised on the stroke of half-time, but Luciano Vietto restored the visitors' lead six minutes into the second period.
However, quickfire goals from Rafinha and Lionel Messi put Barca in the lead for the first time, and they held on to extend their winning run in all competitions to eight matches and end Villarreal's 18-game undefeated streak.
For the third time in 11 days, Sevilla met Espanyol and it proved to be an entertaining affair as Unai Emery's men triumphed 3-2 thanks to Iago Aspas' strike a minute from time.
Espanyol won 3-2 on aggregate in their recent Copa del Rey quarter-final, but this time it was Sevilla's turn to enjoy success as they moved back up to fourth in the table.
Christian Stuani put Espanyol ahead from the penalty spot in the 15th minute before a freak goal brought Sevilla level.
Diogo Figueiras went in for a 50-50 challenge with an opponent but as he lashed the ball away it sailed over the head of Kiko Casilla and into the net from 50 yards.
Vitolo put Sevilla ahead 10 minutes prior to the interval and five minutes later Casilla raced from his goal, inexplicably handled Aspas' lobbed effort and was shown a straight red card.
Victor Sanchez brought Espanyol level with 13 minutes to go, but in the 89th minute Aspas had the final say with a smart finish to send the home fans into raptures.
Elsewhere, Athletic Bilbao won 2-0 at Levante thanks to a brace from Aritz Aduriz, while Edgar Mendez's strike earned Almeria a 1-0 win over Getafe.
Both sides finished with 10 men, as Getafe saw Sergio Escudero dismissed for a second booking before Almeria had Tomer Hemed sent off, also for picking up two cautions.
Get the best features, fun and footballing frolics straight to your inbox every week.
Thank you for signing up to Four Four Two. You will receive a verification email shortly.
There was a problem. Please refresh the page and try again.